diff --git a/src/FlashCom/App.cpp b/src/FlashCom/App.cpp index 302e79f..c0db8ac 100644 --- a/src/FlashCom/App.cpp +++ b/src/FlashCom/App.cpp @@ -8,6 +8,7 @@ namespace { const std::unordered_set c_hotkeyCombo{ VK_LWIN, VK_SPACE }; + constexpr std::chrono::milliseconds c_hotkeyExpirationTime{ 1000 }; } namespace FlashCom @@ -88,28 +89,53 @@ namespace FlashCom if (isKeyDown) { m_hotkeysPressed.insert(kb->vkCode); + if (m_hotkeysPressed.size() == c_hotkeyCombo.size()) + { + SPDLOG_INFO("App::HandleLowLevelKeyboardInput - Hotkey pressed"); + ToggleVisibility(); + + // This dummy event is to prevent Start from thinking that the Win key was + // just pressed. + // See https://github.com/microsoft/PowerToys/pull/4874 + INPUT dummyEvent[1] = {}; + dummyEvent[0].type = INPUT_KEYBOARD; + dummyEvent[0].ki.wVk = 0xFF; + dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP; + SendInput(1, dummyEvent, sizeof(INPUT)); + + // Reset hotkey state to avoid any stuck keys or accidental invocations + m_hotkeysPressed.clear(); + + // Cancel reset timer + if (m_hotkeyResetTimer) + { + m_hotkeyResetTimer.Cancel(); + m_hotkeyResetTimer = nullptr; + } + + return FlashCom::Input::LowLevelCallbackReturnKind::Handled; + } + else + { + // Every time a new hotkey key is pressed, (re)set a timer. + // Once the timer elapses, reset hotkey key state. + // This is to handle situations where key events are "eaten" before they reach us + // (ex. User invokes lock with Win+L, lock screen eats the key-up events) + // Otherwise keys might get stuck in a "pressed" state. + if (m_hotkeyResetTimer) + { + m_hotkeyResetTimer.Cancel(); + } + m_hotkeyResetTimer = winrt::WST::ThreadPoolTimer::CreateTimer( + { this, &App::OnHotkeyTimerElapsed }, c_hotkeyExpirationTime); + } } else { m_hotkeysPressed.erase(kb->vkCode); } - if (m_hotkeysPressed.size() == c_hotkeyCombo.size()) - { - SPDLOG_INFO("App::HandleLowLevelKeyboardInput - Hotkey pressed"); - ToggleVisibility(); - - // This dummy event is to prevent Start from thinking that the Win key was - // just pressed. - // See https://github.com/microsoft/PowerToys/pull/4874 - INPUT dummyEvent[1] = {}; - dummyEvent[0].type = INPUT_KEYBOARD; - dummyEvent[0].ki.wVk = 0xFF; - dummyEvent[0].ki.dwFlags = KEYEVENTF_KEYUP; - SendInput(1, dummyEvent, sizeof(INPUT)); - - return FlashCom::Input::LowLevelCallbackReturnKind::Handled; - } + return FlashCom::Input::LowLevelCallbackReturnKind::Unhandled; } @@ -146,6 +172,14 @@ namespace FlashCom } } + void App::OnHotkeyTimerElapsed(winrt::WST::ThreadPoolTimer timer) + { + // See comment in App::HandleLowLevelKeyboardInput + SPDLOG_INFO("App::OnHotkeyTimerElapsed - Timer elapsed, clearing hotkey state"); + m_hotkeysPressed.clear(); + m_hotkeyResetTimer = nullptr; + } + void App::OnKeyDown(uint8_t vkeyCode) { if (vkeyCode == VK_ESCAPE) diff --git a/src/FlashCom/App.h b/src/FlashCom/App.h index d9a38af..4f1e35b 100644 --- a/src/FlashCom/App.h +++ b/src/FlashCom/App.h @@ -28,10 +28,12 @@ namespace FlashCom View::TrayIcon m_trayIcon; View::Ui m_ui; std::unordered_set m_hotkeysPressed; + winrt::Windows::System::Threading::ThreadPoolTimer m_hotkeyResetTimer{ nullptr }; bool m_isShowing{ false }; App(const HINSTANCE& hInstance); void HandleFocusLost(); + void OnHotkeyTimerElapsed(winrt::Windows::System::Threading::ThreadPoolTimer timer); void OnKeyDown(uint8_t vkeyCode); void OnKeyUp(uint8_t vkeyCode); void Show(); diff --git a/src/FlashCom/pch.h b/src/FlashCom/pch.h index 33f9910..8979401 100644 --- a/src/FlashCom/pch.h +++ b/src/FlashCom/pch.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ namespace winrt namespace WGDX = Windows::Graphics::DirectX; namespace WStorage = Windows::Storage; namespace WS = Windows::System; + namespace WST = Windows::System::Threading; namespace WUI = Windows::UI; namespace WUIC = Windows::UI::Composition; namespace WUICD = Windows::UI::Composition::Desktop; diff --git a/src/Packaging/Package.appxmanifest b/src/Packaging/Package.appxmanifest index 09d1aa5..84a2629 100644 --- a/src/Packaging/Package.appxmanifest +++ b/src/Packaging/Package.appxmanifest @@ -9,7 +9,7 @@ + Version="0.2.1.0" /> FlashCom