From 2a544583c0109c748a46a28d57bd7560e04a5b1a Mon Sep 17 00:00:00 2001 From: Andrey Nekrasov Date: Wed, 3 Jan 2024 16:49:29 +0100 Subject: [PATCH] [KBM] Do not register low level hook if there're no remappings (#29708) * [KBM] Do not register low level hook if there're no remappings * f: typo * f: address review comment --- src/common/utils/window.h | 15 ++++-- .../KeyboardManagerEngine/main.cpp | 9 +++- .../KeyboardManager.cpp | 47 +++++++++++++++++++ .../KeyboardManager.h | 7 +++ 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/common/utils/window.h b/src/common/utils/window.h index cfcf20534a..dbce3a95ee 100644 --- a/src/common/utils/window.h +++ b/src/common/utils/window.h @@ -6,9 +6,13 @@ #include #include +#include +#include // Initializes and runs windows message loop -inline int run_message_loop(const bool until_idle = false, const std::optional timeout_ms = {}) +inline int run_message_loop(const bool until_idle = false, + const std::optional timeout_ms = {}, + std::unordered_map> wm_app_msg_callbacks = {}) { MSG msg{}; bool stop = false; @@ -24,11 +28,16 @@ inline int run_message_loop(const bool until_idle = false, const std::optionalsecond(); } + if (timeout_ms.has_value()) { KillTimer(nullptr, timerId); } + return static_cast(msg.wParam); } @@ -60,7 +69,7 @@ template inline T GetWindowCreateParam(LPARAM lparam) { static_assert(sizeof(T) <= sizeof(void*)); - T data{ static_cast (reinterpret_cast(lparam)->lpCreateParams) }; + T data{ static_cast(reinterpret_cast(lparam)->lpCreateParams) }; return data; } @@ -74,5 +83,5 @@ inline void StoreWindowParam(HWND window, T data) template inline T GetWindowParam(HWND window) { - return reinterpret_cast (GetWindowLongPtrW(window, GWLP_USERDATA)); + return reinterpret_cast(GetWindowLongPtrW(window, GWLP_USERDATA)); } diff --git a/src/modules/keyboardmanager/KeyboardManagerEngine/main.cpp b/src/modules/keyboardmanager/KeyboardManagerEngine/main.cpp index 25965ffd9b..31417e9c23 100644 --- a/src/modules/keyboardmanager/KeyboardManagerEngine/main.cpp +++ b/src/modules/keyboardmanager/KeyboardManagerEngine/main.cpp @@ -61,9 +61,14 @@ int WINAPI wWinMain(_In_ HINSTANCE /*hInstance*/, } auto kbm = KeyboardManager(); - kbm.StartLowlevelKeyboardHook(); + if (kbm.HasRegisteredRemappings()) + kbm.StartLowlevelKeyboardHook(); - run_message_loop(); + auto StartHookFunc = [&kbm]() { + kbm.StartLowlevelKeyboardHook(); + }; + + run_message_loop({}, {}, { { KeyboardManager::StartHookMessageID, StartHookFunc } }); kbm.StopLowlevelKeyboardHook(); Trace::UnregisterProvider(); diff --git a/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.cpp b/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.cpp index acfcacfc3b..bb5b8a13e7 100644 --- a/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.cpp +++ b/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.cpp @@ -21,8 +21,15 @@ HHOOK KeyboardManager::hookHandleCopy; HHOOK KeyboardManager::hookHandle; KeyboardManager* KeyboardManager::keyboardManagerObjectPtr; +namespace +{ + DWORD mainThreadId = {}; +} + KeyboardManager::KeyboardManager() { + mainThreadId = GetCurrentThreadId(); + // Load the initial settings. LoadSettings(); @@ -38,9 +45,11 @@ KeyboardManager::KeyboardManager() } loadingSettings = true; + bool loadedSuccessfully = false; try { LoadSettings(); + loadedSuccessfully = true; } catch (...) { @@ -48,6 +57,18 @@ KeyboardManager::KeyboardManager() } loadingSettings = false; + + if (!loadedSuccessfully) + return; + + const bool newHasRemappings = HasRegisteredRemappingsUnchecked(); + // We didn't have any bindings before and we have now + if (newHasRemappings && !hookHandle) + PostThreadMessageW(mainThreadId, StartHookMessageID, 0, 0); + + // All bindings were removed + if (!newHasRemappings && hookHandle) + StopLowlevelKeyboardHook(); }; editorIsRunningEvent = CreateEvent(nullptr, true, false, KeyboardManagerConstants::EditorWindowEventName.c_str()); @@ -121,6 +142,32 @@ void KeyboardManager::StopLowlevelKeyboardHook() } } +bool KeyboardManager::HasRegisteredRemappings() const +{ + constexpr int MaxAttempts = 5; + + if (loadingSettings) + { + for (int currentAttempt = 0; currentAttempt < MaxAttempts; ++currentAttempt) + { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + if (!loadingSettings) + break; + } + } + + // Assume that we have registered remappings to be on the safe side if we couldn't check + if (loadingSettings) + return true; + + return HasRegisteredRemappingsUnchecked(); +} + +bool KeyboardManager::HasRegisteredRemappingsUnchecked() const +{ + return !(state.appSpecificShortcutReMap.empty() && state.appSpecificShortcutReMapSortedKeys.empty() && state.osLevelShortcutReMap.empty() && state.osLevelShortcutReMapSortedKeys.empty() && state.singleKeyReMap.empty() && state.singleKeyToTextReMap.empty()); +} + intptr_t KeyboardManager::HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept { if (loadingSettings) diff --git a/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.h b/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.h index 457a9135b7..846d19a3db 100644 --- a/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.h +++ b/src/modules/keyboardmanager/KeyboardManagerEngineLibrary/KeyboardManager.h @@ -7,6 +7,8 @@ class KeyboardManager { public: + static const inline DWORD StartHookMessageID = WM_APP + 1; + // Constructor KeyboardManager(); @@ -21,7 +23,12 @@ public: void StartLowlevelKeyboardHook(); void StopLowlevelKeyboardHook(); + bool HasRegisteredRemappings() const; + private: + // Returns whether there are any remappings available without waiting for settings to load + bool HasRegisteredRemappingsUnchecked() const; + // Contains the non localized module name std::wstring moduleName = KeyboardManagerConstants::ModuleName;