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
This commit is contained in:
Arjun Balgovind 2020-04-09 09:20:19 -07:00 committed by Tomas Agustin Raies
parent 6fbed4ad5c
commit e0ddaa74d0
16 changed files with 309 additions and 233 deletions

View file

@ -89,6 +89,7 @@
<ItemGroup>
<ClCompile Include="Helpers.cpp" />
<ClCompile Include="KeyboardManagerState.cpp" />
<ClCompile Include="LayoutMap.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
@ -99,6 +100,7 @@
<ItemGroup>
<ClInclude Include="Helpers.h" />
<ClInclude Include="KeyboardManagerState.h" />
<ClInclude Include="LayoutMap.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="RemapShortcut.h" />
<ClInclude Include="Shortcut.h" />

View file

@ -24,6 +24,9 @@
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LayoutMap.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Shortcut.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -41,6 +44,9 @@
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LayoutMap.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Shortcut.h">
<Filter>Header Files</Filter>
</ClInclude>

View file

@ -58,6 +58,10 @@ void KeyboardManagerState::ResetUIState()
detectedShortcut.Reset();
detectedShortcut_lock.unlock();
std::unique_lock<std::mutex> currentShortcut_lock(currentShortcut_mutex);
currentShortcut.Reset();
currentShortcut_lock.unlock();
// Reset all the single key remap UI stored variables.
std::unique_lock<std::mutex> currentSingleKeyUI_lock(currentSingleKeyUI_mutex);
currentSingleKeyUI = nullptr;
@ -158,8 +162,11 @@ void KeyboardManagerState::UpdateDetectShortcutUI()
std::unique_lock<std::mutex> detectedShortcut_lock(detectedShortcut_mutex);
std::vector<hstring> shortcut = detectedShortcut.GetKeyVector();
std::unique_lock<std::mutex> currentShortcut_lock(currentShortcut_mutex);
// Save the latest displayed shortcut
currentShortcut = detectedShortcut;
currentShortcut_lock.unlock();
std::vector<hstring> shortcut = detectedShortcut.GetKeyVector(keyboardMap);
detectedShortcut_lock.unlock();
@ -184,7 +191,7 @@ void KeyboardManagerState::UpdateDetectSingleKeyRemapUI()
}
std::unique_lock<std::mutex> 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<std::mutex> lock(currentShortcutUI_mutex);
std::vector<winrt::hstring> keys;
if (currentShortcutUI.Children().Size() > 0)
{
for (auto border : currentShortcutUI.Children())
{
auto keyString = border.as<Border>().Child().as<TextBlock>().Text();
keys.push_back(keyString);
}
}
lock.unlock();
return Shortcut::CreateShortcut(keys);
std::lock_guard<std::mutex> 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<std::mutex> lock(currentSingleKeyUI_mutex);
DWORD key = 0;
if (currentSingleKeyUI.Children().Size() > 0)
{
auto border = currentSingleKeyUI.Children().GetAt(0);
auto keyString = border.as<Border>().Child().as<TextBlock>().Text();
key = std::stoul(keyString.c_str());
}
lock.unlock();
return key;
std::lock_guard<std::mutex> 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.

View file

@ -1,5 +1,6 @@
#pragma once
#include "Helpers.h"
#include "LayoutMap.h"
#include "Shortcut.h"
#include "RemapShortcut.h"
#include <interface/lowlevel_keyboard_event_data.h>
@ -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<std::wstring, std::map<Shortcut, RemapShortcut>> appSpecificShortcutReMap;
std::mutex appSpecificShortcutReMap_mutex;
// Stores the keyboard layout
LayoutMap keyboardMap;
// Constructor
KeyboardManagerState();

View file

@ -0,0 +1,14 @@
#include "pch.h"
#include "LayoutMap.h"
std::wstring LayoutMap::GetKeyName(DWORD key)
{
std::wstring result = L"Undefined";
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
auto it = keyboardLayoutMap.find(key);
if (it != keyboardLayoutMap.end())
{
result = it->second;
}
return result;
}

View file

@ -0,0 +1,152 @@
#pragma once
#include <interface/lowlevel_keyboard_event_data.h>
#include <string>
#include <map>
#include <mutex>
// 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<DWORD, std::wstring> 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);
};

View file

@ -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<winrt::hstring> keys = GetKeyVector();
std::vector<winrt::hstring> 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<winrt::hstring> Shortcut::GetKeyVector() const
std::vector<winrt::hstring> Shortcut::GetKeyVector(LayoutMap& keyboardMap)
{
std::vector<winrt::hstring> 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<winrt::hstring>& 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<std::wstring> shortcut = splitwstring(input.c_str(), L' ');
return CreateShortcut(std::vector<winrt::hstring>(shortcut.begin(), shortcut.end()));
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "Helpers.h"
#include "LayoutMap.h"
#include <interface/lowlevel_keyboard_event_data.h>
// 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<winrt::hstring> GetKeyVector() const;
std::vector<winrt::hstring> 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<winrt::hstring>& keys);
// Function to create a shortcut object from its string representation
static Shortcut CreateShortcut(const winrt::hstring& input);
};

View file

@ -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<DWORD> detectedShortcutKeys;
public:
// Constructor
KeyboardManager()

View file

@ -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<std::mutex> 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<StackPanel>();
hstring originalKeyString = currentRow.Children().GetAt(0).as<StackPanel>().Children().GetAt(1).as<TextBlock>().Text();
hstring newKeyString = currentRow.Children().GetAt(1).as<StackPanel>().Children().GetAt(1).as<TextBlock>().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<std::mutex> 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() });

View file

