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  }