Display Unicode character for keys in HotkeySettingsControl (#2249)

* Fix HotkeyControl virtual key display

* A new interop project was setup to provide wrappers for C# projects
  that want to access functionality in the common project.

* Add assembly info

* Remove WIN32 configurations
This commit is contained in:
Tomas Agustin Raies
2020-04-20 21:01:21 -07:00
committed by GitHub
parent d45c4740ad
commit 93752fb6cb
31 changed files with 868 additions and 350 deletions

View File

@@ -2,6 +2,8 @@
#include "Helpers.h"
#include <sstream>
using namespace winrt::Windows::Foundation;
namespace KeyboardManagerHelper
{
// Function to split a wstring based on a delimiter and return a vector of split strings
@@ -14,12 +16,12 @@ namespace KeyboardManagerHelper
{
splittedStrings.push_back(item);
}
return splittedStrings;
}
// Function to return the next sibling element for an element under a stack panel
winrt::Windows::Foundation::IInspectable getSiblingElement(winrt::Windows::Foundation::IInspectable const& element)
IInspectable getSiblingElement(IInspectable const& element)
{
FrameworkElement frameworkElement = element.as<FrameworkElement>();
StackPanel parentElement = frameworkElement.Parent().as<StackPanel>();
@@ -28,7 +30,7 @@ namespace KeyboardManagerHelper
parentElement.Children().IndexOf(frameworkElement, index);
return parentElement.Children().GetAt(index + 1);
}
// Function to check if the key is a modifier key
bool IsModifierKey(DWORD key)
{
@@ -75,4 +77,14 @@ namespace KeyboardManagerHelper
return false;
}
}
Collections::IVector<IInspectable> ToBoxValue(const std::vector<std::wstring>& list)
{
Collections::IVector<IInspectable> boxList = single_threaded_vector<IInspectable>();
for (auto& val : list)
{
boxList.Append(winrt::box_value(val));
}
return boxList;
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <vector>
#include <winrt/Windows.System.h>
#include <winrt/Windows.Foundation.h>
namespace KeyboardManagerHelper
{
@@ -56,4 +57,7 @@ namespace KeyboardManagerHelper
// Function to return if the key is an extended key which requires the use of the extended key flag
bool isExtendedKey(DWORD key);
}
// Function to return the list of key name in the order for the drop down based on the key codes
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable> ToBoxValue(const std::vector<std::wstring>& list);
}

View File

@@ -90,7 +90,6 @@
<ClCompile Include="Helpers.cpp" />
<ClCompile Include="KeyboardManagerState.cpp" />
<ClCompile Include="KeyDelay.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>
@@ -103,7 +102,6 @@
<ClInclude Include="KeyboardManagerConstants.h" />
<ClInclude Include="KeyboardManagerState.h" />
<ClInclude Include="KeyDelay.h" />
<ClInclude Include="LayoutMap.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="RemapShortcut.h" />
<ClInclude Include="Shortcut.h" />

View File

@@ -24,9 +24,6 @@
<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>
@@ -47,9 +44,6 @@
<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

@@ -1,6 +1,6 @@
#pragma once
#include "Helpers.h"
#include "LayoutMap.h"
#include "..\common\keyboard_layout.h"
#include "Shortcut.h"
#include "RemapShortcut.h"
#include "KeyDelay.h"

View File

