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 0000000000..789d7ccbb5
Binary files /dev/null and b/src/common/interop/app.ico differ
diff --git a/src/common/interop/app.rc b/src/common/interop/app.rc
new file mode 100644
index 0000000000..eab43064f1
--- /dev/null
+++ b/src/common/interop/app.rc
@@ -0,0 +1,61 @@
+ÿþ/ / M i c r o s o f t V i s u a l C + + g e n e r a t e d r e s o u r c e s c r i p t .
+ / /
+ # i n c l u d e " r e s o u r c e . h "
+
+ # d e f i n e A P S T U D I O _ R E A D O N L Y _ S Y M B O L S
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+ # u n d e f A P S T U D I O _ R E A D O N L Y _ S Y M B O L S
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+ / / E n g l i s h ( U n i t e d S t a t e s ) r e s o u r c e s
+
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+ / /
+ / / I c o n
+ / /
+ / / I c o n p l a c e d f i r s t o r w i t h l o w e s t I D v a l u e b e c o m e s a p p l i c a t i o n i c o n
+ L A N G U A G E 9 , 1
+ 1 I C O N " a p p . i c o "
+
+ # i f d e f A P S T U D I O _ I N V O K E D
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+ / /
+ / / T E X T I N C L U D E
+ / /
+
+ 1 T E X T I N C L U D E
+ B E G I N
+ " r e s o u r c e . h \ 0 "
+ " \ 0 "
+ E N D
+
+ 2 T E X T I N C L U D E
+ B E G I N
+ " # i n c l u d e " " a f x r e s . h " " \ r \ n "
+ " \ 0 "
+ E N D
+
+ 3 T E X T I N C L U D E
+ B E G I N
+ " \ 0 "
+ E N D
+
+ # e n d i f / / A P S T U D I O _ I N V O K E D
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+
+
+
+ # i f n d e f A P S T U D I O _ I N V O K E D
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+ / /
+ / / G e n e r a t e d f r o m t h e T E X T I N C L U D E 3 r e s o u r c e .
+ / /
+
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+ # e n d i f / / n o t A P S T U D I O _ I N V O K E D
+
+
\ No newline at end of file
diff --git a/src/common/interop/interop.cpp b/src/common/interop/interop.cpp
new file mode 100644
index 0000000000..16c4ee80d8
--- /dev/null
+++ b/src/common/interop/interop.cpp
@@ -0,0 +1,4 @@
+#include "pch.h"
+
+#include "interop.h"
+
diff --git a/src/common/interop/interop.h b/src/common/interop/interop.h
new file mode 100644
index 0000000000..85f3812cec
--- /dev/null
+++ b/src/common/interop/interop.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include
+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