diff --git a/src/modules/keyboardmanager/common/KeyboardManagerConstants.h b/src/modules/keyboardmanager/common/KeyboardManagerConstants.h index 3f849d6160..8b54f5cf0b 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerConstants.h +++ b/src/modules/keyboardmanager/common/KeyboardManagerConstants.h @@ -77,10 +77,10 @@ namespace KeyboardManagerConstants // Shared style constants for both Remap Table and Shortcut Table inline const double HeaderButtonWidth = 100; - // Flags used for distinguishing key events sent by Keyboard Manager - inline const ULONG_PTR KEYBOARDMANAGER_SINGLEKEY_FLAG = 0x11; - inline const ULONG_PTR KEYBOARDMANAGER_SHORTCUT_FLAG = 0x101; + inline const ULONG_PTR KEYBOARDMANAGER_SINGLEKEY_FLAG = 0x11; // Single key remaps + inline const ULONG_PTR KEYBOARDMANAGER_SHORTCUT_FLAG = 0x101; // Shortcut remaps + inline const ULONG_PTR KEYBOARDMANAGER_SUPPRESS_FLAG = 0x111; // Key events which must be suppressed // Dummy key event used in between key up and down events to prevent certain global events from happening inline const DWORD DUMMY_KEY = 0xFF; diff --git a/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp b/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp index 4db3d1ae43..2be48d4a30 100644 --- a/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp +++ b/src/modules/keyboardmanager/dll/KeyboardEventHandlers.cpp @@ -601,4 +601,20 @@ namespace KeyboardEventHandlers return 0; } + + // Function to ensure Num Lock state does not change when it is suppressed by the low level hook + void SetNumLockToPreviousState() + { + // Num Lock's key state is applied before it is intercepted by low level keyboard hooks, so we have to manually set back the state when we suppress the key. This is done by sending an additional key up, key down set of messages. + // We need 2 key events because after Num Lock is suppressed, key up to release num lock key and key down to revert the num lock state + int key_count = 2; + LPINPUT keyEventList = new INPUT[size_t(key_count)](); + memset(keyEventList, 0, sizeof(keyEventList)); + + // Use the shortcut flag to ensure these are not intercepted by any remapped keys or shortcuts + KeyboardManagerHelper::SetKeyEvent(keyEventList, 0, INPUT_KEYBOARD, VK_NUMLOCK, KEYEVENTF_KEYUP, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG); + KeyboardManagerHelper::SetKeyEvent(keyEventList, 1, INPUT_KEYBOARD, VK_NUMLOCK, 0, KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG); + UINT res = SendInput((UINT)key_count, keyEventList, sizeof(INPUT)); + delete[] keyEventList; + } } diff --git a/src/modules/keyboardmanager/dll/KeyboardEventHandlers.h b/src/modules/keyboardmanager/dll/KeyboardEventHandlers.h index 9faea52cea..b802736858 100644 --- a/src/modules/keyboardmanager/dll/KeyboardEventHandlers.h +++ b/src/modules/keyboardmanager/dll/KeyboardEventHandlers.h @@ -18,4 +18,7 @@ namespace KeyboardEventHandlers // Function to a handle an app-specific shortcut remap intptr_t HandleAppSpecificShortcutRemapEvent(LowlevelKeyboardEvent* data, KeyboardManagerState& keyboardManagerState) noexcept; + + // Function to ensure Num Lock state does not change when it is suppressed by the low level hook + void SetNumLockToPreviousState(); }; diff --git a/src/modules/keyboardmanager/dll/dllmain.cpp b/src/modules/keyboardmanager/dll/dllmain.cpp index 5953dbd7a9..1d4eba889f 100644 --- a/src/modules/keyboardmanager/dll/dllmain.cpp +++ b/src/modules/keyboardmanager/dll/dllmain.cpp @@ -283,6 +283,11 @@ public: event.wParam = wParam; if (keyboardmanager_object_ptr->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 + if (event.lParam->vkCode == VK_NUMLOCK && (event.wParam == WM_KEYDOWN || event.wParam == WM_SYSKEYDOWN) && event.lParam->dwExtraInfo != KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) + { + KeyboardEventHandlers::SetNumLockToPreviousState(); + } return 1; } } @@ -324,6 +329,12 @@ public: // Function called by the hook procedure to handle the events. This is the starting point function for remapping intptr_t HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept { + // If key has suppress flag, then suppress it + if (data->lParam->dwExtraInfo == KeyboardManagerConstants::KEYBOARDMANAGER_SUPPRESS_FLAG) + { + return 1; + } + // If the Detect Key Window is currently activated, then suppress the keyboard event KeyboardManagerHelper::KeyboardHookDecision singleKeyRemapUIDetected = keyboardManagerState.DetectSingleRemapKeyUIBackend(data); if (singleKeyRemapUIDetected == KeyboardManagerHelper::KeyboardHookDecision::Suppress)