From e0ddaa74d0ef46acd9080f38359166ae81ede069 Mon Sep 17 00:00:00 2001 From: Arjun Balgovind <32061677+arjunbalgovind@users.noreply.github.com> Date: Thu, 9 Apr 2020 09:20:19 -0700 Subject: [PATCH] Add unicode naming for keys (dev/keyboardManager) (#1978) * Added key names * Display names in detect keyboard UI * Added keyboard layout for edit keyboard window * Removed commented code * removed unused code * fixed argument modifiers * Added newline at EOF * Added unicode changes to edit shortcuts window --- .../common/KeyboardManagerCommon.vcxproj | 2 + .../KeyboardManagerCommon.vcxproj.filters | 6 + .../common/KeyboardManagerState.cpp | 43 ++--- .../common/KeyboardManagerState.h | 10 +- .../keyboardmanager/common/LayoutMap.cpp | 14 ++ .../keyboardmanager/common/LayoutMap.h | 152 ++++++++++++++++++ .../keyboardmanager/common/Shortcut.cpp | 119 ++------------ src/modules/keyboardmanager/common/Shortcut.h | 18 +-- src/modules/keyboardmanager/dll/dllmain.cpp | 3 - .../keyboardmanager/ui/EditKeyboardWindow.cpp | 42 +++-- .../ui/EditShortcutsWindow.cpp | 53 +++--- .../keyboardmanager/ui/EditShortcutsWindow.h | 1 + .../keyboardmanager/ui/ShortcutControl.cpp | 31 +++- .../keyboardmanager/ui/ShortcutControl.h | 12 +- .../ui/SingleKeyRemapControl.cpp | 26 ++- .../ui/SingleKeyRemapControl.h | 10 +- 16 files changed, 309 insertions(+), 233 deletions(-) create mode 100644 src/modules/keyboardmanager/common/LayoutMap.cpp create mode 100644 src/modules/keyboardmanager/common/LayoutMap.h diff --git a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj index de3c0bda42..9fc11fdcee 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj +++ b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj @@ -89,6 +89,7 @@ + Create Create @@ -99,6 +100,7 @@ + diff --git a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters index d75bb93c11..8451c15957 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters +++ b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters @@ -24,6 +24,9 @@ Source Files + + Source Files + Source Files @@ -41,6 +44,9 @@ Header Files + + Header Files + Header Files diff --git a/src/modules/keyboardmanager/common/KeyboardManagerState.cpp b/src/modules/keyboardmanager/common/KeyboardManagerState.cpp index 2b208f613b..bf729a166c 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerState.cpp +++ b/src/modules/keyboardmanager/common/KeyboardManagerState.cpp @@ -58,6 +58,10 @@ void KeyboardManagerState::ResetUIState() detectedShortcut.Reset(); detectedShortcut_lock.unlock(); + std::unique_lock currentShortcut_lock(currentShortcut_mutex); + currentShortcut.Reset(); + currentShortcut_lock.unlock(); + // Reset all the single key remap UI stored variables. std::unique_lock currentSingleKeyUI_lock(currentSingleKeyUI_mutex); currentSingleKeyUI = nullptr; @@ -158,8 +162,11 @@ void KeyboardManagerState::UpdateDetectShortcutUI() std::unique_lock detectedShortcut_lock(detectedShortcut_mutex); - - std::vector shortcut = detectedShortcut.GetKeyVector(); + std::unique_lock currentShortcut_lock(currentShortcut_mutex); + // Save the latest displayed shortcut + currentShortcut = detectedShortcut; + currentShortcut_lock.unlock(); + std::vector shortcut = detectedShortcut.GetKeyVector(keyboardMap); detectedShortcut_lock.unlock(); @@ -184,7 +191,7 @@ void KeyboardManagerState::UpdateDetectSingleKeyRemapUI() } std::unique_lock detectedRemapKey_lock(detectedRemapKey_mutex); - hstring key = winrt::to_hstring((unsigned int)detectedRemapKey); + hstring key = winrt::to_hstring(keyboardMap.GetKeyName(detectedRemapKey).c_str()); detectedRemapKey_lock.unlock(); // Since this function is invoked from the back-end thread, in order to update the UI the dispatcher must be used. @@ -198,37 +205,15 @@ void KeyboardManagerState::UpdateDetectSingleKeyRemapUI() // Function to return the currently detected shortcut which is displayed on the UI Shortcut KeyboardManagerState::GetDetectedShortcut() { - std::unique_lock lock(currentShortcutUI_mutex); - - std::vector keys; - if (currentShortcutUI.Children().Size() > 0) - { - for (auto border : currentShortcutUI.Children()) - { - auto keyString = border.as().Child().as().Text(); - keys.push_back(keyString); - } - } - - lock.unlock(); - return Shortcut::CreateShortcut(keys); + std::lock_guard lock(currentShortcut_mutex); + return currentShortcut; } // Function to return the currently detected remap key which is displayed on the UI DWORD KeyboardManagerState::GetDetectedSingleRemapKey() { - std::unique_lock lock(currentSingleKeyUI_mutex); - DWORD key = 0; - if (currentSingleKeyUI.Children().Size() > 0) - { - auto border = currentSingleKeyUI.Children().GetAt(0); - auto keyString = border.as().Child().as().Text(); - key = std::stoul(keyString.c_str()); - } - - lock.unlock(); - - return key; + std::lock_guard lock(detectedRemapKey_mutex); + return detectedRemapKey; } // 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. diff --git a/src/modules/keyboardmanager/common/KeyboardManagerState.h b/src/modules/keyboardmanager/common/KeyboardManagerState.h index 7070bf70d4..62d90fb437 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerState.h +++ b/src/modules/keyboardmanager/common/KeyboardManagerState.h @@ -1,5 +1,6 @@ #pragma once #include "Helpers.h" +#include "LayoutMap.h" #include "Shortcut.h" #include "RemapShortcut.h" #include @@ -30,10 +31,14 @@ private: HWND currentUIWindow; std::mutex currentUIWindow_mutex; - // Object to store the shortcut detected in the detect shortcut UI window. This is used in both the backend and the UI. + // 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. Shortcut detectedShortcut; std::mutex detectedShortcut_mutex; + // 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. + Shortcut currentShortcut; + std::mutex currentShortcut_mutex; + // Store detected remap key in the remap UI window. This is used in both the backend and the UI. DWORD detectedRemapKey; std::mutex detectedRemapKey_mutex; @@ -67,6 +72,9 @@ public: std::map> appSpecificShortcutReMap; std::mutex appSpecificShortcutReMap_mutex; + // Stores the keyboard layout + LayoutMap keyboardMap; + // Constructor KeyboardManagerState(); diff --git a/src/modules/keyboardmanager/common/LayoutMap.cpp b/src/modules/keyboardmanager/common/LayoutMap.cpp new file mode 100644 index 0000000000..3763d859a7 --- /dev/null +++ b/src/modules/keyboardmanager/common/LayoutMap.cpp @@ -0,0 +1,14 @@ +#include "pch.h" +#include "LayoutMap.h" + +std::wstring LayoutMap::GetKeyName(DWORD key) +{ + std::wstring result = L"Undefined"; + std::lock_guard lock(keyboardLayoutMap_mutex); + auto it = keyboardLayoutMap.find(key); + if (it != keyboardLayoutMap.end()) + { + result = it->second; + } + return result; +} diff --git a/src/modules/keyboardmanager/common/LayoutMap.h b/src/modules/keyboardmanager/common/LayoutMap.h new file mode 100644 index 0000000000..ceb58cc160 --- /dev/null +++ b/src/modules/keyboardmanager/common/LayoutMap.h @@ -0,0 +1,152 @@ +#pragma once +#include +#include +#include +#include + +// Wrapper class to handle keyboard layout +class LayoutMap +{ +private: + // Stores mappings for all the virtual key codes to the name of the key + std::map keyboardLayoutMap; + std::mutex keyboardLayoutMap_mutex; + +public: + LayoutMap() + { + // Get keyboard layout for current thread + HKL layout = GetKeyboardLayout(0); + unsigned char btKeys[256] = { 0 }; + GetKeyboardState(btKeys); + + // Iterate over all the virtual key codes + for (int i = 0; i < 256; i++) + { + // Get the scan code from the virtual key code + UINT scanCode = MapVirtualKeyExW(i, MAPVK_VK_TO_VSC, layout); + // Get the unicode representation from the virtual key code and scan code pair to + wchar_t szBuffer[3] = { 0 }; + int result = ToUnicodeEx(i, scanCode, (BYTE*)btKeys, szBuffer, 3, 0, layout); + // If a representation is returned + if (result > 0) + { + keyboardLayoutMap[i] = szBuffer; + } + else + { + // Store the virtual key code as string + keyboardLayoutMap[i] = L"VK " + std::to_wstring(i); + } + } + + // Override special key names like Shift, Ctrl etc because they don't have unicode mappings and key names like Enter, Space as they appear as "\r", " " + // To do: localization + keyboardLayoutMap[VK_CANCEL] = L"Break"; + keyboardLayoutMap[VK_BACK] = L"Backspace"; + keyboardLayoutMap[VK_TAB] = L"Tab"; + keyboardLayoutMap[VK_CLEAR] = L"Clear"; + keyboardLayoutMap[VK_RETURN] = L"Enter"; + keyboardLayoutMap[VK_SHIFT] = L"Shift"; + keyboardLayoutMap[VK_CONTROL] = L"Ctrl"; + keyboardLayoutMap[VK_MENU] = L"Alt"; + keyboardLayoutMap[VK_PAUSE] = L"Pause"; + keyboardLayoutMap[VK_CAPITAL] = L"Caps Lock"; + keyboardLayoutMap[VK_ESCAPE] = L"Esc"; + keyboardLayoutMap[VK_SPACE] = L"Space"; + keyboardLayoutMap[VK_PRIOR] = L"PgUp"; + keyboardLayoutMap[VK_NEXT] = L"PgDn"; + keyboardLayoutMap[VK_END] = L"End"; + keyboardLayoutMap[VK_HOME] = L"Home"; + keyboardLayoutMap[VK_LEFT] = L"Left"; + keyboardLayoutMap[VK_UP] = L"Up"; + keyboardLayoutMap[VK_RIGHT] = L"Right"; + keyboardLayoutMap[VK_DOWN] = L"Down"; + keyboardLayoutMap[VK_SELECT] = L"Select"; + keyboardLayoutMap[VK_PRINT] = L"Print"; + keyboardLayoutMap[VK_EXECUTE] = L"Execute"; + keyboardLayoutMap[VK_SNAPSHOT] = L"Print Screen"; + keyboardLayoutMap[VK_INSERT] = L"Insert"; + keyboardLayoutMap[VK_DELETE] = L"Delete"; + keyboardLayoutMap[VK_HELP] = L"Help"; + keyboardLayoutMap[VK_LWIN] = L"LWin"; + keyboardLayoutMap[VK_RWIN] = L"RWin"; + keyboardLayoutMap[VK_APPS] = L"Menu"; + keyboardLayoutMap[VK_SLEEP] = L"Sleep"; + keyboardLayoutMap[VK_NUMPAD0] = L"NumPad 0"; + keyboardLayoutMap[VK_NUMPAD1] = L"NumPad 1"; + keyboardLayoutMap[VK_NUMPAD2] = L"NumPad 2"; + keyboardLayoutMap[VK_NUMPAD3] = L"NumPad 3"; + keyboardLayoutMap[VK_NUMPAD4] = L"NumPad 4"; + keyboardLayoutMap[VK_NUMPAD5] = L"NumPad 5"; + keyboardLayoutMap[VK_NUMPAD6] = L"NumPad 6"; + keyboardLayoutMap[VK_NUMPAD7] = L"NumPad 7"; + keyboardLayoutMap[VK_NUMPAD8] = L"NumPad 8"; + keyboardLayoutMap[VK_NUMPAD9] = L"NumPad 9"; + keyboardLayoutMap[VK_SEPARATOR] = L"Separator"; + keyboardLayoutMap[VK_F1] = L"F1"; + keyboardLayoutMap[VK_F2] = L"F2"; + keyboardLayoutMap[VK_F3] = L"F3"; + keyboardLayoutMap[VK_F4] = L"F4"; + keyboardLayoutMap[VK_F5] = L"F5"; + keyboardLayoutMap[VK_F6] = L"F6"; + keyboardLayoutMap[VK_F7] = L"F7"; + keyboardLayoutMap[VK_F8] = L"F8"; + keyboardLayoutMap[VK_F9] = L"F9"; + keyboardLayoutMap[VK_F10] = L"F10"; + keyboardLayoutMap[VK_F11] = L"F11"; + keyboardLayoutMap[VK_F12] = L"F12"; + keyboardLayoutMap[VK_F13] = L"F13"; + keyboardLayoutMap[VK_F14] = L"F14"; + keyboardLayoutMap[VK_F15] = L"F15"; + keyboardLayoutMap[VK_F16] = L"F16"; + keyboardLayoutMap[VK_F17] = L"F17"; + keyboardLayoutMap[VK_F18] = L"F18"; + keyboardLayoutMap[VK_F19] = L"F19"; + keyboardLayoutMap[VK_F20] = L"F20"; + keyboardLayoutMap[VK_F21] = L"F21"; + keyboardLayoutMap[VK_F22] = L"F22"; + keyboardLayoutMap[VK_F23] = L"F23"; + keyboardLayoutMap[VK_F24] = L"F24"; + keyboardLayoutMap[VK_NUMLOCK] = L"Num Lock"; + keyboardLayoutMap[VK_SCROLL] = L"Scroll Lock"; + keyboardLayoutMap[VK_LSHIFT] = L"LShift"; + keyboardLayoutMap[VK_RSHIFT] = L"RShift"; + keyboardLayoutMap[VK_LCONTROL] = L"LCtrl"; + keyboardLayoutMap[VK_RCONTROL] = L"RCtrl"; + keyboardLayoutMap[VK_LMENU] = L"LAlt"; + keyboardLayoutMap[VK_RMENU] = L"RAlt"; + keyboardLayoutMap[VK_BROWSER_BACK] = L"Browser Back"; + keyboardLayoutMap[VK_BROWSER_FORWARD] = L"Browser Forward"; + keyboardLayoutMap[VK_BROWSER_REFRESH] = L"Browser Refresh"; + keyboardLayoutMap[VK_BROWSER_STOP] = L"Browser Stop"; + keyboardLayoutMap[VK_BROWSER_SEARCH] = L"Browser Search"; + keyboardLayoutMap[VK_BROWSER_FAVORITES] = L"Browser Favorites"; + keyboardLayoutMap[VK_BROWSER_HOME] = L"Browser Start & Home"; + keyboardLayoutMap[VK_VOLUME_MUTE] = L"Volume Mute"; + keyboardLayoutMap[VK_VOLUME_DOWN] = L"Volume Down"; + keyboardLayoutMap[VK_VOLUME_UP] = L"Volume Up"; + keyboardLayoutMap[VK_MEDIA_NEXT_TRACK] = L"Next Track"; + keyboardLayoutMap[VK_MEDIA_PREV_TRACK] = L"Previous Track"; + keyboardLayoutMap[VK_MEDIA_STOP] = L"Stop Media"; + keyboardLayoutMap[VK_MEDIA_PLAY_PAUSE] = L"Play/Pause Media"; + keyboardLayoutMap[VK_LAUNCH_MAIL] = L"Start Mail"; + keyboardLayoutMap[VK_LAUNCH_MEDIA_SELECT] = L"Select Media"; + keyboardLayoutMap[VK_LAUNCH_APP1] = L"Start Application 1"; + keyboardLayoutMap[VK_LAUNCH_APP2] = L"Start Application 2"; + keyboardLayoutMap[VK_PACKET] = L"Packet"; + keyboardLayoutMap[VK_ATTN] = L"Attn"; + keyboardLayoutMap[VK_CRSEL] = L"CrSel"; + keyboardLayoutMap[VK_EXSEL] = L"ExSel"; + keyboardLayoutMap[VK_EREOF] = L"Erase EOF"; + keyboardLayoutMap[VK_PLAY] = L"Play"; + keyboardLayoutMap[VK_ZOOM] = L"Zoom"; + keyboardLayoutMap[VK_PA1] = L"PA1"; + keyboardLayoutMap[VK_OEM_CLEAR] = L"Clear"; + keyboardLayoutMap[0xFF] = L"Undefined"; + // To do: Add IME key names + } + + // Function to return the unicode string name of the key + std::wstring GetKeyName(DWORD key); +}; diff --git a/src/modules/keyboardmanager/common/Shortcut.cpp b/src/modules/keyboardmanager/common/Shortcut.cpp index f55cae1af3..3966edffa2 100644 --- a/src/modules/keyboardmanager/common/Shortcut.cpp +++ b/src/modules/keyboardmanager/common/Shortcut.cpp @@ -99,7 +99,6 @@ DWORD Shortcut::GetWinKey(const ModifierKey& input) const //return VK_LWIN by default return VK_LWIN; } - } } @@ -393,10 +392,10 @@ void Shortcut::ResetKey(const DWORD& input, const bool& isWinBoth) } // Function to return the string representation of the shortcut -winrt::hstring Shortcut::ToHstring() const +winrt::hstring Shortcut::ToHstring(LayoutMap& keyboardMap) { - std::vector keys = GetKeyVector(); - + std::vector keys = GetKeyVector(keyboardMap); + winrt::hstring output; for (auto& key : keys) { @@ -404,7 +403,7 @@ winrt::hstring Shortcut::ToHstring() const } if (keys.size() > 1) { - return winrt::hstring(output.c_str(), output.size() - 1); + return winrt::hstring(output.c_str(), output.size() - 1); } else { @@ -412,28 +411,28 @@ winrt::hstring Shortcut::ToHstring() const } } -std::vector Shortcut::GetKeyVector() const +std::vector Shortcut::GetKeyVector(LayoutMap& keyboardMap) { std::vector keys; if (winKey != ModifierKey::Disabled) { - keys.push_back(ModifierKeyNameWithSide(winKey, L"Win")); + keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetWinKey(ModifierKey::Left)).c_str())); } if (ctrlKey != ModifierKey::Disabled) { - keys.push_back(ModifierKeyNameWithSide(ctrlKey, L"Ctrl")); + keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetCtrlKey()).c_str())); } if (altKey != ModifierKey::Disabled) { - keys.push_back(ModifierKeyNameWithSide(altKey, L"Alt")); + keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetAltKey()).c_str())); } if (shiftKey != ModifierKey::Disabled) { - keys.push_back(ModifierKeyNameWithSide(shiftKey, L"Shift")); + keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(GetShiftKey()).c_str())); } if (actionKey != NULL) { - keys.push_back(winrt::to_hstring((unsigned int)actionKey)); + keys.push_back(winrt::to_hstring(keyboardMap.GetKeyName(actionKey).c_str())); } return keys; } @@ -710,101 +709,3 @@ int Shortcut::GetCommonModifiersCount(const Shortcut& input) const return commonElements; } - -// Function to return the name of the key with L or R prefix depending on the first argument. Second argument should be the name of the key without any prefix (ex: Win, Ctrl) -winrt::hstring Shortcut::ModifierKeyNameWithSide(const ModifierKey& key, const std::wstring& keyName) const -{ - if (key == ModifierKey::Left) - { - return winrt::to_hstring(L"L") + winrt::to_hstring(keyName.c_str()); - } - else if (key == ModifierKey::Right) - { - return winrt::to_hstring(L"R") + winrt::to_hstring(keyName.c_str()); - } - else if (key == ModifierKey::Both) - { - return winrt::to_hstring(keyName.c_str()); - } - - return winrt::hstring(); -} - -// Function to return the virtual key code from the name of the key -DWORD Shortcut::DecodeKey(const std::wstring& keyName) -{ - if (keyName == L"LWin") - { - return VK_LWIN; - } - else if (keyName == L"RWin") - { - return VK_RWIN; - } - else if (keyName == L"LCtrl") - { - return VK_LCONTROL; - } - else if (keyName == L"RCtrl") - { - return VK_RCONTROL; - } - else if (keyName == L"Ctrl") - { - return VK_CONTROL; - } - else if (keyName == L"LAlt") - { - return VK_LMENU; - } - else if (keyName == L"RAlt") - { - return VK_RMENU; - } - else if (keyName == L"Alt") - { - return VK_MENU; - } - else if (keyName == L"LShift") - { - return VK_LSHIFT; - } - else if (keyName == L"RShift") - { - return VK_RSHIFT; - } - else if (keyName == L"Shift") - { - return VK_SHIFT; - } - else - { - return std::stoi(keyName); - } -} - -// Function to create a shortcut object from its string representation -Shortcut Shortcut::CreateShortcut(const std::vector& keys) -{ - Shortcut newShortcut; - for (int i = 0; i < keys.size(); i++) - { - if (keys[i] == L"Win") - { - newShortcut.SetKey(NULL, true); - } - else - { - DWORD keyCode = DecodeKey(keys[i].c_str()); - newShortcut.SetKey(keyCode); - } - } - - return newShortcut; -} - -Shortcut Shortcut::CreateShortcut(const winrt::hstring& input) -{ - std::vector shortcut = splitwstring(input.c_str(), L' '); - return CreateShortcut(std::vector(shortcut.begin(), shortcut.end())); -} \ No newline at end of file diff --git a/src/modules/keyboardmanager/common/Shortcut.h b/src/modules/keyboardmanager/common/Shortcut.h index d1284dee13..304e5d0154 100644 --- a/src/modules/keyboardmanager/common/Shortcut.h +++ b/src/modules/keyboardmanager/common/Shortcut.h @@ -1,5 +1,6 @@ #pragma once #include "Helpers.h" +#include "LayoutMap.h" #include // Enum type to store different states of the win key @@ -20,10 +21,8 @@ private: ModifierKey shiftKey; DWORD actionKey; - // Function to return the name of the key with L or R prefix depending on the first argument. Second argument should be the name of the key without any prefix (ex: Win, Ctrl) - winrt::hstring ModifierKeyNameWithSide(const ModifierKey& key, const std::wstring& keyName) const; - public: + // By default create an empty shortcut Shortcut() : winKey(ModifierKey::Disabled), ctrlKey(ModifierKey::Disabled), altKey(ModifierKey::Disabled), shiftKey(ModifierKey::Disabled), actionKey(NULL) @@ -138,10 +137,10 @@ public: void ResetKey(const DWORD& input, const bool& isWinBoth = false); // Function to return the string representation of the shortcut - winrt::hstring ToHstring() const; + winrt::hstring ToHstring(LayoutMap& keyboardMap); // Function to return a vector of hstring for each key, in the same order as ToHstring() - std::vector GetKeyVector() const; + std::vector GetKeyVector(LayoutMap& keyboardMap); // Function to check if all the modifiers in the shortcut have been pressed down bool CheckModifiersKeyboardState() const; @@ -151,13 +150,4 @@ public: // Function to get the number of modifiers that are common between the current shortcut and the shortcut in the argument int GetCommonModifiersCount(const Shortcut& input) const; - - // Function to return the virtual key code from the name of the key - static DWORD DecodeKey(const std::wstring& keyName); - - // Function to create a shortcut object from its string vector representation - static Shortcut CreateShortcut(const std::vector& keys); - - // Function to create a shortcut object from its string representation - static Shortcut CreateShortcut(const winrt::hstring& input); }; diff --git a/src/modules/keyboardmanager/dll/dllmain.cpp b/src/modules/keyboardmanager/dll/dllmain.cpp index fb464b5998..63b12c9097 100644 --- a/src/modules/keyboardmanager/dll/dllmain.cpp +++ b/src/modules/keyboardmanager/dll/dllmain.cpp @@ -59,9 +59,6 @@ private: // Variable which stores all the state information to be shared between the UI and back-end KeyboardManagerState keyboardManagerState; - // Vector to store the detected shortcut in the detect shortcut UI. Acts as a shortcut buffer while detecting the shortcuts in the UI. - std::vector detectedShortcutKeys; - public: // Constructor KeyboardManager() diff --git a/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp b/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp index 5e1db893f1..833e17126d 100644 --- a/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp +++ b/src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp @@ -130,6 +130,21 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan // Message to display success/failure of saving settings. TextBlock settingsMessage; + // Store handle of edit keyboard window + SingleKeyRemapControl::EditKeyboardWindowHandle = _hWndEditKeyboardWindow; + // Store keyboard manager state + SingleKeyRemapControl::keyboardManagerState = &keyboardManagerState; + // Clear the single key remap buffer + SingleKeyRemapControl::singleKeyRemapBuffer.clear(); + + // Load existing remaps into UI + std::unique_lock lock(keyboardManagerState.singleKeyReMap_mutex); + for (const auto& it : keyboardManagerState.singleKeyReMap) + { + SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, it.first, it.second); + } + lock.unlock(); + // Main Header Apply button Button applyButton; applyButton.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() }); @@ -140,17 +155,13 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan // Clear existing Key Remaps keyboardManagerState.ClearSingleKeyRemaps(); - // Save the keys that are valid and report if any of them were invalid - for (unsigned int i = 1; i < keyRemapTable.Children().Size(); i++) + for (int i = 0; i < SingleKeyRemapControl::singleKeyRemapBuffer.size(); i++) { - StackPanel currentRow = keyRemapTable.Children().GetAt(i).as(); - hstring originalKeyString = currentRow.Children().GetAt(0).as().Children().GetAt(1).as().Text(); - hstring newKeyString = currentRow.Children().GetAt(1).as().Children().GetAt(1).as().Text(); - if (!originalKeyString.empty() && !newKeyString.empty()) - { - DWORD originalKey = std::stoi(originalKeyString.c_str()); - DWORD newKey = std::stoi(newKeyString.c_str()); + DWORD originalKey = SingleKeyRemapControl::singleKeyRemapBuffer[i][0]; + DWORD newKey = SingleKeyRemapControl::singleKeyRemapBuffer[i][1]; + if (originalKey != NULL && newKey != NULL) + { bool result = keyboardManagerState.AddSingleKeyRemap(originalKey, newKey); if (!result) { @@ -180,19 +191,6 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan header.Children().Append(applyButton); header.Children().Append(settingsMessage); - // Store handle of edit keyboard window - SingleKeyRemapControl::EditKeyboardWindowHandle = _hWndEditKeyboardWindow; - // Store keyboard manager state - SingleKeyRemapControl::keyboardManagerState = &keyboardManagerState; - - // Load existing remaps into UI - std::unique_lock lock(keyboardManagerState.singleKeyReMap_mutex); - for (const auto& it : keyboardManagerState.singleKeyReMap) - { - SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, it.first, it.second); - } - lock.unlock(); - // Add remap key button Windows::UI::Xaml::Controls::Button addRemapKey; addRemapKey.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() }); diff --git a/src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp b/src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp index 22236800b3..a12f0c52e8 100644 --- a/src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp +++ b/src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp @@ -121,6 +121,21 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa // Message to display success/failure of saving settings. TextBlock settingsMessage; + // Store handle of edit shortcuts window + ShortcutControl::EditShortcutsWindowHandle = _hWndEditShortcutsWindow; + // Store keyboard manager state + ShortcutControl::keyboardManagerState = &keyboardManagerState; + // Clear the shortcut remap buffer + ShortcutControl::shortcutRemapBuffer.clear(); + + // Load existing shortcuts into UI + std::unique_lock lock(keyboardManagerState.osLevelShortcutReMap_mutex); + for (const auto& it : keyboardManagerState.osLevelShortcutReMap) + { + ShortcutControl::AddNewShortcutControlRow(shortcutTable, it.first, it.second.targetShortcut); + } + lock.unlock(); + // Apply button Button applyButton; applyButton.Content(winrt::box_value(winrt::to_hstring("Apply"))); @@ -130,26 +145,15 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa keyboardManagerState.ClearOSLevelShortcuts(); // Save the shortcuts that are valid and report if any of them were invalid - for (unsigned int i = 1; i < shortcutTable.Children().Size(); i++) + for (int i = 0; i < ShortcutControl::shortcutRemapBuffer.size(); i++) { - StackPanel currentRow = shortcutTable.Children().GetAt(i).as(); - hstring originalShortcutText = currentRow.Children().GetAt(0).as().Children().GetAt(1).as().Text(); - hstring newShortcutText = currentRow.Children().GetAt(1).as().Children().GetAt(1).as().Text(); - if (!originalShortcutText.empty() && !newShortcutText.empty()) - { - Shortcut originalShortcut = Shortcut::CreateShortcut(originalShortcutText); - Shortcut newShortcut = Shortcut::CreateShortcut(newShortcutText); + Shortcut originalShortcut = ShortcutControl::shortcutRemapBuffer[i][0]; + Shortcut newShortcut = ShortcutControl::shortcutRemapBuffer[i][1]; - // Shortcut should be valid - if (originalShortcut.IsValidShortcut() && originalShortcut.IsValidShortcut()) - { - bool result = keyboardManagerState.AddOSLevelShortcut(originalShortcut, newShortcut); - if (!result) - { - isSuccess = false; - } - } - else + if (originalShortcut.IsValidShortcut() && originalShortcut.IsValidShortcut()) + { + bool result = keyboardManagerState.AddOSLevelShortcut(originalShortcut, newShortcut); + if (!result) { isSuccess = false; } @@ -177,19 +181,6 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa header.Children().Append(applyButton); header.Children().Append(settingsMessage); - // Store handle of edit shortcuts window - ShortcutControl::EditShortcutsWindowHandle = _hWndEditShortcutsWindow; - // Store keyboard manager state - ShortcutControl::keyboardManagerState = &keyboardManagerState; - - // Load existing shortcuts into UI - std::unique_lock lock(keyboardManagerState.osLevelShortcutReMap_mutex); - for (const auto& it : keyboardManagerState.osLevelShortcutReMap) - { - ShortcutControl::AddNewShortcutControlRow(shortcutTable, it.first, it.second.targetShortcut); - } - lock.unlock(); - // Add shortcut button Windows::UI::Xaml::Controls::Button addShortcut; FontIcon plusSymbol; diff --git a/src/modules/keyboardmanager/ui/EditShortcutsWindow.h b/src/modules/keyboardmanager/ui/EditShortcutsWindow.h index 369aad8a54..65fbd06416 100644 --- a/src/modules/keyboardmanager/ui/EditShortcutsWindow.h +++ b/src/modules/keyboardmanager/ui/EditShortcutsWindow.h @@ -1,5 +1,6 @@ #pragma once #include "keyboardmanager/common/KeyboardManagerState.h" +#include "keyboardmanager/common/Shortcut.h" #include "keyboardmanager/common/Helpers.h" // Function to create the Edit Shortcuts Window diff --git a/src/modules/keyboardmanager/ui/ShortcutControl.cpp b/src/modules/keyboardmanager/ui/ShortcutControl.cpp index 78b72e9a51..a8df1ef9ac 100644 --- a/src/modules/keyboardmanager/ui/ShortcutControl.cpp +++ b/src/modules/keyboardmanager/ui/ShortcutControl.cpp @@ -4,9 +4,11 @@ //Both static members are initialized to null HWND ShortcutControl::EditShortcutsWindowHandle = nullptr; KeyboardManagerState* ShortcutControl::keyboardManagerState = nullptr; +// Initialized as new vector +std::vector> ShortcutControl::shortcutRemapBuffer; // Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values. -void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, const Shortcut& originalKeys, const Shortcut& newKeys) +void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, Shortcut originalKeys, Shortcut newKeys) { // Parent element for the row Windows::UI::Xaml::Controls::StackPanel tableRow; @@ -15,18 +17,24 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, const Shortcu tableRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal); // ShortcutControl for the original shortcut - ShortcutControl originalSC; + ShortcutControl originalSC(shortcutRemapBuffer.size(), 0); tableRow.Children().Append(originalSC.getShortcutControl()); // ShortcutControl for the new shortcut - ShortcutControl newSC; + ShortcutControl newSC(shortcutRemapBuffer.size(), 1); tableRow.Children().Append(newSC.getShortcutControl()); // Set the shortcut text if the two vectors are not empty (i.e. default args) if (!originalKeys.IsEmpty() && !newKeys.IsEmpty()) { - originalSC.shortcutText.Text(originalKeys.ToHstring()); - newSC.shortcutText.Text(newKeys.ToHstring()); + shortcutRemapBuffer.push_back(std::vector{ originalKeys, newKeys }); + originalSC.shortcutText.Text(originalKeys.ToHstring(keyboardManagerState->keyboardMap)); + newSC.shortcutText.Text(newKeys.ToHstring(keyboardManagerState->keyboardMap)); + } + else + { + // Initialize both shortcuts as empty shortcuts + shortcutRemapBuffer.push_back(std::vector{ Shortcut(), Shortcut() }); } // Delete row button @@ -40,6 +48,8 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, const Shortcu uint32_t index; parent.Children().IndexOf(currentRow, index); parent.Children().RemoveAt(index); + // delete the row from the buffer. Since first child of the stackpanel is the header, the effective index starts from 1 + shortcutRemapBuffer.erase(shortcutRemapBuffer.begin() + (index - 1)); }); tableRow.Children().Append(deleteShortcut); parent.Children().Append(tableRow); @@ -52,7 +62,7 @@ StackPanel ShortcutControl::getShortcutControl() } // Function to create the detect shortcut UI window -void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState) +void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector>& shortcutRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex) { // ContentDialog for detecting shortcuts. This is the parent UI element. ContentDialog detectShortcutBox; @@ -70,10 +80,15 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam TextBlock linkedShortcutText = getSiblingElement(sender).as(); // OK button - detectShortcutBox.PrimaryButtonClick([=, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) { + detectShortcutBox.PrimaryButtonClick([=, &shortcutRemapBuffer, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) { // Save the detected shortcut in the linked text block Shortcut detectedShortcutKeys = keyboardManagerState.GetDetectedShortcut(); - linkedShortcutText.Text(detectedShortcutKeys.ToHstring()); + + if (!detectedShortcutKeys.IsEmpty()) + { + shortcutRemapBuffer[rowIndex][colIndex] = detectedShortcutKeys; + linkedShortcutText.Text(detectedShortcutKeys.ToHstring(keyboardManagerState.keyboardMap)); + } // Reset the keyboard manager UI state keyboardManagerState.ResetUIState(); diff --git a/src/modules/keyboardmanager/ui/ShortcutControl.h b/src/modules/keyboardmanager/ui/ShortcutControl.h index a271c916b4..66e274039b 100644 --- a/src/modules/keyboardmanager/ui/ShortcutControl.h +++ b/src/modules/keyboardmanager/ui/ShortcutControl.h @@ -20,14 +20,16 @@ public: static HWND EditShortcutsWindowHandle; // Pointer to the keyboard manager state static KeyboardManagerState* keyboardManagerState; + // Stores the current list of remappings + static std::vector> shortcutRemapBuffer; - ShortcutControl() + ShortcutControl(const int& rowIndex, const int& colIndex) { typeShortcut.Content(winrt::box_value(winrt::to_hstring("Type Shortcut"))); - typeShortcut.Click([&](IInspectable const& sender, RoutedEventArgs const&) { + typeShortcut.Click([&, rowIndex, colIndex](IInspectable const& sender, RoutedEventArgs const&) { keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectShortcutWindowActivated, EditShortcutsWindowHandle); // Using the XamlRoot of the typeShortcut to get the root of the XAML host - createDetectShortcutWindow(sender, sender.as