diff --git a/src/runner/centralized_kb_hook.cpp b/src/runner/centralized_kb_hook.cpp index 72b473bd08c5..3e05a6de4085 100644 --- a/src/runner/centralized_kb_hook.cpp +++ b/src/runner/centralized_kb_hook.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "centralized_kb_hook.h" +#include #include #include #include @@ -42,7 +43,7 @@ namespace CentralizedKeyboardHook // keep track of last pressed key, to detect repeated keys and if there are more keys pressed. const DWORD VK_DISABLED = CommonSharedConstants::VK_DISABLED; - DWORD vkCodePressed = VK_DISABLED; + std::atomic vkCodePressed{ VK_DISABLED }; // Save the runner window handle for registering timers. HWND runnerWindow; @@ -72,7 +73,12 @@ namespace CentralizedKeyboardHook { if (it.idTimer == idTimer) { - it.action(); + // Revalidate that the key is still physically held before firing. + // This prevents ghost activations after the key was already released. + if (GetAsyncKeyState(static_cast(it.virtualKey)) & 0x8000) + { + it.action(); + } } } @@ -177,6 +183,7 @@ namespace CentralizedKeyboardHook dummyEvent[0].type = INPUT_KEYBOARD; dummyEvent[0].ki.wVk = 0xFF; dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP; + dummyEvent[0].ki.dwExtraInfo = PowertoyModuleIface::CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG; SendInput(1, dummyEvent, sizeof(INPUT)); // Swallow the key press @@ -263,6 +270,18 @@ namespace CentralizedKeyboardHook void Stop() noexcept { + // Kill all pending pressed-key timers before unhooking to prevent + // ghost callbacks firing after the hook is removed. + { + std::unique_lock lock{ pressedKeyMutex }; + for (const auto& it : pressedKeyDescriptors) + { + KillTimer(runnerWindow, it.idTimer); + } + } + + vkCodePressed = VK_DISABLED; + if (hHook && UnhookWindowsHookEx(hHook)) { hHook = NULL;