@ -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<std::mutex> 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<StackPanel>();
hstring originalShortcutText = currentRow.Children().GetAt(0).as<StackPanel>().Children().GetAt(1).as<TextBlock>().Text();
hstring newShortcutText = currentRow.Children().GetAt(1).as<StackPanel>().Children().GetAt(1).as<TextBlock>().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<std::mutex> 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;

View file

@ -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

View file

@ -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<std::vector<Shortcut>> 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<Shortcut>{ 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(), 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<std::vector<Shortcut>>& 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<TextBlock>();
// 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();

View file

@ -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<std::vector<Shortcut>> 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<Button>().XamlRoot(), *keyboardManagerState);
createDetectShortcutWindow(sender, sender.as<Button>().XamlRoot(), shortcutRemapBuffer, *keyboardManagerState, rowIndex, colIndex);
});
shortcutControlLayout.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
@ -39,11 +41,11 @@ public:
}
// 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.
static void AddNewShortcutControlRow(StackPanel& parent, const Shortcut& originalKeys = Shortcut(), const Shortcut& newKeys = Shortcut());
static void AddNewShortcutControlRow(StackPanel& parent, Shortcut originalKeys = Shortcut(), Shortcut newKeys = Shortcut());
// Function to return the stack panel element of the ShortcutControl. This is the externally visible UI element which can be used to add it to other layouts
StackPanel getShortcutControl();
// Function to create the detect shortcut UI window
void createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState);
void createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex);
};

View file

@ -4,6 +4,8 @@
//Both static members are initialized to null
HWND SingleKeyRemapControl::EditKeyboardWindowHandle = nullptr;
KeyboardManagerState* SingleKeyRemapControl::keyboardManagerState = nullptr;
// Initialized as new vector
std::vector<std::vector<DWORD>> SingleKeyRemapControl::singleKeyRemapBuffer;
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, const DWORD& originalKey, const DWORD& newKey)
@ -15,18 +17,24 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, const D
tableRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
// SingleKeyRemapControl for the original key.
SingleKeyRemapControl originalRemapKeyControl;
SingleKeyRemapControl originalRemapKeyControl(singleKeyRemapBuffer.size(), 0);
tableRow.Children().Append(originalRemapKeyControl.getSingleKeyRemapControl());
// SingleKeyRemapControl for the new remap key.
SingleKeyRemapControl newRemapKeyControl;
SingleKeyRemapControl newRemapKeyControl(singleKeyRemapBuffer.size(), 1);
tableRow.Children().Append(newRemapKeyControl.getSingleKeyRemapControl());
// Set the key text if the two keys are not null (i.e. default args)
if (originalKey != NULL && newKey != NULL)
{
originalRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring((unsigned int)originalKey));
newRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring((unsigned int)newKey));
singleKeyRemapBuffer.push_back(std::vector<DWORD>{ originalKey, newKey });
originalRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring(keyboardManagerState->keyboardMap.GetKeyName(originalKey).c_str()));
newRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring(keyboardManagerState->keyboardMap.GetKeyName(newKey).c_str()));
}
else
{
// Initialize both keys to NULL
singleKeyRemapBuffer.push_back(std::vector<DWORD>{ NULL, NULL });
}
// Delete row button
@ -42,6 +50,8 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, const D
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
singleKeyRemapBuffer.erase(singleKeyRemapBuffer.begin() + (index - 1));
});
tableRow.Children().Append(deleteRemapKeys);
parent.Children().Append(tableRow);
@ -54,7 +64,7 @@ StackPanel SingleKeyRemapControl::getSingleKeyRemapControl()
}
// Function to create the detect remap key UI window
void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState)
void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex)
{
// ContentDialog for detecting remap key. This is the parent UI element.
ContentDialog detectRemapKeyBox;
@ -72,12 +82,14 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
TextBlock linkedRemapText = getSiblingElement(sender).as<TextBlock>();
// OK button
detectRemapKeyBox.PrimaryButtonClick([=, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
detectRemapKeyBox.PrimaryButtonClick([=, &singleKeyRemapBuffer, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
// Save the detected key in the linked text block
DWORD detectedKey = keyboardManagerState.GetDetectedSingleRemapKey();
if (detectedKey != NULL)
{
linkedRemapText.Text(winrt::to_hstring((unsigned int)detectedKey));
singleKeyRemapBuffer[rowIndex][colIndex] = detectedKey;
linkedRemapText.Text(winrt::to_hstring(keyboardManagerState.keyboardMap.GetKeyName(detectedKey).c_str()));
}
// Reset the keyboard manager UI state

View file

@ -18,16 +18,18 @@ public:
static HWND EditKeyboardWindowHandle;
// Pointer to the keyboard manager state
static KeyboardManagerState* keyboardManagerState;
// Stores the current list of remappings
static std::vector<std::vector<DWORD>> singleKeyRemapBuffer;
SingleKeyRemapControl()
SingleKeyRemapControl(const int& rowIndex, const int& colIndex)
{
typeKey.Content(winrt::box_value(winrt::to_hstring("Type Key")));
typeKey.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
typeKey.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
typeKey.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
typeKey.Click([&, rowIndex, colIndex](IInspectable const& sender, RoutedEventArgs const&) {
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated, EditKeyboardWindowHandle);
// Using the XamlRoot of the typeKey to get the root of the XAML host
createDetectKeyWindow(sender, sender.as<Button>().XamlRoot(), *keyboardManagerState);
createDetectKeyWindow(sender, sender.as<Button>().XamlRoot(), singleKeyRemapBuffer, *keyboardManagerState, rowIndex, colIndex);
});
singleKeyRemapControlLayout.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
@ -45,5 +47,5 @@ public:
StackPanel getSingleKeyRemapControl();
// Function to create the detect remap keys UI window
void createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState);
void createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex);
};