mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Add drop down key selection support to Keyboard Manager UI (dev/build-features) (#2140)
* Added combobox * Formatted and removed unused code * Added drop down support for Edit Keyboard window * Reordered the displayed key list * Add shortcut stack panels and drop downs linked to detect shortcut * Add more selected item logic * Added complete dropdown support for edit shortcuts window * Added Flyout warning for incorrect drop down input * Tweaked warnings * Removed MainWindow code * Changed SelectedValue toSelectedIndex * Removed unnecessary assignments * Added a warning for two dropdowns and the first one is changed to an action key * Added function comments in cpp file * Fixed some comments * Fixed all allocation and out of scope issues * Fix most issues except reloading shortcuts * Fixed issue while reloading shortcuts * Fixed type cast warnings * Changed delete to delete[] * tweaked
This commit is contained in:
@@ -27,6 +27,37 @@ IInspectable getSiblingElement(IInspectable const& element)
|
||||
return parentElement.Children().GetAt(index + 1);
|
||||
}
|
||||
|
||||
// Function to check if the key is a modifier key
|
||||
bool IsModifierKey(DWORD key)
|
||||
{
|
||||
return (GetKeyType(key) != KeyType::Action);
|
||||
}
|
||||
|
||||
// Function to get the type of the key
|
||||
KeyType GetKeyType(DWORD key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case VK_LWIN:
|
||||
case VK_RWIN:
|
||||
return KeyType::Win;
|
||||
case VK_CONTROL:
|
||||
case VK_LCONTROL:
|
||||
case VK_RCONTROL:
|
||||
return KeyType::Ctrl;
|
||||
case VK_MENU:
|
||||
case VK_LMENU:
|
||||
case VK_RMENU:
|
||||
return KeyType::Alt;
|
||||
case VK_SHIFT:
|
||||
case VK_LSHIFT:
|
||||
case VK_RSHIFT:
|
||||
return KeyType::Shift;
|
||||
default:
|
||||
return KeyType::Action;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to return if the key is an extended key which requires the use of the extended key flag
|
||||
bool isExtendedKey(DWORD key)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
#include <vector>
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
// Type to distinguish between keys
|
||||
enum class KeyType
|
||||
{
|
||||
Win,
|
||||
Ctrl,
|
||||
Alt,
|
||||
Shift,
|
||||
Action
|
||||
};
|
||||
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter);
|
||||
|
||||
@@ -33,5 +43,11 @@ std::vector<T> convertWStringVectorToIntegerVector(const std::vector<std::wstrin
|
||||
return typeVector;
|
||||
}
|
||||
|
||||
// Function to check if the key is a modifier key
|
||||
bool IsModifierKey(DWORD key);
|
||||
|
||||
// Function to get the type of the key
|
||||
KeyType GetKeyType(DWORD key);
|
||||
|
||||
// Function to return if the key is an extended key which requires the use of the extended key flag
|
||||
bool isExtendedKey(DWORD key);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#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";
|
||||
@@ -15,30 +16,41 @@ std::wstring LayoutMap::GetKeyName(DWORD key)
|
||||
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) {
|
||||
if (layout == previousLayout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
previousLayout = layout;
|
||||
if (!isKeyCodeListGenerated)
|
||||
{
|
||||
unicodeKeys.clear();
|
||||
unknownKeys.clear();
|
||||
}
|
||||
|
||||
unsigned char btKeys[256] = { 0 };
|
||||
unsigned char* btKeys = new unsigned char[256]{ 0 };
|
||||
GetKeyboardState(btKeys);
|
||||
|
||||
// Iterate over all the virtual key codes
|
||||
for (int i = 0; i < 256; i++)
|
||||
// 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
|
||||
// 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
|
||||
{
|
||||
@@ -46,9 +58,15 @@ void LayoutMap::UpdateLayout()
|
||||
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";
|
||||
@@ -155,3 +173,104 @@ void LayoutMap::UpdateLayout()
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5,16 +5,33 @@
|
||||
#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::map<DWORD, std::wstring> keyboardLayoutMap;
|
||||
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();
|
||||
|
||||
@@ -26,4 +43,9 @@ public:
|
||||
// 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);
|
||||
};
|
||||
|
||||
@@ -391,26 +391,7 @@ void Shortcut::ResetKey(const DWORD& input, const bool& isWinBoth)
|
||||
}
|
||||
}
|
||||
|
||||
// Function to return the string representation of the shortcut
|
||||
winrt::hstring Shortcut::ToHstring(LayoutMap& keyboardMap)
|
||||
{
|
||||
std::vector<winrt::hstring> keys = GetKeyVector(keyboardMap);
|
||||
|
||||
winrt::hstring output;
|
||||
for (auto& key : keys)
|
||||
{
|
||||
output = output + key + winrt::to_hstring(L" ");
|
||||
}
|
||||
if (keys.size() > 1)
|
||||
{
|
||||
return winrt::hstring(output.c_str(), output.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to return a vector of hstring for each key in the display order
|
||||
std::vector<winrt::hstring> Shortcut::GetKeyVector(LayoutMap& keyboardMap) const
|
||||
{
|
||||
std::vector<winrt::hstring> keys;
|
||||
@@ -437,6 +418,43 @@ std::vector<winrt::hstring> Shortcut::GetKeyVector(LayoutMap& keyboardMap) const
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Function to return a vector of key codes in the display order
|
||||
std::vector<DWORD> Shortcut::GetKeyCodes()
|
||||
{
|
||||
std::vector<DWORD> keys;
|
||||
if (winKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(GetWinKey(ModifierKey::Left));
|
||||
}
|
||||
if (ctrlKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(GetCtrlKey());
|
||||
}
|
||||
if (altKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(GetAltKey());
|
||||
}
|
||||
if (shiftKey != ModifierKey::Disabled)
|
||||
{
|
||||
keys.push_back(GetShiftKey());
|
||||
}
|
||||
if (actionKey != NULL)
|
||||
{
|
||||
keys.push_back(actionKey);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Function to set a shortcut from a vector of key codes
|
||||
void Shortcut::SetKeyCodes(const std::vector<DWORD>& keys)
|
||||
{
|
||||
Reset();
|
||||
for (int i = 0; i < keys.size(); i++)
|
||||
{
|
||||
SetKey(keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if all the modifiers in the shortcut have been pressed down
|
||||
bool Shortcut::CheckModifiersKeyboardState() const
|
||||
{
|
||||
@@ -540,7 +558,7 @@ bool Shortcut::CheckModifiersKeyboardState() const
|
||||
bool Shortcut::IsKeyboardStateClearExceptShortcut() const
|
||||
{
|
||||
// Iterate through all the virtual key codes - 0xFF is set to key down because of the Num Lock
|
||||
for (int keyVal = 0; keyVal < 0xFF; keyVal++)
|
||||
for (int keyVal = 1; keyVal < 0xFF; keyVal++)
|
||||
{
|
||||
// Skip mouse buttons. Keeping this could cause a remapping to fail if a mouse button is also pressed at the same time
|
||||
if (keyVal == VK_LBUTTON || keyVal == VK_RBUTTON || keyVal == VK_MBUTTON || keyVal == VK_XBUTTON1 || keyVal == VK_XBUTTON2)
|
||||
|
||||
@@ -22,7 +22,6 @@ private:
|
||||
DWORD actionKey;
|
||||
|
||||
public:
|
||||
|
||||
// By default create an empty shortcut
|
||||
Shortcut() :
|
||||
winKey(ModifierKey::Disabled), ctrlKey(ModifierKey::Disabled), altKey(ModifierKey::Disabled), shiftKey(ModifierKey::Disabled), actionKey(NULL)
|
||||
@@ -136,12 +135,15 @@ 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 a vector of hstring for each key, in the same order as ToHstring()
|
||||
// Function to return a vector of hstring for each key in the display order
|
||||
std::vector<winrt::hstring> GetKeyVector(LayoutMap& keyboardMap) const;
|
||||
|
||||
// Function to return a vector of key codes in the display order
|
||||
std::vector<DWORD> GetKeyCodes();
|
||||
|
||||
// Function to set a shortcut from a vector of key codes
|
||||
void SetKeyCodes(const std::vector<DWORD>& keys);
|
||||
|
||||
// Function to check if all the modifiers in the shortcut have been pressed down
|
||||
bool CheckModifiersKeyboardState() const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user