@@ -1,276 +0,0 @@
#include "pch.h"
#include "LayoutMap.h"
// Function to return the unicode string name of the key
std::wstring LayoutMap::GetKeyName(DWORD key)
{
std::wstring result = L"Undefined";
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
UpdateLayout();
auto it = keyboardLayoutMap.find(key);
if (it != keyboardLayoutMap.end())
{
result = it->second;
}
return result;
}
// Update Keyboard layout according to input locale identifier
void LayoutMap::UpdateLayout()
{
// Get keyboard layout for current thread
HKL layout = GetKeyboardLayout(0);
if (layout == previousLayout)
{
return;
}
previousLayout = layout;
if (!isKeyCodeListGenerated)
{
unicodeKeys.clear();
unknownKeys.clear();
}
unsigned char* btKeys = new unsigned char[256]{ 0 };
GetKeyboardState(btKeys);
// Iterate over all the virtual key codes. virtual key 0 is not used
for (int i = 1; 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;
if (!isKeyCodeListGenerated)
{
unicodeKeys[i] = szBuffer;
}
}
else
{
// Store the virtual key code as string
std::wstring vk = L"VK ";
vk += std::to_wstring(i);
keyboardLayoutMap[i] = vk;
if (!isKeyCodeListGenerated)
{
unknownKeys[i] = vk;
}
}
}
delete[] btKeys;
// 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 list of key codes in the order for the drop down. It creates it if it doesn't exist
std::vector<DWORD> LayoutMap::GetKeyCodeList(const bool isShortcut)
{
std::lock_guard<std::mutex> lock(keyboardLayoutMap_mutex);
UpdateLayout();
std::vector<DWORD> keyCodes;
if (!isKeyCodeListGenerated)
{
// Add modifier keys
keyCodes.push_back(VK_LWIN);
keyCodes.push_back(VK_RWIN);
keyCodes.push_back(VK_CONTROL);
keyCodes.push_back(VK_LCONTROL);
keyCodes.push_back(VK_RCONTROL);
keyCodes.push_back(VK_MENU);
keyCodes.push_back(VK_LMENU);
keyCodes.push_back(VK_RMENU);
keyCodes.push_back(VK_SHIFT);
keyCodes.push_back(VK_LSHIFT);
keyCodes.push_back(VK_RSHIFT);
// Add character keys
for (auto& it : unicodeKeys)
{
// If it was not renamed with a special name
if (it.second == keyboardLayoutMap[it.first])
{
keyCodes.push_back(it.first);
}
}
// Add all other special keys
for (int i = 1; i < 256; i++)
{
// If it is not already been added (i.e. it was either a modifier or had a unicode representation)
if (std::find(keyCodes.begin(), keyCodes.end(), i) == keyCodes.end())
{
// If it is any other key but it is not named as VK #
auto it = unknownKeys.find(i);
if (it == unknownKeys.end())
{
keyCodes.push_back(i);
}
else if (unknownKeys[i] != keyboardLayoutMap[i])
{
keyCodes.push_back(i);
}
}
}
// Add unknown keys
for (auto& it : unknownKeys)
{
// If it was not renamed with a special name
if (it.second == keyboardLayoutMap[it.first])
{
keyCodes.push_back(it.first);
}
}
keyCodeList = keyCodes;
isKeyCodeListGenerated = true;
}
else
{
keyCodes = keyCodeList;
}
// If it is a key list for the shortcut control then we add a "None" key at the start
if (isShortcut)
{
keyCodes.insert(keyCodes.begin(), 0);
}
return keyCodes;
}
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> LayoutMap::GetKeyNameList(const bool isShortcut)
{
std::unique_lock<std::mutex> lock(keyboardLayoutMap_mutex);
UpdateLayout();
lock.unlock();
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> keyNames = single_threaded_vector<Windows::Foundation::IInspectable>();
std::vector<DWORD> keyCodes = GetKeyCodeList(isShortcut);
lock.lock();
// If it is a key list for the shortcut control then we add a "None" key at the start
if (isShortcut)
{
keyNames.Append(winrt::box_value(L"None"));
for (int i = 1; i < keyCodes.size(); i++)
{
keyNames.Append(winrt::box_value(keyboardLayoutMap[keyCodes[i]].c_str()));
}
}
else
{
for (int i = 0; i < keyCodes.size(); i++)
{
keyNames.Append(winrt::box_value(keyboardLayoutMap[keyCodes[i]].c_str()));
}
}
return keyNames;
}

View File

@@ -1,51 +0,0 @@
#pragma once
#include <interface/lowlevel_keyboard_event_data.h>
#include <string>
#include <map>
#include <mutex>
#include <windows.h>
using namespace winrt;
// Wrapper class to handle keyboard layout
class LayoutMap
{
private:
// Stores mappings for all the virtual key codes to the name of the key
std::mutex keyboardLayoutMap_mutex;
// Stores the previous layout
HKL previousLayout = 0;
// Stores the keys which have a unicode representation
std::map<DWORD, std::wstring> unicodeKeys;
// Stores the keys which do not have a name
std::map<DWORD, std::wstring> unknownKeys;
// Stores true if the fixed ordering key code list has already been set
bool isKeyCodeListGenerated = false;
// Stores a fixed order key code list for the drop down menus. It is kept fixed to change in ordering due to languages
std::vector<DWORD> keyCodeList;
public:
std::map<DWORD, std::wstring> keyboardLayoutMap;
// Update Keyboard layout according to input locale identifier
void UpdateLayout();
LayoutMap()
{
UpdateLayout();
}
// Function to return the unicode string name of the key
std::wstring GetKeyName(DWORD key);
// Function to return the list of key codes in the order for the drop down. It creates it if it doesn't exist
std::vector<DWORD> GetKeyCodeList(const bool isShortcut = false);
// Function to return the list of key name in the order for the drop down based on the key codes
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> GetKeyNameList(const bool isShortcut = false);
};

View File

@@ -1,7 +1,7 @@
#pragma once
#include "Helpers.h"
#include "LayoutMap.h"
#include "KeyboardManagerConstants.h"
#include "..\common\keyboard_layout.h"
#include <interface/lowlevel_keyboard_event_data.h>
// Enum type to store different states of the win key
@@ -155,9 +155,6 @@ public:
// Function to reset the state of a shortcut key based on the passed key code argument. Since there is no VK_WIN code, use the second argument for setting common win key.
void ResetKey(const DWORD& input, const bool& isWinBoth = false);
// Function to return the string representation of the shortcut
winrt::hstring ToHstring(LayoutMap& keyboardMap);
// Function to return the string representation of the shortcut in virtual key codes appended in a string by ";" separator.
winrt::hstring ToHstringVK() const;