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:
Arjun Balgovind
2020-04-18 16:12:26 -07:00
committed by GitHub
parent fc7103f56e
commit 0417b6266a
18 changed files with 686 additions and 247 deletions

View File

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

View File

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

View File

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

View File

@@ -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);
};

View File

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

View File

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