From 93752fb6cb68292110fc2d2d3da2f87bd0fee53d Mon Sep 17 00:00:00 2001 From: Tomas Agustin Raies Date: Mon, 20 Apr 2020 21:01:21 -0700 Subject: [PATCH] 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 --- PowerToys.sln | 14 + .../common-md-flag/common-md-flag.vcxproj | 101 +++ .../common-md-flag.vcxproj.filters | 39 ++ src/common/common-md-flag/framework.h | 3 + src/common/common-md-flag/pch.cpp | 5 + src/common/common-md-flag/pch.h | 13 + src/common/common.vcxproj | 3 + src/common/common.vcxproj.filters | 14 +- src/common/interop/Resource.h | 3 + src/common/interop/app.ico | Bin 0 -> 41395 bytes src/common/interop/app.rc | 61 ++ src/common/interop/interop.cpp | 4 + src/common/interop/interop.h | 40 ++ src/common/interop/interop.vcxproj | 150 +++++ src/common/interop/interop.vcxproj.filters | 49 ++ src/common/interop/pch.cpp | 5 + src/common/interop/pch.h | 12 + .../keyboard_layout.cpp} | 578 +++++++++--------- src/common/keyboard_layout.h | 20 + .../keyboard_layout_impl.h} | 103 ++-- ...Microsoft.PowerToys.Settings.UI.Lib.csproj | 4 + .../Utilities/Helper.cs | 7 + .../Controls/HotkeySettingsControl.xaml.cs | 2 +- .../keyboardmanager/common/Helpers.cpp | 20 +- src/modules/keyboardmanager/common/Helpers.h | 6 +- .../common/KeyboardManagerCommon.vcxproj | 2 - .../KeyboardManagerCommon.vcxproj.filters | 6 - .../common/KeyboardManagerState.h | 2 +- src/modules/keyboardmanager/common/Shortcut.h | 5 +- .../keyboardmanager/ui/KeyDropDownControl.cpp | 5 +- .../ui/SingleKeyRemapControl.cpp | 3 +- 31 files changed, 929 insertions(+), 350 deletions(-) create mode 100644 src/common/common-md-flag/common-md-flag.vcxproj create mode 100644 src/common/common-md-flag/common-md-flag.vcxproj.filters create mode 100644 src/common/common-md-flag/framework.h create mode 100644 src/common/common-md-flag/pch.cpp create mode 100644 src/common/common-md-flag/pch.h create mode 100644 src/common/interop/Resource.h create mode 100644 src/common/interop/app.ico create mode 100644 src/common/interop/app.rc create mode 100644 src/common/interop/interop.cpp create mode 100644 src/common/interop/interop.h create mode 100644 src/common/interop/interop.vcxproj create mode 100644 src/common/interop/interop.vcxproj.filters create mode 100644 src/common/interop/pch.cpp create mode 100644 src/common/interop/pch.h rename src/{modules/keyboardmanager/common/LayoutMap.cpp => common/keyboard_layout.cpp} (91%) create mode 100644 src/common/keyboard_layout.h rename src/{modules/keyboardmanager/common/LayoutMap.h => common/keyboard_layout_impl.h} (78%) diff --git a/PowerToys.sln b/PowerToys.sln index 0fe9d331db..584efa908b 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -209,6 +209,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Setting EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerToys.Settings.UnitTest", "src\core\Microsoft.PowerToys.Settings.UnitTest\Microsoft.PowerToys.Settings.UnitTest.csproj", "{A80355C2-780D-4245-BD80-25B8DE698EE3}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "interop", "src\common\interop\interop.vcxproj", "{F055103B-F80B-4D0C-BF48-057C55620033}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common-md-flag", "src\common\common-md-flag\common-md-flag.vcxproj", "{985B3F2F-CEED-4C0A-A249-69257E719145}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -393,6 +397,14 @@ Global {A80355C2-780D-4245-BD80-25B8DE698EE3}.Release|x64.ActiveCfg = Release|x64 {A80355C2-780D-4245-BD80-25B8DE698EE3}.Release|x64.Build.0 = Release|x64 {A80355C2-780D-4245-BD80-25B8DE698EE3}.Release|x64.Deploy.0 = Release|x64 + {F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64 + {F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.Build.0 = Debug|x64 + {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.ActiveCfg = Release|x64 + {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64 + {985B3F2F-CEED-4C0A-A249-69257E719145}.Debug|x64.ActiveCfg = Debug|x64 + {985B3F2F-CEED-4C0A-A249-69257E719145}.Debug|x64.Build.0 = Debug|x64 + {985B3F2F-CEED-4C0A-A249-69257E719145}.Release|x64.ActiveCfg = Release|x64 + {985B3F2F-CEED-4C0A-A249-69257E719145}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -446,6 +458,8 @@ Global {C073B057-B157-40F0-8678-1DCD119D841C} = {C3081D9A-1586-441A-B5F4-ED815B3719C1} {B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A} = {C3081D9A-1586-441A-B5F4-ED815B3719C1} {A80355C2-780D-4245-BD80-25B8DE698EE3} = {C3081D9A-1586-441A-B5F4-ED815B3719C1} + {F055103B-F80B-4D0C-BF48-057C55620033} = {1AFB6476-670D-4E80-A464-657E01DFF482} + {985B3F2F-CEED-4C0A-A249-69257E719145} = {1AFB6476-670D-4E80-A464-657E01DFF482} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/src/common/common-md-flag/common-md-flag.vcxproj b/src/common/common-md-flag/common-md-flag.vcxproj new file mode 100644 index 0000000000..ebd8bc1629 --- /dev/null +++ b/src/common/common-md-flag/common-md-flag.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {985B3F2F-CEED-4C0A-A249-69257E719145} + Win32Proj + commonmdflag + 10.0 + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + false + + + true + + + + Use + Level3 + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + pch.h + + + Windows + true + true + true + + + + + Use + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + pch.h + stdcpp17 + + + Windows + true + + + + + + + + + + + + Create + Create + + + + + + \ No newline at end of file diff --git a/src/common/common-md-flag/common-md-flag.vcxproj.filters b/src/common/common-md-flag/common-md-flag.vcxproj.filters new file mode 100644 index 0000000000..8cb6132a95 --- /dev/null +++ b/src/common/common-md-flag/common-md-flag.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/common/common-md-flag/framework.h b/src/common/common-md-flag/framework.h new file mode 100644 index 0000000000..880eb72076 --- /dev/null +++ b/src/common/common-md-flag/framework.h @@ -0,0 +1,3 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers diff --git a/src/common/common-md-flag/pch.cpp b/src/common/common-md-flag/pch.cpp new file mode 100644 index 0000000000..91c22df2a1 --- /dev/null +++ b/src/common/common-md-flag/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/src/common/common-md-flag/pch.h b/src/common/common-md-flag/pch.h new file mode 100644 index 0000000000..04ff4c23fb --- /dev/null +++ b/src/common/common-md-flag/pch.h @@ -0,0 +1,13 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +// add headers that you want to pre-compile here +#include "framework.h" + +#endif //PCH_H diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index eecc209872..230cb8dd7f 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -121,6 +121,8 @@ + + @@ -149,6 +151,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 20dedbc650..c58c72019d 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -99,6 +99,12 @@ Header Files + + Header Files + + + Header Files + @@ -159,5 +165,11 @@ Source Files + + Source Files + - + + + + \ No newline at end of file diff --git a/src/common/interop/Resource.h b/src/common/interop/Resource.h new file mode 100644 index 0000000000..d5ac7c42aa --- /dev/null +++ b/src/common/interop/Resource.h @@ -0,0 +1,3 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc diff --git a/src/common/interop/app.ico b/src/common/interop/app.ico new file mode 100644 index 0000000000000000000000000000000000000000..789d7ccbb56ed92f1bb005054ec7e67257ddc37e GIT binary patch literal 41395 zcmeHQZA=_R7=DjCkZTKK8e`L%_DrfaQ35q-NU0yk2`Okwv@x+7+O*QNL}I~`Y8$Mc zweceoTVpWz1KLD?5Tj6HjAC->RZTH5(3+Y^qR}Q*QIUg61#Btj%&kM`7H)6nj+0&P zne4DLH}A~6^UO0d@9xgBL=JKjcMi&?At%w>EL>Qq#oKdt>C$N+(Rua|At$Lyk0H7#>diEi}F0wek;+HU7|b|XXU)xB+Bzp4Xf+HR-)G) zs@#~fX!#;mY)(aa>1JM9q{b|Es@mJmiXcbB=8Zn;=)3uM7IEz^*;GQ*b!7464yF^i z>&qW&Ajxqo~ z`o$M|S6|Ksp*!JynDLQBBox`-#bTKXNNLW6@ zgkx${f)e9J7HU zW>BoNwY0UbHnH&K*Qp-nz06Nvr^+meah=M<;eY@TNCN~S6LgB(nf&r-v~=^*=c0n&Ojh75tz+RnK5HVPvXohh+3)UAs(fW-b|Sp*ELAr(aAhg;CWNC zNg-csQaH8gOTI~A>mQ?;HLt$xf4z2e-!~6*cy1{Dt+(p06<@t|uzZicMMS~oQ0<3D z0x!1grj?D(wFOt)E;k)Ed9+Tg3NEWIIN#a3e!Td!+uXBZlaG*-5o1m2`SF#ewPVG* z`nqqrRCRT#YNfyP4BvY&bah{6bzfHSM$0IhOhc`lceYNT^Phg?sL%8lI?Ns?&V`*c zRdBocy$a9gPIeW|Bs$T^;GR!b6_sshE;@YY_gp~UPvB*7Kl6N3QpB;1NN_*^2mk>f zpdrBaQ2Eo`hgtjKfdM$cIKcK+E@&TbtfT$t|Aou}RsOSm)?qt)eP5#e#_0u9G5^8-Gva`rFPQ&e|Jj)XdOjO*ANC*YKRsXU%zfB@ z$=iQ=KG;33I{(?dy?Xu8el`17kDuM+=zsLT5eMwf?|AwfwVkKM%WwB|v>)T&hy!-# zcRc-#+K%yWJT~HChjicv4%m(ZY5o2e-U9>zKp=e)5dSYJ-Z^~{vUkhl^=tHZCp?kH z`q>9+;D7)SxP}0;>rdL;uu&S+@th^rgWXn^{AFF=V`xmP6 zLQm8mZTksaRPj`m7xe&t;4gDP@IsYOs`8>9xo#d7zpIv~Dlh6m{oudM0l^DZKB>x! zdgQug{)_ZfpHctp{7*IRqI}>VjlUj`bctK)VsIXmk>B_FKdTq@^7|D0wuFay@!ess zi$&(x%>|#u+@X3Fb@P0QtXIgd%~cBlKUMB +using namespace System; + +//https://docs.microsoft.com/en-us/cpp/dotnet/how-to-wrap-native-class-for-use-by-csharp?view=vs-2019 +namespace interop +{ +public ref class LayoutMapManaged + { + public: + LayoutMapManaged() : + _map(new LayoutMap) {} + + ~LayoutMapManaged() + { + delete _map; + } + + String ^ GetKeyName(DWORD key) + { + return gcnew String(_map->GetKeyName(key).c_str()); + } + + void Updatelayout() + { + _map->UpdateLayout(); + } + + protected: + !LayoutMapManaged() + { + delete _map; + } + + private: + LayoutMap* _map; + }; +} + diff --git a/src/common/interop/interop.vcxproj b/src/common/interop/interop.vcxproj new file mode 100644 index 0000000000..ca7846aedb --- /dev/null +++ b/src/common/interop/interop.vcxproj @@ -0,0 +1,150 @@ + + + + + PowerToysInterop + Microsoft Corp. + Copyright (C) 2019 Microsoft Corp. + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {F055103B-F80B-4D0C-BF48-057C55620033} + v4.7.2 + ManagedCProj + interop + 10.0 + + + + DynamicLibrary + true + v142 + true + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + PowerToysInterop + + + PowerToysInterop + + + + Use + pch.h + Level3 + _DEBUG;%(PreprocessorDefinitions) + $(SolutionDir)src\common\interop;$(SolutionDir)src;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + false + stdcpp17 + + + %(AdditionalDependencies) + + + + + + + Use + pch.h + Level3 + NDEBUG;%(PreprocessorDefinitions) + $(SolutionDir)src\common\interop;$(SolutionDir)src;%(AdditionalIncludeDirectories) + MultiThreadedDLL + stdcpp17 + + + %(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + + + + {985b3f2f-ceed-4c0a-a249-69257e719145} + + + + + + \ No newline at end of file diff --git a/src/common/interop/interop.vcxproj.filters b/src/common/interop/interop.vcxproj.filters new file mode 100644 index 0000000000..00df378334 --- /dev/null +++ b/src/common/interop/interop.vcxproj.filters @@ -0,0 +1,49 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/src/common/interop/pch.cpp b/src/common/interop/pch.cpp new file mode 100644 index 0000000000..64b7eef6d6 --- /dev/null +++ b/src/common/interop/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/src/common/interop/pch.h b/src/common/interop/pch.h new file mode 100644 index 0000000000..9d715b0698 --- /dev/null +++ b/src/common/interop/pch.h @@ -0,0 +1,12 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +// add headers that you want to pre-compile here + +#endif //PCH_H diff --git a/src/modules/keyboardmanager/common/LayoutMap.cpp b/src/common/keyboard_layout.cpp similarity index 91% rename from src/modules/keyboardmanager/common/LayoutMap.cpp rename to src/common/keyboard_layout.cpp index 811fd9bec9..bf8c24d20d 100644 --- a/src/modules/keyboardmanager/common/LayoutMap.cpp +++ b/src/common/keyboard_layout.cpp @@ -1,276 +1,302 @@ -#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 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 LayoutMap::GetKeyCodeList(const bool isShortcut) -{ - std::lock_guard lock(keyboardLayoutMap_mutex); - UpdateLayout(); - std::vector 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 LayoutMap::GetKeyNameList(const bool isShortcut) -{ - std::unique_lock lock(keyboardLayoutMap_mutex); - UpdateLayout(); - lock.unlock(); - Windows::Foundation::Collections::IVector keyNames = single_threaded_vector(); - std::vector 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; -} +#include "pch.h" +#include "keyboard_layout_impl.h" + +LayoutMap::LayoutMap() : + impl(new LayoutMap::LayoutMapImpl()) +{ +} + +LayoutMap::~LayoutMap() +{ + delete impl; +} + +void LayoutMap::UpdateLayout() +{ + impl->UpdateLayout(); +} + +std::wstring LayoutMap::GetKeyName(DWORD key) +{ + return impl->GetKeyName(key); +} + +std::vector LayoutMap::GetKeyCodeList(const bool isShortcut) +{ + return impl->GetKeyCodeList(isShortcut); +} + +std::vector LayoutMap::GetKeyNameList(const bool isShortcut) +{ + return impl->GetKeyNameList(isShortcut); +} + +// Function to return the unicode string name of the key +std::wstring LayoutMap::LayoutMapImpl::GetKeyName(DWORD key) +{ + std::wstring result = L"Undefined"; + std::lock_guard 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::LayoutMapImpl::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 LayoutMap::LayoutMapImpl::GetKeyCodeList(const bool isShortcut) +{ + std::lock_guard lock(keyboardLayoutMap_mutex); + UpdateLayout(); + std::vector 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; +} + +std::vector LayoutMap::LayoutMapImpl::GetKeyNameList(const bool isShortcut) +{ + std::vector keyNames; + std::vector keyCodes = GetKeyCodeList(isShortcut); + // If it is a key list for the shortcut control then we add a "None" key at the start + if (isShortcut) + { + keyNames.push_back(L"None"); + for (int i = 1; i < keyCodes.size(); i++) + { + keyNames.push_back(GetKeyName(keyCodes[i])); + } + } + else + { + for (int i = 0; i < keyCodes.size(); i++) + { + keyNames.push_back(GetKeyName(keyCodes[i])); + } + } + + return keyNames; +} diff --git a/src/common/keyboard_layout.h b/src/common/keyboard_layout.h new file mode 100644 index 0000000000..58fe9f5280 --- /dev/null +++ b/src/common/keyboard_layout.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include +#include + +class LayoutMap +{ +public: + LayoutMap(); + ~LayoutMap(); + void UpdateLayout(); + std::wstring GetKeyName(DWORD key); + std::vector GetKeyCodeList(const bool isShortcut = false); + std::vector GetKeyNameList(const bool isShortcut = false); + +private: + class LayoutMapImpl; + LayoutMapImpl* impl; +}; diff --git a/src/modules/keyboardmanager/common/LayoutMap.h b/src/common/keyboard_layout_impl.h similarity index 78% rename from src/modules/keyboardmanager/common/LayoutMap.h rename to src/common/keyboard_layout_impl.h index 24c4833aa9..1138f1f7da 100644 --- a/src/modules/keyboardmanager/common/LayoutMap.h +++ b/src/common/keyboard_layout_impl.h @@ -1,51 +1,52 @@ -#pragma once -#include -#include -#include -#include -#include - -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 unicodeKeys; - - // Stores the keys which do not have a name - std::map 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 keyCodeList; - -public: - std::map 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 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 GetKeyNameList(const bool isShortcut = false); -}; +#pragma once +#include "keyboard_layout.h" +#include "..\modules\interface\lowlevel_keyboard_event_data.h" +#include +#include +#include +#include + +using namespace winrt; + +// Wrapper class to handle keyboard layout +class LayoutMap::LayoutMapImpl +{ +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 unicodeKeys; + + // Stores the keys which do not have a name + std::map 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 keyCodeList; + +public: + std::map keyboardLayoutMap; + + // Update Keyboard layout according to input locale identifier + void UpdateLayout(); + + LayoutMapImpl() + { + 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 GetKeyCodeList(const bool isShortcut); + + // Function to return the list of key name in the order for the drop down based on the key codes + std::vector GetKeyNameList(const bool isShortcut); +}; \ No newline at end of file diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/Microsoft.PowerToys.Settings.UI.Lib.csproj b/src/core/Microsoft.PowerToys.Settings.UI.Lib/Microsoft.PowerToys.Settings.UI.Lib.csproj index f876c6964d..a26da16475 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/Microsoft.PowerToys.Settings.UI.Lib.csproj +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/Microsoft.PowerToys.Settings.UI.Lib.csproj @@ -31,4 +31,8 @@ + + + + diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/Utilities/Helper.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/Utilities/Helper.cs index e9079dc4b8..273914b494 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/Utilities/Helper.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/Utilities/Helper.cs @@ -64,5 +64,12 @@ namespace Microsoft.PowerToys.Settings.UI.Lib.Utilities [DllImport("user32.dll")] private static extern bool AllowSetForegroundWindow(int dwProcessId); + + private static interop.LayoutMapManaged layoutMap = new interop.LayoutMapManaged(); + + public static string GetKeyName(uint key) + { + return layoutMap.GetKeyName(key); + } } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Controls/HotkeySettingsControl.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Controls/HotkeySettingsControl.xaml.cs index 7c796a60b4..4277644479 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Controls/HotkeySettingsControl.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Controls/HotkeySettingsControl.xaml.cs @@ -90,7 +90,7 @@ namespace Microsoft.PowerToys.Settings.UI.Controls settings.Shift = true; } - settings.Key = e.Key.ToString(); + settings.Key = Lib.Utilities.Helper.GetKeyName((uint)e.Key); // TODO: Check that e.OriginalKey is the ScanCode. It is not clear from docs. settings.Code = (int)e.OriginalKey; diff --git a/src/modules/keyboardmanager/common/Helpers.cpp b/src/modules/keyboardmanager/common/Helpers.cpp index 613f888a4d..118482e27a 100644 --- a/src/modules/keyboardmanager/common/Helpers.cpp +++ b/src/modules/keyboardmanager/common/Helpers.cpp @@ -2,6 +2,8 @@ #include "Helpers.h" #include +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(); StackPanel parentElement = frameworkElement.Parent().as(); @@ -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 ToBoxValue(const std::vector& list) + { + Collections::IVector boxList = single_threaded_vector(); + for (auto& val : list) + { + boxList.Append(winrt::box_value(val)); + } + + return boxList; + } } diff --git a/src/modules/keyboardmanager/common/Helpers.h b/src/modules/keyboardmanager/common/Helpers.h index 046a0d83c5..a7452dd63b 100644 --- a/src/modules/keyboardmanager/common/Helpers.h +++ b/src/modules/keyboardmanager/common/Helpers.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include 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 ToBoxValue(const std::vector& list); +} \ No newline at end of file diff --git a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj index 9575c769c9..4842156f7a 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj +++ b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj @@ -90,7 +90,6 @@ - Create Create @@ -103,7 +102,6 @@ - diff --git a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters index b7b3256953..25b1c95513 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters +++ b/src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj.filters @@ -24,9 +24,6 @@ Source Files - - Source Files - Source Files @@ -47,9 +44,6 @@ Header Files - - Header Files - Header Files diff --git a/src/modules/keyboardmanager/common/KeyboardManagerState.h b/src/modules/keyboardmanager/common/KeyboardManagerState.h index 53b0130927..cfb93d732f 100644 --- a/src/modules/keyboardmanager/common/KeyboardManagerState.h +++ b/src/modules/keyboardmanager/common/KeyboardManagerState.h @@ -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" diff --git a/src/modules/keyboardmanager/common/Shortcut.h b/src/modules/keyboardmanager/common/Shortcut.h index 0a72b8bb06..8cc9d9afa0 100644 --- a/src/modules/keyboardmanager/common/Shortcut.h +++ b/src/modules/keyboardmanager/common/Shortcut.h @@ -1,7 +1,7 @@ #pragma once #include "Helpers.h" -#include "LayoutMap.h" #include "KeyboardManagerConstants.h" +#include "..\common\keyboard_layout.h" #include // 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; diff --git a/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp b/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp index fca34d3db3..c290f877d2 100644 --- a/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp +++ b/src/modules/keyboardmanager/ui/KeyDropDownControl.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "KeyDropDownControl.h" +#include "keyboardmanager/common/Helpers.h" // Initialized to null KeyboardManagerState* KeyDropDownControl::keyboardManagerState = nullptr; @@ -12,7 +13,7 @@ void KeyDropDownControl::SetDefaultProperties(bool isShortcut) // Initialise layout attribute previousLayout = GetKeyboardLayout(0); keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut); - dropDown.ItemsSource(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut)); + dropDown.ItemsSource(KeyboardManagerHelper::ToBoxValue(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut))); // drop down open handler - to reload the items with the latest layout dropDown.DropDownOpened([&, isShortcut](winrt::Windows::Foundation::IInspectable const& sender, auto args) { ComboBox currentDropDown = sender.as(); @@ -30,7 +31,7 @@ void KeyDropDownControl::CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, if (previousLayout != layout) { keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut); - currentDropDown.ItemsSource(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut)); + currentDropDown.ItemsSource(KeyboardManagerHelper::ToBoxValue(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut))); previousLayout = layout; } } diff --git a/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp b/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp index 265fd819e8..dfbe46ebde 100644 --- a/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp +++ b/src/modules/keyboardmanager/ui/SingleKeyRemapControl.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "SingleKeyRemapControl.h" +#include "keyboardmanager/common/Helpers.h" //Both static members are initialized to null HWND SingleKeyRemapControl::EditKeyboardWindowHandle = nullptr; @@ -114,7 +115,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(winrt::Windows::Foundation::II { std::vector keyCodeList = keyboardManagerState.keyboardMap.GetKeyCodeList(); // Update the drop down list with the new language to ensure that the correct key is displayed - linkedRemapDropDown.ItemsSource(keyboardManagerState.keyboardMap.GetKeyNameList()); + linkedRemapDropDown.ItemsSource(KeyboardManagerHelper::ToBoxValue(keyboardManagerState.keyboardMap.GetKeyNameList())); auto it = std::find(keyCodeList.begin(), keyCodeList.end(), detectedKey); if (it != keyCodeList.end()) {