KeyboardManagerState.h
1 #pragma once 2 3 #include <common/hooks/LowlevelKeyboardEvent.h> 4 #include <common/interop/keyboard_layout.h> 5 6 #include <keyboardmanager/common/KeyboardManagerConstants.h> 7 #include <keyboardmanager/common/Shortcut.h> 8 9 class KeyDelay; 10 11 namespace Helpers 12 { 13 // Enum type to store possible decision for input in the low level hook 14 enum class KeyboardHookDecision 15 { 16 ContinueExec, 17 Suppress, 18 SkipHook 19 }; 20 } 21 22 namespace winrt::Windows::UI::Xaml::Controls 23 { 24 struct StackPanel; 25 struct TextBlock; 26 } 27 28 namespace KBMEditor 29 { 30 // Enum type to store different states of the UI 31 enum class KeyboardManagerUIState 32 { 33 // If set to this value then there is no keyboard manager window currently active that requires a hook 34 Deactivated, 35 // If set to this value then the detect key window is currently active and it requires a hook 36 DetectSingleKeyRemapWindowActivated, 37 // If set to this value then the detect shortcut window in edit keyboard window is currently active and it requires a hook 38 DetectShortcutWindowInEditKeyboardWindowActivated, 39 // If set to this value then the edit keyboard window is currently active and remaps should not be applied 40 EditKeyboardWindowActivated, 41 // If set to this value then the detect shortcut window is currently active and it requires a hook 42 DetectShortcutWindowActivated, 43 // If set to this value then the edit shortcuts window is currently active and remaps should not be applied 44 EditShortcutsWindowActivated 45 }; 46 47 // Class to store the shared state of the keyboard manager between the UI and the hook 48 class KeyboardManagerState 49 { 50 private: 51 // State variable used to store which UI window is currently active that requires interaction with the hook 52 KeyboardManagerUIState uiState; 53 std::mutex uiState_mutex; 54 55 // Window handle for the current UI window which is active. Should be set to nullptr if UI is deactivated 56 HWND currentUIWindow; 57 std::mutex currentUIWindow_mutex; 58 59 // Object to store the shortcut detected in the detect shortcut UI window. Gets cleared on releasing keys. This is used in both the backend and the UI. 60 Shortcut detectedShortcut; 61 std::mutex detectedShortcut_mutex; 62 63 // Object to store the shortcut state displayed in the UI window. Always stores last displayed shortcut irrespective of releasing keys. This is used in both the backend and the UI. 64 Shortcut currentShortcut; 65 std::mutex currentShortcut_mutex; 66 67 // Store detected remap key in the remap UI window. This is used in both the backend and the UI. 68 DWORD detectedRemapKey; 69 std::mutex detectedRemapKey_mutex; 70 71 // Stores the UI element which is to be updated based on the remap key entered. 72 winrt::Windows::Foundation::IInspectable currentSingleKeyUI; 73 std::mutex currentSingleKeyUI_mutex; 74 75 // Stores the UI element which is to be updated based on the shortcut entered (each StackPanel represents a row of keys) 76 winrt::Windows::Foundation::IInspectable currentShortcutUI1; 77 winrt::Windows::Foundation::IInspectable currentShortcutUI2; 78 std::mutex currentShortcutUI_mutex; 79 80 // Registered KeyDelay objects, used to notify delayed key events. 81 std::map<DWORD, std::unique_ptr<KeyDelay>> keyDelays; 82 std::mutex keyDelays_mutex; 83 84 public: 85 // Display a key by appending a border Control as a child of the panel. 86 winrt::Windows::UI::Xaml::Controls::TextBlock AddKeyToLayout(const winrt::Windows::UI::Xaml::Controls::StackPanel& panel, const winrt::hstring& key); 87 88 89 90 // flag to set if we want to allow building a chord 91 bool AllowChord = false; 92 93 bool exactMatch = false; 94 95 // Stores the keyboard layout 96 LayoutMap keyboardMap; 97 98 // Constructor 99 KeyboardManagerState(); 100 101 // Destructor 102 ~KeyboardManagerState(); 103 104 // Function to reset the UI state members 105 void ResetUIState(); 106 107 // Function to check the if the UI state matches the argument state. For states with detect windows it also checks if the window is in focus. 108 bool CheckUIState(KeyboardManagerUIState state); 109 110 // Function to set the window handle of the current UI window that is activated 111 void SetCurrentUIWindow(HWND windowHandle); 112 113 // Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument. 114 void SetUIState(KeyboardManagerUIState state, HWND windowHandle = nullptr); 115 116 // Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook 117 void ConfigureDetectShortcutUI(const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock1, const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock2); 118 119 // Function to set the textblock of the detect remap key UI so that it can be accessed by the hook 120 void ConfigureDetectSingleKeyRemapUI(const winrt::Windows::UI::Xaml::Controls::StackPanel& textBlock); 121 122 // Function to update the detect shortcut UI based on the entered keys 123 void UpdateDetectShortcutUI(); 124 125 // Function to update the detect remap key UI based on the entered key. 126 void UpdateDetectSingleKeyRemapUI(); 127 128 // Function to return the currently detected shortcut which is displayed on the UI 129 Shortcut GetDetectedShortcut(); 130 131 // Function to SetDetectedShortcut and also UpdateDetectShortcutUI 132 void KeyboardManagerState::SetDetectedShortcut(Shortcut shortcut); 133 134 // Function to return the currently detected remap key which is displayed on the UI 135 DWORD GetDetectedSingleRemapKey(); 136 137 // Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active. 138 Helpers::KeyboardHookDecision DetectSingleRemapKeyUIBackend(LowlevelKeyboardEvent* data); 139 140 // Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active. 141 Helpers::KeyboardHookDecision DetectShortcutUIBackend(LowlevelKeyboardEvent* data, bool isRemapKey); 142 143 // Add a KeyDelay object to get delayed key presses events for a given virtual key 144 // NOTE: this will throw an exception if a virtual key is registered twice. 145 // NOTE*: the virtual key should represent the original, unmapped virtual key. 146 void RegisterKeyDelay( 147 DWORD key, 148 std::function<void(DWORD)> onShortPress, 149 std::function<void(DWORD)> onLongPressDetected, 150 std::function<void(DWORD)> onLongPressReleased); 151 152 // Remove a KeyDelay. 153 // NOTE: this method will throw if the virtual key is not registered beforehand. 154 // NOTE*: the virtual key should represent the original, unmapped virtual key. 155 void UnregisterKeyDelay(DWORD key); 156 157 // Function to clear all the registered key delays 158 void ClearRegisteredKeyDelays(); 159 160 void ClearStoredShortcut(); 161 162 // Handle a key event, for a delayed key. 163 bool HandleKeyDelayEvent(LowlevelKeyboardEvent* ev); 164 165 // Update the currently selected single key remap 166 void SelectDetectedRemapKey(DWORD key); 167 168 // Update the currently selected shortcut. 169 void SelectDetectedShortcut(DWORD key); 170 171 // Reset the shortcut (backend) state after releasing a key. 172 void ResetDetectedShortcutKey(DWORD key); 173 }; 174 }