[KBM] Distinguish numpad keys (#28097)

This commit is contained in:
Andrey Nekrasov
2023-08-23 18:56:40 +02:00
committed by GitHub
parent c2bb2a8c3a
commit efee03eb99
9 changed files with 145 additions and 136 deletions

View File

@@ -5,6 +5,8 @@
#include "keyboard_layout_impl.h" #include "keyboard_layout_impl.h"
#include "shared_constants.h" #include "shared_constants.h"
constexpr DWORD numpadOriginBit = 1ull << 31;
LayoutMap::LayoutMap() : LayoutMap::LayoutMap() :
impl(new LayoutMap::LayoutMapImpl()) impl(new LayoutMap::LayoutMapImpl())
{ {
@@ -110,7 +112,6 @@ void LayoutMap::LayoutMapImpl::UpdateLayout()
keyboardLayoutMap[VK_BACK] = L"Backspace"; keyboardLayoutMap[VK_BACK] = L"Backspace";
keyboardLayoutMap[VK_TAB] = L"Tab"; keyboardLayoutMap[VK_TAB] = L"Tab";
keyboardLayoutMap[VK_CLEAR] = L"Clear"; keyboardLayoutMap[VK_CLEAR] = L"Clear";
keyboardLayoutMap[VK_RETURN] = L"Enter";
keyboardLayoutMap[VK_SHIFT] = L"Shift"; keyboardLayoutMap[VK_SHIFT] = L"Shift";
keyboardLayoutMap[VK_CONTROL] = L"Ctrl"; keyboardLayoutMap[VK_CONTROL] = L"Ctrl";
keyboardLayoutMap[VK_MENU] = L"Alt"; keyboardLayoutMap[VK_MENU] = L"Alt";
@@ -118,20 +119,36 @@ void LayoutMap::LayoutMapImpl::UpdateLayout()
keyboardLayoutMap[VK_CAPITAL] = L"Caps Lock"; keyboardLayoutMap[VK_CAPITAL] = L"Caps Lock";
keyboardLayoutMap[VK_ESCAPE] = L"Esc"; keyboardLayoutMap[VK_ESCAPE] = L"Esc";
keyboardLayoutMap[VK_SPACE] = L"Space"; keyboardLayoutMap[VK_SPACE] = L"Space";
keyboardLayoutMap[VK_LEFT] = L"Left";
keyboardLayoutMap[VK_RIGHT] = L"Right";
keyboardLayoutMap[VK_UP] = L"Up";
keyboardLayoutMap[VK_DOWN] = L"Down";
keyboardLayoutMap[VK_INSERT] = L"Insert";
keyboardLayoutMap[VK_DELETE] = L"Delete";
keyboardLayoutMap[VK_PRIOR] = L"PgUp"; keyboardLayoutMap[VK_PRIOR] = L"PgUp";
keyboardLayoutMap[VK_NEXT] = L"PgDn"; keyboardLayoutMap[VK_NEXT] = L"PgDn";
keyboardLayoutMap[VK_END] = L"End";
keyboardLayoutMap[VK_HOME] = L"Home"; keyboardLayoutMap[VK_HOME] = L"Home";
keyboardLayoutMap[VK_LEFT] = L"Left"; keyboardLayoutMap[VK_END] = L"End";
keyboardLayoutMap[VK_UP] = L"Up"; keyboardLayoutMap[VK_RETURN] = L"Enter";
keyboardLayoutMap[VK_RIGHT] = L"Right";
keyboardLayoutMap[VK_DOWN] = L"Down"; keyboardLayoutMap[VK_LEFT | numpadOriginBit] = L"Left (Numpad)";
keyboardLayoutMap[VK_RIGHT | numpadOriginBit] = L"Right (Numpad)";
keyboardLayoutMap[VK_UP | numpadOriginBit] = L"Up (Numpad)";
keyboardLayoutMap[VK_DOWN | numpadOriginBit] = L"Down (Numpad)";
keyboardLayoutMap[VK_INSERT | numpadOriginBit] = L"Insert (Numpad)";
keyboardLayoutMap[VK_DELETE | numpadOriginBit] = L"Delete (Numpad)";
keyboardLayoutMap[VK_PRIOR | numpadOriginBit] = L"PgUp (Numpad)";
keyboardLayoutMap[VK_NEXT | numpadOriginBit] = L"PgDn (Numpad)";
keyboardLayoutMap[VK_HOME | numpadOriginBit] = L"Home (Numpad)";
keyboardLayoutMap[VK_END | numpadOriginBit] = L"End (Numpad)";
keyboardLayoutMap[VK_RETURN | numpadOriginBit] = L"Enter (Numpad)";
keyboardLayoutMap[VK_DIVIDE | numpadOriginBit] = L"/ (Numpad)";
keyboardLayoutMap[VK_SELECT] = L"Select"; keyboardLayoutMap[VK_SELECT] = L"Select";
keyboardLayoutMap[VK_PRINT] = L"Print"; keyboardLayoutMap[VK_PRINT] = L"Print";
keyboardLayoutMap[VK_EXECUTE] = L"Execute"; keyboardLayoutMap[VK_EXECUTE] = L"Execute";
keyboardLayoutMap[VK_SNAPSHOT] = L"Print Screen"; keyboardLayoutMap[VK_SNAPSHOT] = L"Print Screen";
keyboardLayoutMap[VK_INSERT] = L"Insert";
keyboardLayoutMap[VK_DELETE] = L"Delete";
keyboardLayoutMap[VK_HELP] = L"Help"; keyboardLayoutMap[VK_HELP] = L"Help";
keyboardLayoutMap[VK_LWIN] = L"Win (Left)"; keyboardLayoutMap[VK_LWIN] = L"Win (Left)";
keyboardLayoutMap[VK_RWIN] = L"Win (Right)"; keyboardLayoutMap[VK_RWIN] = L"Win (Right)";
@@ -275,6 +292,12 @@ std::vector<DWORD> LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcu
} }
} }
// Add numpad keys
for (auto it = keyboardLayoutMap.rbegin(); it->first & numpadOriginBit; ++it)
{
keyCodes.push_back(it->first);
}
// Sort the special keys in alphabetical order // Sort the special keys in alphabetical order
std::sort(specialKeys.begin(), specialKeys.end(), [&](const DWORD& lhs, const DWORD& rhs) { std::sort(specialKeys.begin(), specialKeys.end(), [&](const DWORD& lhs, const DWORD& rhs) {
return keyboardLayoutMap[lhs] < keyboardLayoutMap[rhs]; return keyboardLayoutMap[lhs] < keyboardLayoutMap[rhs];

View File

@@ -207,6 +207,8 @@ LRESULT KeyboardManagerEditor::KeyHookProc(int nCode, WPARAM wParam, LPARAM lPar
{ {
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
event.wParam = wParam; event.wParam = wParam;
event.lParam->vkCode = Helpers::EncodeKeyNumpadOrigin(event.lParam->vkCode, event.lParam->flags & LLKHF_EXTENDED);
if (editor->HandleKeyboardHookEvent(&event) == 1) if (editor->HandleKeyboardHookEvent(&event) == 1)
{ {
// Reset Num Lock whenever a NumLock key down event is suppressed since Num Lock key state change occurs before it is intercepted by low level hooks // Reset Num Lock whenever a NumLock key down event is suppressed since Num Lock key state change occurs before it is intercepted by low level hooks

View File

@@ -27,7 +27,7 @@ DWORD KeyDropDownControl::GetSelectedValue(ComboBox comboBox)
} }
auto value = winrt::unbox_value<hstring>(dataContext); auto value = winrt::unbox_value<hstring>(dataContext);
return stoi(std::wstring(value)); return stoul(std::wstring(value));
} }
void KeyDropDownControl::SetSelectedValue(std::wstring value) void KeyDropDownControl::SetSelectedValue(std::wstring value)

View File

@@ -42,8 +42,7 @@ namespace KeyboardEventHandlers
key_count = std::get<Shortcut>(it->second).Size(); key_count = std::get<Shortcut>(it->second).Size();
} }
LPINPUT keyEventList = new INPUT[size_t(key_count)](); LPINPUT keyEventList = new INPUT[size_t(key_count)]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Handle remaps to VK_WIN_BOTH // Handle remaps to VK_WIN_BOTH
DWORD target; DWORD target;
@@ -148,7 +147,6 @@ namespace KeyboardEventHandlers
} }
int key_count = 2; int key_count = 2;
LPINPUT keyEventList = new INPUT[size_t(key_count)](); LPINPUT keyEventList = new INPUT[size_t(key_count)]();
memset(keyEventList, 0, sizeof(keyEventList));
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG); Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
Helpers::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG); Helpers::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, (WORD)data->lParam->vkCode, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SINGLEKEY_FLAG);
@@ -232,8 +230,7 @@ namespace KeyboardEventHandlers
{ {
// key down for all new shortcut keys except the common modifiers // key down for all new shortcut keys except the common modifiers
key_count = dest_size - commonKeys; key_count = dest_size - commonKeys;
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
int i = 0; int i = 0;
Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first); Helpers::SetModifierKeyEvents(std::get<Shortcut>(it->second.targetShortcut), it->second.winKeyInvoked, keyEventList, i, true, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, it->first);
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
@@ -243,8 +240,7 @@ namespace KeyboardEventHandlers
{ {
// Dummy key, key up for all the original shortcut modifier keys and key down for all the new shortcut keys but common keys in each are not repeated // Dummy key, key up for all the original shortcut modifier keys and key down for all the new shortcut keys but common keys in each are not repeated
key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + (src_size - 1) + (dest_size) - (2 * static_cast<size_t>(commonKeys)); key_count = KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE + (src_size - 1) + (dest_size) - (2 * static_cast<size_t>(commonKeys));
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->Ctrl+V, press Win+A, since Win will be released here we need to send a dummy event before it // Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->Ctrl+V, press Win+A, since Win will be released here we need to send a dummy event before it
int i = 0; int i = 0;
@@ -282,8 +278,7 @@ namespace KeyboardEventHandlers
it->second.isOriginalActionKeyPressed = true; it->second.isOriginalActionKeyPressed = true;
} }
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->V, press Win+A, since Win will be released here we need to send a dummy event before it // Send a dummy key event to prevent modifier press+release from being triggered. Example: Win+A->V, press Win+A, since Win will be released here we need to send a dummy event before it
int i = 0; int i = 0;
@@ -302,7 +297,7 @@ namespace KeyboardEventHandlers
// Modifier state reset might be required for this key depending on the shortcut's action and target modifier - ex: Win+Caps -> Ctrl // Modifier state reset might be required for this key depending on the shortcut's action and target modifier - ex: Win+Caps -> Ctrl
if (it->first.GetCtrlKey() == NULL && it->first.GetAltKey() == NULL && it->first.GetShiftKey() == NULL) if (it->first.GetCtrlKey() == NULL && it->first.GetAltKey() == NULL && it->first.GetShiftKey() == NULL)
{ {
ResetIfModifierKeyForLowerLevelKeyHandlers(ii,static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), data->lParam->vkCode); ResetIfModifierKeyForLowerLevelKeyHandlers(ii, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), data->lParam->vkCode);
} }
} }
@@ -361,8 +356,7 @@ namespace KeyboardEventHandlers
key_count += 1; key_count += 1;
} }
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Release new shortcut state (release in reverse order of shortcut to be accurate) // Release new shortcut state (release in reverse order of shortcut to be accurate)
int i = 0; int i = 0;
@@ -400,8 +394,7 @@ namespace KeyboardEventHandlers
key_count--; key_count--;
} }
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Release new key state // Release new key state
int i = 0; int i = 0;
@@ -453,8 +446,7 @@ namespace KeyboardEventHandlers
} }
size_t key_count = 1; size_t key_count = 1;
LPINPUT keyEventList = new INPUT[key_count](); LPINPUT keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
if (remapToShortcut) if (remapToShortcut)
{ {
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
@@ -476,13 +468,12 @@ namespace KeyboardEventHandlers
LPINPUT keyEventList; LPINPUT keyEventList;
if (remapToShortcut) if (remapToShortcut)
{ {
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(std::get<Shortcut>(it->second.targetShortcut).GetActionKey()), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
} }
else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED) else if (std::get<DWORD>(it->second.targetShortcut) == CommonSharedConstants::VK_DISABLED)
{ {
// If remapped to disable, do nothing and suppress the key event // If remapped to disable, do nothing and suppress the key event
// Since the original shortcut's action key is released, set it to false // Since the original shortcut's action key is released, set it to false
it->second.isOriginalActionKeyPressed = false; it->second.isOriginalActionKeyPressed = false;
return 1; return 1;
@@ -491,13 +482,12 @@ namespace KeyboardEventHandlers
{ {
// Check if the keyboard state is clear apart from the target remap key (by creating a temp Shortcut object with the target key) // Check if the keyboard state is clear apart from the target remap key (by creating a temp Shortcut object with the target key)
bool isKeyboardStateClear = Shortcut(std::vector<int32_t>({ Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)) })).IsKeyboardStateClearExceptShortcut(ii); bool isKeyboardStateClear = Shortcut(std::vector<int32_t>({ Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut)) })).IsKeyboardStateClearExceptShortcut(ii);
// If the keyboard state is clear, we release the target key but do not reset the remap state // If the keyboard state is clear, we release the target key but do not reset the remap state
if (isKeyboardStateClear) if (isKeyboardStateClear)
{ {
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList)); Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD,static_cast<WORD>(Helpers::FilterArtificialKeys(std::get<DWORD>(it->second.targetShortcut))), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
} }
else else
{ {
@@ -507,8 +497,7 @@ namespace KeyboardEventHandlers
// 1 for releasing new key and original shortcut modifiers, and dummy key // 1 for releasing new key and original shortcut modifiers, and dummy key
key_count = dest_size + (src_size - 1) + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE; key_count = dest_size + (src_size - 1) + KeyboardManagerConstants::DUMMY_KEY_EVENT_SIZE;
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Release new key state // Release new key state
int i = 0; int i = 0;
@@ -574,7 +563,7 @@ namespace KeyboardEventHandlers
size_t key_count; size_t key_count;
LPINPUT keyEventList = nullptr; LPINPUT keyEventList = nullptr;
// Check if a new remapping should be applied // Check if a new remapping should be applied
Shortcut currentlyPressed = it->first; Shortcut currentlyPressed = it->first;
currentlyPressed.actionKey = data->lParam->vkCode; currentlyPressed.actionKey = data->lParam->vkCode;
@@ -588,8 +577,7 @@ namespace KeyboardEventHandlers
DWORD to = std::get<0>(newRemapping.targetShortcut); DWORD to = std::get<0>(newRemapping.targetShortcut);
bool isLastKeyStillPressed = ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)); bool isLastKeyStillPressed = ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey));
key_count = static_cast<size_t>(from.Size()) - 1 + 1 + (isLastKeyStillPressed ? 1 : 0); key_count = static_cast<size_t>(from.Size()) - 1 + 1 + (isLastKeyStillPressed ? 1 : 0);
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
int i = 0; int i = 0;
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey))) if (ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)))
@@ -599,7 +587,8 @@ namespace KeyboardEventHandlers
i++; i++;
} }
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(to), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(to), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
}else }
else
{ {
Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut); Shortcut to = std::get<Shortcut>(newRemapping.targetShortcut);
bool isLastKeyStillPressed = ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey)); bool isLastKeyStillPressed = ii.GetVirtualKeyState(static_cast<WORD>(from.actionKey));
@@ -608,7 +597,7 @@ namespace KeyboardEventHandlers
temp_key_count_calculation += static_cast<size_t>(to.Size()) - 1; temp_key_count_calculation += static_cast<size_t>(to.Size()) - 1;
temp_key_count_calculation -= static_cast<size_t>(2) * from.GetCommonModifiersCount(to); temp_key_count_calculation -= static_cast<size_t>(2) * from.GetCommonModifiersCount(to);
key_count = temp_key_count_calculation + 1 + (isLastKeyStillPressed ? 1 : 0); key_count = temp_key_count_calculation + 1 + (isLastKeyStillPressed ? 1 : 0);
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
int i = 0; int i = 0;
Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to); Helpers::SetModifierKeyEvents(from, it->second.winKeyInvoked, keyEventList, i, false, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG, to);
@@ -635,7 +624,7 @@ namespace KeyboardEventHandlers
} }
else else
{ {
// Key up for all new shortcut keys, key down for original shortcut modifiers and current key press but common keys aren't repeated // Key up for all new shortcut keys, key down for original shortcut modifiers and current key press but common keys aren't repeated
key_count = (dest_size) + (src_size - 1) - (2 * static_cast<size_t>(commonKeys)); key_count = (dest_size) + (src_size - 1) - (2 * static_cast<size_t>(commonKeys));
// If the target shortcut's action key is pressed, then it should be released and original shortcut's action key should be set // If the target shortcut's action key is pressed, then it should be released and original shortcut's action key should be set
@@ -646,8 +635,7 @@ namespace KeyboardEventHandlers
key_count += 2; key_count += 2;
} }
keyEventList = new INPUT[key_count](); keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Release new shortcut state (release in reverse order of shortcut to be accurate) // Release new shortcut state (release in reverse order of shortcut to be accurate)
int i = 0; int i = 0;
@@ -719,8 +707,7 @@ namespace KeyboardEventHandlers
// Key down for original shortcut modifiers and action key, and current key press // Key down for original shortcut modifiers and action key, and current key press
size_t key_count = src_size + 1; size_t key_count = src_size + 1;
LPINPUT keyEventList = new INPUT[key_count](); LPINPUT keyEventList = new INPUT[key_count]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Set original shortcut key down state // Set original shortcut key down state
int i = 0; int i = 0;
@@ -730,7 +717,7 @@ namespace KeyboardEventHandlers
if (isRemapToDisable && isOriginalActionKeyPressed) if (isRemapToDisable && isOriginalActionKeyPressed)
{ {
// Set original action key // Set original action key
Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD,static_cast<WORD>(it->first.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG); Helpers::SetKeyEvent(keyEventList, i, INPUT_KEYBOARD, static_cast<WORD>(it->first.GetActionKey()), 0, KeyboardManagerConstants::KEYBOARDMANAGER_SHORTCUT_FLAG);
i++; i++;
} }
else else
@@ -812,7 +799,7 @@ namespace KeyboardEventHandlers
std::wstring query_string; std::wstring query_string;
AppSpecificShortcutRemapTable::iterator it; AppSpecificShortcutRemapTable::iterator it;
// Check if an app-specific shortcut is already activated // Check if an app-specific shortcut is already activated
if (state.GetActivatedApp() == KeyboardManagerConstants::NoActivatedApp) if (state.GetActivatedApp() == KeyboardManagerConstants::NoActivatedApp)
{ {
@@ -854,8 +841,7 @@ namespace KeyboardEventHandlers
if (Helpers::IsModifierKey(key) && !(key == VK_LWIN || key == VK_RWIN || key == CommonSharedConstants::VK_WIN_BOTH)) if (Helpers::IsModifierKey(key) && !(key == VK_LWIN || key == VK_RWIN || key == CommonSharedConstants::VK_WIN_BOTH))
{ {
int key_count = 1; int key_count = 1;
LPINPUT keyEventList = new INPUT[size_t(key_count)](); LPINPUT keyEventList = new INPUT[size_t(key_count)]{};
memset(keyEventList, 0, sizeof(keyEventList));
// Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts // Use the suppress flag to ensure these are not intercepted by any remapped keys or shortcuts
Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(key), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG); Helpers::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, static_cast<WORD>(key), KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG);

View File

@@ -66,13 +66,14 @@ void KeyboardManager::LoadSettings()
} }
} }
LRESULT CALLBACK KeyboardManager::HookProc(int nCode, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK KeyboardManager::HookProc(int nCode, const WPARAM wParam, const LPARAM lParam)
{ {
LowlevelKeyboardEvent event; LowlevelKeyboardEvent event;
if (nCode == HC_ACTION) if (nCode == HC_ACTION)
{ {
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
event.wParam = wParam; event.wParam = wParam;
event.lParam->vkCode = Helpers::EncodeKeyNumpadOrigin(event.lParam->vkCode, event.lParam->flags & LLKHF_EXTENDED);
if (keyboardManagerObjectPtr->HandleKeyboardHookEvent(&event) == 1) if (keyboardManagerObjectPtr->HandleKeyboardHookEvent(&event) == 1)
{ {
// Reset Num Lock whenever a NumLock key down event is suppressed since Num Lock key state change occurs before it is intercepted by low level hooks // Reset Num Lock whenever a NumLock key down event is suppressed since Num Lock key state change occurs before it is intercepted by low level hooks
@@ -83,7 +84,7 @@ LRESULT CALLBACK KeyboardManager::HookProc(int nCode, WPARAM wParam, LPARAM lPar
return 1; return 1;
} }
} }
return CallNextHookEx(hookHandleCopy, nCode, wParam, lParam); return CallNextHookEx(hookHandleCopy, nCode, wParam, lParam);
} }

View File

@@ -9,6 +9,50 @@
namespace Helpers namespace Helpers
{ {
DWORD EncodeKeyNumpadOrigin(const DWORD key, const bool extended)
{
bool numpad_originated = false;
switch (key)
{
case VK_LEFT:
case VK_RIGHT:
case VK_UP:
case VK_DOWN:
case VK_INSERT:
case VK_DELETE:
case VK_PRIOR:
case VK_NEXT:
case VK_HOME:
case VK_END:
numpad_originated = !extended;
break;
case VK_RETURN:
case VK_DIVIDE:
numpad_originated = extended;
break;
}
if (numpad_originated)
return key | GetNumpadOriginEncodingBit();
else
return key;
}
DWORD ClearKeyNumpadOrigin(const DWORD key)
{
return (key & ~GetNumpadOriginEncodingBit());
}
bool IsNumpadOriginated(const DWORD key)
{
return !!(key & GetNumpadOriginEncodingBit());
}
DWORD GetNumpadOriginEncodingBit()
{
// Intentionally do not mimic KF_EXTENDED to avoid confusion, because it's not the same thing
// See EncodeKeyNumpadOrigin.
return 1ull << 31;
}
// Function to check if the key is a modifier key // Function to check if the key is a modifier key
bool IsModifierKey(DWORD key) bool IsModifierKey(DWORD key)
{ {
@@ -18,7 +62,8 @@ namespace Helpers
// Function to get the combined key for modifier keys // Function to get the combined key for modifier keys
DWORD GetCombinedKey(DWORD key) DWORD GetCombinedKey(DWORD key)
{ {
switch (key) { switch (key)
{
case VK_LWIN: case VK_LWIN:
case VK_RWIN: case VK_RWIN:
return CommonSharedConstants::VK_WIN_BOTH; return CommonSharedConstants::VK_WIN_BOTH;

View File

@@ -14,6 +14,12 @@ namespace Helpers
Shift, Shift,
Action Action
}; };
// Functions to encode that a key is originated from numpad
DWORD EncodeKeyNumpadOrigin(const DWORD key, const bool extended);
DWORD ClearKeyNumpadOrigin(const DWORD key);
bool IsNumpadOriginated(const DWORD key);
DWORD GetNumpadOriginEncodingBit();
// Function to check if the key is a modifier key // Function to check if the key is a modifier key
bool IsModifierKey(DWORD key); bool IsModifierKey(DWORD key);

View File

@@ -194,7 +194,7 @@ DWORD Shortcut::GetShiftKey() const
} }
// Function to check if the input key matches the win key expected in the shortcut // Function to check if the input key matches the win key expected in the shortcut
bool Shortcut::CheckWinKey(const DWORD& input) const bool Shortcut::CheckWinKey(const DWORD input) const
{ {
if (winKey == ModifierKey::Disabled) if (winKey == ModifierKey::Disabled)
{ {
@@ -216,7 +216,7 @@ bool Shortcut::CheckWinKey(const DWORD& input) const
} }
// Function to check if the input key matches the ctrl key expected in the shortcut // Function to check if the input key matches the ctrl key expected in the shortcut
bool Shortcut::CheckCtrlKey(const DWORD& input) const bool Shortcut::CheckCtrlKey(const DWORD input) const
{ {
if (ctrlKey == ModifierKey::Disabled) if (ctrlKey == ModifierKey::Disabled)
{ {
@@ -238,7 +238,7 @@ bool Shortcut::CheckCtrlKey(const DWORD& input) const
} }
// Function to check if the input key matches the alt key expected in the shortcut // Function to check if the input key matches the alt key expected in the shortcut
bool Shortcut::CheckAltKey(const DWORD& input) const bool Shortcut::CheckAltKey(const DWORD input) const
{ {
if (altKey == ModifierKey::Disabled) if (altKey == ModifierKey::Disabled)
{ {
@@ -260,7 +260,7 @@ bool Shortcut::CheckAltKey(const DWORD& input) const
} }
// Function to check if the input key matches the shift key expected in the shortcut // Function to check if the input key matches the shift key expected in the shortcut
bool Shortcut::CheckShiftKey(const DWORD& input) const bool Shortcut::CheckShiftKey(const DWORD input) const
{ {
if (shiftKey == ModifierKey::Disabled) if (shiftKey == ModifierKey::Disabled)
{ {
@@ -282,7 +282,7 @@ bool Shortcut::CheckShiftKey(const DWORD& input) const
} }
// Function to set a key in the shortcut based on the passed key code argument. Returns false if it is already set to the same value. This can be used to avoid UI refreshing // Function to set a key in the shortcut based on the passed key code argument. Returns false if it is already set to the same value. This can be used to avoid UI refreshing
bool Shortcut::SetKey(const DWORD& input) bool Shortcut::SetKey(const DWORD input)
{ {
// Since there isn't a key for a common Win key we use the key code defined by us // Since there isn't a key for a common Win key we use the key code defined by us
if (input == CommonSharedConstants::VK_WIN_BOTH) if (input == CommonSharedConstants::VK_WIN_BOTH)
@@ -394,7 +394,7 @@ bool Shortcut::SetKey(const DWORD& input)
} }
// Function to reset the state of a shortcut key based on the passed key code argument. Since there is no VK_WIN code, use the second argument for setting common win key. // Function to reset the state of a shortcut key based on the passed key code argument. Since there is no VK_WIN code, use the second argument for setting common win key.
void Shortcut::ResetKey(const DWORD& input) void Shortcut::ResetKey(const DWORD input)
{ {
// Since there isn't a key for a common Win key this is handled with a separate argument. // Since there isn't a key for a common Win key this is handled with a separate argument.
if (input == CommonSharedConstants::VK_WIN_BOTH || input == VK_LWIN || input == VK_RWIN) if (input == CommonSharedConstants::VK_WIN_BOTH || input == VK_LWIN || input == VK_RWIN)
@@ -415,7 +415,7 @@ void Shortcut::ResetKey(const DWORD& input)
} }
else else
{ {
actionKey = NULL; actionKey = {};
} }
} }

View File

@@ -1,5 +1,8 @@
#pragma once #pragma once
#include "ModifierKey.h" #include "ModifierKey.h"
#include <compare>
#include <tuple>
#include <variant> #include <variant>
namespace KeyboardManagerInput namespace KeyboardManagerInput
@@ -14,91 +17,34 @@ private:
// Function to split a wstring based on a delimiter and return a vector of split strings // Function to split a wstring based on a delimiter and return a vector of split strings
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter); std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter);
public: inline auto comparator() const
ModifierKey winKey;
ModifierKey ctrlKey;
ModifierKey altKey;
ModifierKey shiftKey;
DWORD actionKey;
// By default create an empty shortcut
Shortcut() :
winKey(ModifierKey::Disabled), ctrlKey(ModifierKey::Disabled), altKey(ModifierKey::Disabled), shiftKey(ModifierKey::Disabled), actionKey(NULL)
{ {
return std::make_tuple(winKey, ctrlKey, altKey, shiftKey, actionKey);
} }
public:
ModifierKey winKey = ModifierKey::Disabled;
ModifierKey ctrlKey = ModifierKey::Disabled;
ModifierKey altKey = ModifierKey::Disabled;
ModifierKey shiftKey = ModifierKey::Disabled;
DWORD actionKey = {};
Shortcut() = default;
// Constructor to initialize Shortcut from it's virtual key code string representation. // Constructor to initialize Shortcut from it's virtual key code string representation.
Shortcut(const std::wstring& shortcutVK); Shortcut(const std::wstring& shortcutVK);
// Constructor to initialize shortcut from a list of keys // Constructor to initialize shortcut from a list of keys
Shortcut(const std::vector<int32_t>& keys); Shortcut(const std::vector<int32_t>& keys);
// == operator inline friend auto operator<=>(const Shortcut& lhs, const Shortcut& rhs) noexcept
inline bool operator==(const Shortcut& sc) const
{ {
return (winKey == sc.winKey && ctrlKey == sc.ctrlKey && altKey == sc.altKey && shiftKey == sc.shiftKey && actionKey == sc.actionKey); return lhs.comparator() <=> rhs.comparator();
} }
// Less than operator must be defined to use with std::map. inline friend bool operator==(const Shortcut& lhs, const Shortcut& rhs) noexcept
inline bool operator<(const Shortcut& sc) const
{ {
// Compare win key first return lhs.comparator() == rhs.comparator();
if (winKey < sc.winKey)
{
return true;
}
else if (winKey > sc.winKey)
{
return false;
}
else
{
// If win key is equal, then compare ctrl key
if (ctrlKey < sc.ctrlKey)
{
return true;
}
else if (ctrlKey > sc.ctrlKey)
{
return false;
}
else
{
// If ctrl key is equal, then compare alt key
if (altKey < sc.altKey)
{
return true;
}
else if (altKey > sc.altKey)
{
return false;
}
else
{
// If alt key is equal, then compare shift key
if (shiftKey < sc.shiftKey)
{
return true;
}
else if (shiftKey > sc.shiftKey)
{
return false;
}
else
{
// If shift key is equal, then compare action key
if (actionKey < sc.actionKey)
{
return true;
}
else
{
return false;
}
}
}
}
}
} }
// Function to return the number of keys in the shortcut // Function to return the number of keys in the shortcut
@@ -126,22 +72,22 @@ public:
DWORD GetShiftKey() const; DWORD GetShiftKey() const;
// Function to check if the input key matches the win key expected in the shortcut // Function to check if the input key matches the win key expected in the shortcut
bool CheckWinKey(const DWORD& input) const; bool CheckWinKey(const DWORD input) const;
// Function to check if the input key matches the ctrl key expected in the shortcut // Function to check if the input key matches the ctrl key expected in the shortcut
bool CheckCtrlKey(const DWORD& input) const; bool CheckCtrlKey(const DWORD input) const;
// Function to check if the input key matches the alt key expected in the shortcut // Function to check if the input key matches the alt key expected in the shortcut
bool CheckAltKey(const DWORD& input) const; bool CheckAltKey(const DWORD input) const;
// Function to check if the input key matches the shift key expected in the shortcut // Function to check if the input key matches the shift key expected in the shortcut
bool CheckShiftKey(const DWORD& input) const; bool CheckShiftKey(const DWORD input) const;
// Function to set a key in the shortcut based on the passed key code argument. Returns false if it is already set to the same value. This can be used to avoid UI refreshing // Function to set a key in the shortcut based on the passed key code argument. Returns false if it is already set to the same value. This can be used to avoid UI refreshing
bool SetKey(const DWORD& input); bool SetKey(const DWORD input);
// Function to reset the state of a shortcut key based on the passed key code argument // Function to reset the state of a shortcut key based on the passed key code argument
void ResetKey(const DWORD& input); void ResetKey(const DWORD input);
// Function to return the string representation of the shortcut in virtual key codes appended in a string by ";" separator. // Function to return the string representation of the shortcut in virtual key codes appended in a string by ";" separator.
winrt::hstring ToHstringVK() const; winrt::hstring ToHstringVK() const;