mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +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:
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "EditKeyboardWindow.h"
|
||||
#include "SingleKeyRemapControl.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
LRESULT CALLBACK EditKeyboardWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
@@ -15,7 +16,6 @@ std::mutex editKeyboardWindowMutex;
|
||||
// Function to create the Edit Keyboard Window
|
||||
void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
|
||||
{
|
||||
|
||||
// Window Registration
|
||||
const wchar_t szWindowClass[] = L"EditKeyboardWindow";
|
||||
if (!isEditKeyboardWindowRegistrationCompleted)
|
||||
@@ -104,7 +104,7 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
TextBlock keyRemapInfoHeader;
|
||||
keyRemapInfoHeader.Text(winrt::to_hstring("Select the key you want to remap, original key, and it's new output when pressed, the new key"));
|
||||
keyRemapInfoHeader.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
|
||||
keyRemapInfoHeader.Margin({ 0, 0, 0, 10 });
|
||||
keyRemapInfoHeader.Margin({ 10, 0, 0, 10 });
|
||||
|
||||
// Table to display the key remaps
|
||||
Windows::UI::Xaml::Controls::StackPanel keyRemapTable;
|
||||
@@ -143,14 +143,17 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
SingleKeyRemapControl::EditKeyboardWindowHandle = _hWndEditKeyboardWindow;
|
||||
// Store keyboard manager state
|
||||
SingleKeyRemapControl::keyboardManagerState = &keyboardManagerState;
|
||||
KeyDropDownControl::keyboardManagerState = &keyboardManagerState;
|
||||
// Clear the single key remap buffer
|
||||
SingleKeyRemapControl::singleKeyRemapBuffer.clear();
|
||||
// Vector to store dynamically allocated control objects to avoid early destruction
|
||||
std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>> keyboardRemapControlObjects;
|
||||
|
||||
// Load existing remaps into UI
|
||||
std::unique_lock<std::mutex> lock(keyboardManagerState.singleKeyReMap_mutex);
|
||||
for (const auto& it : keyboardManagerState.singleKeyReMap)
|
||||
{
|
||||
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, it.first, it.second);
|
||||
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects, it.first, it.second);
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
@@ -210,7 +213,7 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
|
||||
addRemapKey.Content(plusSymbol);
|
||||
addRemapKey.Margin({ 10 });
|
||||
addRemapKey.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable);
|
||||
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, keyboardRemapControlObjects);
|
||||
});
|
||||
|
||||
xamlContainer.Children().Append(header);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "EditShortcutsWindow.h"
|
||||
#include "ShortcutControl.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
LRESULT CALLBACK EditShortcutsWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
@@ -133,14 +134,17 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
ShortcutControl::EditShortcutsWindowHandle = _hWndEditShortcutsWindow;
|
||||
// Store keyboard manager state
|
||||
ShortcutControl::keyboardManagerState = &keyboardManagerState;
|
||||
KeyDropDownControl::keyboardManagerState = &keyboardManagerState;
|
||||
// Clear the shortcut remap buffer
|
||||
ShortcutControl::shortcutRemapBuffer.clear();
|
||||
// Vector to store dynamically allocated control objects to avoid early destruction
|
||||
std::vector<std::vector<std::unique_ptr<ShortcutControl>>> keyboardRemapControlObjects;
|
||||
|
||||
// Load existing shortcuts into UI
|
||||
std::unique_lock<std::mutex> lock(keyboardManagerState.osLevelShortcutReMap_mutex);
|
||||
for (const auto& it : keyboardManagerState.osLevelShortcutReMap)
|
||||
{
|
||||
ShortcutControl::AddNewShortcutControlRow(shortcutTable, it.first, it.second.targetShortcut);
|
||||
ShortcutControl::AddNewShortcutControlRow(shortcutTable, keyboardRemapControlObjects, it.first, it.second.targetShortcut);
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
@@ -158,7 +162,7 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
Shortcut originalShortcut = ShortcutControl::shortcutRemapBuffer[i][0];
|
||||
Shortcut newShortcut = ShortcutControl::shortcutRemapBuffer[i][1];
|
||||
|
||||
if (originalShortcut.IsValidShortcut() && originalShortcut.IsValidShortcut())
|
||||
if (originalShortcut.IsValidShortcut() && newShortcut.IsValidShortcut())
|
||||
{
|
||||
bool result = keyboardManagerState.AddOSLevelShortcut(originalShortcut, newShortcut);
|
||||
if (!result)
|
||||
@@ -197,7 +201,7 @@ void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMa
|
||||
addShortcut.Content(plusSymbol);
|
||||
addShortcut.Margin({ 10 });
|
||||
addShortcut.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
ShortcutControl::AddNewShortcutControlRow(shortcutTable);
|
||||
ShortcutControl::AddNewShortcutControlRow(shortcutTable, keyboardRemapControlObjects);
|
||||
});
|
||||
|
||||
xamlContainer.Children().Append(header);
|
||||
|
||||
113
src/modules/keyboardmanager/ui/KeyDropDownControl.cpp
Normal file
113
src/modules/keyboardmanager/ui/KeyDropDownControl.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "pch.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
// Initialized to null
|
||||
KeyboardManagerState* KeyDropDownControl::keyboardManagerState = nullptr;
|
||||
|
||||
// Function to set properties apart from the SelectionChanged event handler
|
||||
void KeyDropDownControl::SetDefaultProperties(bool isShortcut)
|
||||
{
|
||||
dropDown.Width(100);
|
||||
dropDown.MaxDropDownHeight(200);
|
||||
// Initialise layout attribute
|
||||
previousLayout = GetKeyboardLayout(0);
|
||||
keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut);
|
||||
dropDown.ItemsSource(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut));
|
||||
// drop down open handler - to reload the items with the latest layout
|
||||
dropDown.DropDownOpened([&, isShortcut](IInspectable const& sender, auto args) {
|
||||
ComboBox currentDropDown = sender.as<ComboBox>();
|
||||
CheckAndUpdateKeyboardLayout(currentDropDown, isShortcut);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to check if the layout has changed and accordingly update the drop down list
|
||||
void KeyDropDownControl::CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, bool isShortcut)
|
||||
{
|
||||
// Get keyboard layout for current thread
|
||||
HKL layout = GetKeyboardLayout(0);
|
||||
|
||||
// Check if the layout has changed
|
||||
if (previousLayout != layout)
|
||||
{
|
||||
keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(isShortcut);
|
||||
currentDropDown.ItemsSource(keyboardManagerState->keyboardMap.GetKeyNameList(isShortcut));
|
||||
previousLayout = layout;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to set the selected index of the drop down
|
||||
void KeyDropDownControl::SetSelectedIndex(int32_t index)
|
||||
{
|
||||
dropDown.SelectedIndex(index);
|
||||
}
|
||||
|
||||
// Function to return the combo box element of the drop down
|
||||
ComboBox KeyDropDownControl::GetComboBox()
|
||||
{
|
||||
return dropDown;
|
||||
}
|
||||
|
||||
// Function to add a drop down to the shortcut stack panel
|
||||
void KeyDropDownControl::AddDropDown(StackPanel parent, const size_t rowIndex, const size_t colIndex, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects)
|
||||
{
|
||||
keyDropDownControlObjects.push_back(std::move(std::unique_ptr<KeyDropDownControl>(new KeyDropDownControl(rowIndex, colIndex, shortcutRemapBuffer, keyDropDownControlObjects, parent))));
|
||||
// Flyout to display the warning on the drop down element
|
||||
Flyout warningFlyout;
|
||||
TextBlock warningMessage;
|
||||
warningFlyout.Content(warningMessage);
|
||||
parent.Children().Append(keyDropDownControlObjects[keyDropDownControlObjects.size() - 1]->GetComboBox());
|
||||
parent.UpdateLayout();
|
||||
}
|
||||
|
||||
// Function to get the list of key codes from the shortcut combo box stack panel
|
||||
std::vector<DWORD> KeyDropDownControl::GetKeysFromStackPanel(StackPanel parent)
|
||||
{
|
||||
std::vector<DWORD> keys;
|
||||
std::vector<DWORD> keyCodeList = keyboardManagerState->keyboardMap.GetKeyCodeList(true);
|
||||
for (int i = 0; i < (int)parent.Children().Size(); i++)
|
||||
{
|
||||
ComboBox currentDropDown = parent.Children().GetAt(i).as<ComboBox>();
|
||||
int selectedKeyIndex = currentDropDown.SelectedIndex();
|
||||
if (selectedKeyIndex != -1 && keyCodeList.size() > selectedKeyIndex)
|
||||
{
|
||||
// If None is not the selected key
|
||||
if (keyCodeList[selectedKeyIndex] != 0)
|
||||
{
|
||||
keys.push_back(keyCodeList[selectedKeyIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Function to check if a modifier has been repeated in the previous drop downs
|
||||
bool KeyDropDownControl::CheckRepeatedModifier(StackPanel parent, uint32_t dropDownIndex, int selectedKeyIndex, const std::vector<DWORD>& keyCodeList)
|
||||
{
|
||||
// check if modifier has already been added before in a previous drop down
|
||||
std::vector<DWORD> currentKeys = GetKeysFromStackPanel(parent);
|
||||
bool matchPreviousModifier = false;
|
||||
for (int i = 0; i < currentKeys.size(); i++)
|
||||
{
|
||||
// Skip the current drop down
|
||||
if (i != dropDownIndex)
|
||||
{
|
||||
// If the key type for the newly added key matches any of the existing keys in the shortcut
|
||||
if (GetKeyType(keyCodeList[selectedKeyIndex]) == GetKeyType(currentKeys[i]))
|
||||
{
|
||||
matchPreviousModifier = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchPreviousModifier;
|
||||
}
|
||||
|
||||
// Function to set the flyout warning message
|
||||
void KeyDropDownControl::SetDropDownError(ComboBox dropDown, TextBlock messageBlock, hstring message)
|
||||
{
|
||||
messageBlock.Text(message);
|
||||
dropDown.ContextFlyout().ShowAttachedFlyout((FrameworkElement)dropDown);
|
||||
dropDown.SelectedIndex(-1);
|
||||
}
|
||||
190
src/modules/keyboardmanager/ui/KeyDropDownControl.h
Normal file
190
src/modules/keyboardmanager/ui/KeyDropDownControl.h
Normal file
@@ -0,0 +1,190 @@
|
||||
#pragma once
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
|
||||
// Wrapper class for the key drop down menu
|
||||
class KeyDropDownControl
|
||||
{
|
||||
private:
|
||||
// Stores the drop down combo box
|
||||
ComboBox dropDown;
|
||||
// Stores the previous layout
|
||||
HKL previousLayout = 0;
|
||||
// Stores the key code list
|
||||
std::vector<DWORD> keyCodeList;
|
||||
|
||||
// Function to set properties apart from the SelectionChanged event handler
|
||||
void SetDefaultProperties(bool isShortcut);
|
||||
|
||||
// Function to check if the layout has changed and accordingly update the drop down list
|
||||
void CheckAndUpdateKeyboardLayout(ComboBox currentDropDown, bool isShortcut);
|
||||
|
||||
public:
|
||||
// Pointer to the keyboard manager state
|
||||
static KeyboardManagerState* keyboardManagerState;
|
||||
|
||||
// Constructor for single key drop down
|
||||
KeyDropDownControl(size_t rowIndex, size_t colIndex, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer)
|
||||
{
|
||||
SetDefaultProperties(false);
|
||||
dropDown.SelectionChanged([&, rowIndex, colIndex](IInspectable const& sender, SelectionChangedEventArgs const& args) {
|
||||
ComboBox currentDropDown = sender.as<ComboBox>();
|
||||
int selectedKeyIndex = currentDropDown.SelectedIndex();
|
||||
|
||||
// Check if the element was not found or the index exceeds the known keys
|
||||
if (selectedKeyIndex != -1 && keyCodeList.size() > selectedKeyIndex)
|
||||
{
|
||||
singleKeyRemapBuffer[rowIndex][colIndex] = keyCodeList[selectedKeyIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset to null if the key is not found
|
||||
singleKeyRemapBuffer[rowIndex][colIndex] = NULL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Constructor for shortcut drop down
|
||||
KeyDropDownControl(size_t rowIndex, size_t colIndex, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects, StackPanel parent)
|
||||
{
|
||||
SetDefaultProperties(true);
|
||||
Flyout warningFlyout;
|
||||
TextBlock warningMessage;
|
||||
warningFlyout.Content(warningMessage);
|
||||
dropDown.ContextFlyout().SetAttachedFlyout((FrameworkElement)dropDown, warningFlyout);
|
||||
|
||||
// drop down selection handler
|
||||
dropDown.SelectionChanged([&, rowIndex, colIndex, parent, warningMessage](IInspectable const& sender, SelectionChangedEventArgs const&) {
|
||||
ComboBox currentDropDown = sender.as<ComboBox>();
|
||||
int selectedKeyIndex = currentDropDown.SelectedIndex();
|
||||
uint32_t dropDownIndex = -1;
|
||||
bool dropDownFound = parent.Children().IndexOf(currentDropDown, dropDownIndex);
|
||||
|
||||
if (selectedKeyIndex != -1 && keyCodeList.size() > selectedKeyIndex && dropDownFound)
|
||||
{
|
||||
// If only 1 drop down and action key is chosen: Warn that a modifier must be chosen
|
||||
if (parent.Children().Size() == 1 && !IsModifierKey(keyCodeList[selectedKeyIndex]))
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut must start with a modifier key");
|
||||
}
|
||||
// If it is the last drop down
|
||||
else if (dropDownIndex == parent.Children().Size() - 1)
|
||||
{
|
||||
// If last drop down and a modifier is selected: add a new drop down (max of 5 drop downs should be enforced)
|
||||
if (IsModifierKey(keyCodeList[selectedKeyIndex]) && parent.Children().Size() < 5)
|
||||
{
|
||||
// If it matched any of the previous modifiers then reset that drop down
|
||||
if (CheckRepeatedModifier(parent, dropDownIndex, selectedKeyIndex, keyCodeList))
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut cannot contain a repeated modifier");
|
||||
}
|
||||
// If not, add a new drop down
|
||||
else
|
||||
{
|
||||
AddDropDown(parent, rowIndex, colIndex, shortcutRemapBuffer, keyDropDownControlObjects);
|
||||
}
|
||||
}
|
||||
// If last drop down and a modifier is selected but there are already 5 drop downs: warn the user
|
||||
else if (IsModifierKey(keyCodeList[selectedKeyIndex]) && parent.Children().Size() >= 5)
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut must contain an action key");
|
||||
}
|
||||
// If None is selected but it's the last index: warn
|
||||
else if (keyCodeList[selectedKeyIndex] == 0)
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut must contain an action key");
|
||||
}
|
||||
// If none of the above, then the action key will be set
|
||||
}
|
||||
// If it is the not the last drop down
|
||||
else
|
||||
{
|
||||
if (IsModifierKey(keyCodeList[selectedKeyIndex]))
|
||||
{
|
||||
// If it matched any of the previous modifiers then reset that drop down
|
||||
if (CheckRepeatedModifier(parent, dropDownIndex, selectedKeyIndex, keyCodeList))
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut cannot contain a repeated modifier");
|
||||
}
|
||||
// If not, the modifier key will be set
|
||||
}
|
||||
// If None is selected and there are more than 2 drop downs
|
||||
else if (keyCodeList[selectedKeyIndex] == 0 && parent.Children().Size() > 2)
|
||||
{
|
||||
// delete drop down
|
||||
parent.Children().RemoveAt(dropDownIndex);
|
||||
// delete drop down control object from the vector so that it can be destructed
|
||||
keyDropDownControlObjects.erase(keyDropDownControlObjects.begin() + dropDownIndex);
|
||||
parent.UpdateLayout();
|
||||
}
|
||||
else if (keyCodeList[selectedKeyIndex] == 0 && parent.Children().Size() <= 2)
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut must have atleast 2 keys");
|
||||
}
|
||||
// If the user tries to set an action key check if all drop down menus after this are empty if it is not the first key
|
||||
else if (dropDownIndex != 0)
|
||||
{
|
||||
bool isClear = true;
|
||||
for (int i = dropDownIndex + 1; i < (int)parent.Children().Size(); i++)
|
||||
{
|
||||
ComboBox currentDropDown = parent.Children().GetAt(i).as<ComboBox>();
|
||||
if (currentDropDown.SelectedIndex() != -1)
|
||||
{
|
||||
isClear = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isClear)
|
||||
{
|
||||
// remove all the drop down
|
||||
int elementsToBeRemoved = parent.Children().Size() - dropDownIndex - 1;
|
||||
for (int i = 0; i < elementsToBeRemoved; i++)
|
||||
{
|
||||
parent.Children().RemoveAtEnd();
|
||||
}
|
||||
parent.UpdateLayout();
|
||||
}
|
||||
else
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut cannot have more than one action key");
|
||||
}
|
||||
}
|
||||
// If there an action key is chosen on the first drop down and there are more than one drop down menus
|
||||
else
|
||||
{
|
||||
// warn and reset the drop down
|
||||
SetDropDownError(currentDropDown, warningMessage, L"Shortcut must start with a modifier key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the buffer based on the new selected drop down items
|
||||
shortcutRemapBuffer[rowIndex][colIndex].SetKeyCodes(GetKeysFromStackPanel(parent));
|
||||
});
|
||||
}
|
||||
|
||||
// Function to set the selected index of the drop down
|
||||
void SetSelectedIndex(int32_t index);
|
||||
|
||||
// Function to return the combo box element of the drop down
|
||||
ComboBox GetComboBox();
|
||||
|
||||
// Function to add a drop down to the shortcut stack panel
|
||||
static void AddDropDown(StackPanel parent, const size_t rowIndex, const size_t colIndex, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, std::vector<std::unique_ptr<KeyDropDownControl>>& keyDropDownControlObjects);
|
||||
|
||||
// Function to get the list of key codes from the shortcut combo box stack panel
|
||||
std::vector<DWORD> GetKeysFromStackPanel(StackPanel parent);
|
||||
|
||||
// Function to check if a modifier has been repeated in the previous drop downs
|
||||
bool CheckRepeatedModifier(StackPanel parent, uint32_t dropDownIndex, int selectedKeyIndex, const std::vector<DWORD>& keyCodeList);
|
||||
|
||||
// Function to set the flyout warning message
|
||||
void SetDropDownError(ComboBox dropDown, TextBlock messageBlock, hstring message);
|
||||
};
|
||||
@@ -98,7 +98,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="EditKeyboardWindow.cpp" />
|
||||
<ClCompile Include="EditShortcutsWindow.cpp" />
|
||||
<ClCompile Include="MainWindow.cpp" />
|
||||
<ClCompile Include="KeyDropDownControl.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
@@ -109,8 +109,8 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="EditKeyboardWindow.h" />
|
||||
<ClInclude Include="EditShortcutsWindow.h" />
|
||||
<ClInclude Include="KeyDropDownControl.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="MainWindow.h" />
|
||||
<ClInclude Include="ShortcutControl.h" />
|
||||
<ClInclude Include="SingleKeyRemapControl.h" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="MainWindow.cpp" />
|
||||
<ClCompile Include="EditKeyboardWindow.cpp" />
|
||||
<ClCompile Include="EditShortcutsWindow.cpp" />
|
||||
<ClCompile Include="ShortcutControl.cpp" />
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="SingleKeyRemapControl.cpp" />
|
||||
<ClCompile Include="KeyDropDownControl.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="MainWindow.h" />
|
||||
<ClInclude Include="EditKeyboardWindow.h" />
|
||||
<ClInclude Include="EditShortcutsWindow.h" />
|
||||
<ClInclude Include="ShortcutControl.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="SingleKeyRemapControl.h" />
|
||||
<ClInclude Include="KeyDropDownControl.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "MainWindow.h"
|
||||
#include "EditKeyboardWindow.h"
|
||||
#include "EditShortcutsWindow.h"
|
||||
|
||||
HWND _hWndMain;
|
||||
HINSTANCE _hInstance;
|
||||
// This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml.
|
||||
HWND hWndXamlIslandMain = nullptr;
|
||||
// This variable is used to check if window registration has been done to avoid repeated registration leading to an error.
|
||||
bool isMainWindowRegistrationCompleted = false;
|
||||
|
||||
// Function to create the Main Window
|
||||
void createMainWindow(HINSTANCE hInstance, KeyboardManagerState& keyboardManagerState)
|
||||
{
|
||||
_hInstance = hInstance;
|
||||
|
||||
// Window Registration
|
||||
const wchar_t szWindowClass[] = L"MainWindowClass";
|
||||
if (!isMainWindowRegistrationCompleted)
|
||||
{
|
||||
WNDCLASSEX windowClass = {};
|
||||
windowClass.cbSize = sizeof(WNDCLASSEX);
|
||||
windowClass.lpfnWndProc = MainWindowProc;
|
||||
windowClass.hInstance = hInstance;
|
||||
windowClass.lpszClassName = szWindowClass;
|
||||
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
|
||||
if (RegisterClassEx(&windowClass) == NULL)
|
||||
{
|
||||
MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
isMainWindowRegistrationCompleted = true;
|
||||
}
|
||||
|
||||
// Window Creation
|
||||
_hWndMain = CreateWindow(
|
||||
szWindowClass,
|
||||
L"Keyboard Manager Settings",
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
hInstance,
|
||||
NULL);
|
||||
if (_hWndMain == NULL)
|
||||
{
|
||||
MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
//XAML Island section
|
||||
// This DesktopWindowXamlSource is the object that enables a non-UWP desktop application
|
||||
// to host UWP controls in any UI element that is associated with a window handle (HWND).
|
||||
DesktopWindowXamlSource desktopSource;
|
||||
// Get handle to corewindow
|
||||
auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
|
||||
// Parent the DesktopWindowXamlSource object to current window
|
||||
check_hresult(interop->AttachToWindow(_hWndMain));
|
||||
|
||||
// Get the new child window's hwnd
|
||||
interop->get_WindowHandle(&hWndXamlIslandMain);
|
||||
// Update the xaml island window size becuase initially is 0,0
|
||||
SetWindowPos(hWndXamlIslandMain, 0, 0, 0, 800, 800, SWP_SHOWWINDOW);
|
||||
|
||||
//Creating the Xaml content
|
||||
Windows::UI::Xaml::Controls::StackPanel xamlContainer;
|
||||
xamlContainer.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
|
||||
|
||||
Windows::UI::Xaml::Controls::StackPanel keyRow;
|
||||
keyRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||
keyRow.Spacing(10);
|
||||
keyRow.Margin({ 10 });
|
||||
|
||||
Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> keyNames{ single_threaded_vector<Windows::Foundation::IInspectable>(
|
||||
{ winrt::box_value(L"Alt"),
|
||||
winrt::box_value(L"Delete"),
|
||||
winrt::box_value(L"LAlt"),
|
||||
winrt::box_value(L"LWin"),
|
||||
winrt::box_value(L"Shift"),
|
||||
winrt::box_value(L"NumLock"),
|
||||
winrt::box_value(L"LCtrl") }) };
|
||||
Windows::UI::Xaml::Controls::ComboBox cb;
|
||||
cb.IsEditable(true);
|
||||
cb.Width(200);
|
||||
cb.ItemsSource(keyNames);
|
||||
|
||||
Windows::UI::Xaml::Controls::Button bt;
|
||||
bt.Content(winrt::box_value(winrt::to_hstring("Edit Keyboard")));
|
||||
bt.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
std::thread th(createEditKeyboardWindow, _hInstance, std::ref(keyboardManagerState));
|
||||
th.join();
|
||||
});
|
||||
|
||||
Windows::UI::Xaml::Controls::Button bt2;
|
||||
bt2.Content(winrt::box_value(winrt::to_hstring("Edit Shortcuts")));
|
||||
bt2.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
std::thread th(createEditShortcutsWindow, _hInstance, std::ref(keyboardManagerState));
|
||||
th.join();
|
||||
});
|
||||
|
||||
keyRow.Children().Append(cb);
|
||||
keyRow.Children().Append(bt);
|
||||
keyRow.Children().Append(bt2);
|
||||
|
||||
xamlContainer.Children().Append(keyRow);
|
||||
xamlContainer.UpdateLayout();
|
||||
desktopSource.Content(xamlContainer);
|
||||
//End XAML Island section
|
||||
if (_hWndMain)
|
||||
{
|
||||
ShowWindow(_hWndMain, SW_SHOW);
|
||||
UpdateWindow(_hWndMain);
|
||||
}
|
||||
|
||||
//Message loop:
|
||||
MSG msg = {};
|
||||
while (GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
desktopSource.Close();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
RECT rcClient;
|
||||
|
||||
switch (messageCode)
|
||||
{
|
||||
case WM_PAINT:
|
||||
GetClientRect(hWnd, &rcClient);
|
||||
SetWindowPos(hWndXamlIslandMain, 0, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom, SWP_SHOWWINDOW);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, messageCode, wParam, lParam);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
|
||||
// Function to create the Main Window
|
||||
__declspec(dllexport) void createMainWindow(HINSTANCE hInstance, KeyboardManagerState& keyboardManagerState);
|
||||
LRESULT CALLBACK MainWindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "ShortcutControl.h"
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
//Both static members are initialized to null
|
||||
HWND ShortcutControl::EditShortcutsWindowHandle = nullptr;
|
||||
@@ -8,7 +9,7 @@ KeyboardManagerState* ShortcutControl::keyboardManagerState = nullptr;
|
||||
std::vector<std::vector<Shortcut>> ShortcutControl::shortcutRemapBuffer;
|
||||
|
||||
// Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values.
|
||||
void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, Shortcut originalKeys, Shortcut newKeys)
|
||||
void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<ShortcutControl>>>& keyboardRemapControlObjects, Shortcut originalKeys, Shortcut newKeys)
|
||||
{
|
||||
// Parent element for the row
|
||||
Windows::UI::Xaml::Controls::StackPanel tableRow;
|
||||
@@ -16,27 +17,17 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, Shortcut orig
|
||||
tableRow.Spacing(100);
|
||||
tableRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||
|
||||
// Create new ShortcutControl objects dynamically so that we does not get destructed
|
||||
std::vector<std::unique_ptr<ShortcutControl>> newrow;
|
||||
newrow.push_back(std::move(std::unique_ptr<ShortcutControl>(new ShortcutControl(shortcutRemapBuffer.size(), 0))));
|
||||
newrow.push_back(std::move(std::unique_ptr<ShortcutControl>(new ShortcutControl(shortcutRemapBuffer.size(), 1))));
|
||||
keyboardRemapControlObjects.push_back(std::move(newrow));
|
||||
// ShortcutControl for the original shortcut
|
||||
ShortcutControl originalSC(shortcutRemapBuffer.size(), 0);
|
||||
tableRow.Children().Append(originalSC.getShortcutControl());
|
||||
|
||||
tableRow.Children().Append(keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->getShortcutControl());
|
||||
// ShortcutControl for the new shortcut
|
||||
ShortcutControl newSC(shortcutRemapBuffer.size(), 1);
|
||||
tableRow.Children().Append(newSC.getShortcutControl());
|
||||
|
||||
// Set the shortcut text if the two vectors are not empty (i.e. default args)
|
||||
if (!originalKeys.IsEmpty() && !newKeys.IsEmpty())
|
||||
{
|
||||
shortcutRemapBuffer.push_back(std::vector<Shortcut>{ originalKeys, newKeys });
|
||||
originalSC.shortcutText.Text(originalKeys.ToHstring(keyboardManagerState->keyboardMap));
|
||||
newSC.shortcutText.Text(newKeys.ToHstring(keyboardManagerState->keyboardMap));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialize both shortcuts as empty shortcuts
|
||||
shortcutRemapBuffer.push_back(std::vector<Shortcut>{ Shortcut(), Shortcut() });
|
||||
}
|
||||
tableRow.Children().Append(keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->getShortcutControl());
|
||||
|
||||
|
||||
// Delete row button
|
||||
Windows::UI::Xaml::Controls::Button deleteShortcut;
|
||||
FontIcon deleteSymbol;
|
||||
@@ -50,9 +41,57 @@ void ShortcutControl::AddNewShortcutControlRow(StackPanel& parent, Shortcut orig
|
||||
parent.Children().RemoveAt(index);
|
||||
// delete the row from the buffer. Since first child of the stackpanel is the header, the effective index starts from 1
|
||||
shortcutRemapBuffer.erase(shortcutRemapBuffer.begin() + (index - 1));
|
||||
// delete the ShortcutControl objects so that they get destructed
|
||||
keyboardRemapControlObjects.erase(keyboardRemapControlObjects.begin() + (index - 1));
|
||||
});
|
||||
tableRow.Children().Append(deleteShortcut);
|
||||
tableRow.UpdateLayout();
|
||||
parent.Children().Append(tableRow);
|
||||
parent.UpdateLayout();
|
||||
|
||||
// Set the shortcut text if the two vectors are not empty (i.e. default args)
|
||||
if (originalKeys.IsValidShortcut() && newKeys.IsValidShortcut())
|
||||
{
|
||||
shortcutRemapBuffer.push_back(std::vector<Shortcut>{ Shortcut(), Shortcut() });
|
||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->AddShortcutToControl(originalKeys, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->shortcutDropDownStackPanel, *keyboardManagerState, shortcutRemapBuffer.size() - 1, 0);
|
||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->AddShortcutToControl(newKeys, keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->shortcutDropDownStackPanel, *keyboardManagerState, shortcutRemapBuffer.size() - 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialize both shortcuts as empty shortcuts
|
||||
shortcutRemapBuffer.push_back(std::vector<Shortcut>{ Shortcut(), Shortcut() });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Function to add a shortcut to the shortcut control as combo boxes
|
||||
void ShortcutControl::AddShortcutToControl(Shortcut& shortcut, StackPanel parent, KeyboardManagerState& keyboardManagerState, const size_t rowIndex, const size_t colIndex)
|
||||
{
|
||||
// Delete the existing drop down menus
|
||||
parent.Children().Clear();
|
||||
// Remove references to the old drop down objects to destroy them
|
||||
keyDropDownControlObjects.clear();
|
||||
|
||||
std::vector<DWORD> shortcutKeyCodes = shortcut.GetKeyCodes();
|
||||
std::vector<DWORD> keyCodeList = keyboardManagerState.keyboardMap.GetKeyCodeList(true);
|
||||
if (shortcutKeyCodes.size() != 0)
|
||||
{
|
||||
KeyDropDownControl::AddDropDown(parent, rowIndex, colIndex, shortcutRemapBuffer, keyDropDownControlObjects);
|
||||
for (int i = 0; i < shortcutKeyCodes.size(); i++)
|
||||
{
|
||||
// New drop down gets added automatically when the SelectedIndex is set
|
||||
if (i < (int)parent.Children().Size())
|
||||
{
|
||||
ComboBox currentDropDown = parent.Children().GetAt(i).as<ComboBox>();
|
||||
auto it = std::find(keyCodeList.begin(), keyCodeList.end(), shortcutKeyCodes[i]);
|
||||
if (it != keyCodeList.end())
|
||||
{
|
||||
currentDropDown.SelectedIndex((int32_t)std::distance(keyCodeList.begin(), it));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parent.UpdateLayout();
|
||||
}
|
||||
|
||||
// Function to return the stack panel element of the ShortcutControl. This is the externally visible UI element which can be used to add it to other layouts
|
||||
@@ -62,7 +101,7 @@ StackPanel ShortcutControl::getShortcutControl()
|
||||
}
|
||||
|
||||
// Function to create the detect shortcut UI window
|
||||
void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex)
|
||||
void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, KeyboardManagerState& keyboardManagerState, const size_t rowIndex, const size_t colIndex)
|
||||
{
|
||||
// ContentDialog for detecting shortcuts. This is the parent UI element.
|
||||
ContentDialog detectShortcutBox;
|
||||
@@ -76,7 +115,7 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam
|
||||
detectShortcutBox.IsSecondaryButtonEnabled(false);
|
||||
|
||||
// Get the linked text block for the "Type shortcut" button that was clicked
|
||||
TextBlock linkedShortcutText = getSiblingElement(sender).as<TextBlock>();
|
||||
StackPanel linkedShortcutStackPanel = getSiblingElement(sender).as<StackPanel>();
|
||||
|
||||
auto unregisterKeys = [&keyboardManagerState]() {
|
||||
std::thread t1(&KeyboardManagerState::UnregisterKeyDelay, &keyboardManagerState, VK_ESCAPE);
|
||||
@@ -90,7 +129,8 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam
|
||||
keyboardManagerState.ResetDetectedShortcutKey(key);
|
||||
};
|
||||
|
||||
auto onAccept = [linkedShortcutText,
|
||||
auto onAccept = [this,
|
||||
linkedShortcutStackPanel,
|
||||
detectShortcutBox,
|
||||
&keyboardManagerState,
|
||||
&shortcutRemapBuffer,
|
||||
@@ -102,8 +142,8 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam
|
||||
|
||||
if (!detectedShortcutKeys.IsEmpty())
|
||||
{
|
||||
shortcutRemapBuffer[rowIndex][colIndex] = detectedShortcutKeys;
|
||||
linkedShortcutText.Text(detectedShortcutKeys.ToHstring(keyboardManagerState.keyboardMap));
|
||||
// The shortcut buffer gets set in this function
|
||||
AddShortcutToControl(detectedShortcutKeys, linkedShortcutStackPanel, keyboardManagerState, rowIndex, colIndex);
|
||||
}
|
||||
|
||||
// Reset the keyboard manager UI state
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include <keyboardManager/common/Helpers.h>
|
||||
#include <keyboardmanager/common/Shortcut.h>
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
class ShortcutControl
|
||||
{
|
||||
@@ -9,6 +10,9 @@ private:
|
||||
// Textblock to display the selected shortcut
|
||||
TextBlock shortcutText;
|
||||
|
||||
// Stack panel for the drop downs to display the selected shortcut
|
||||
StackPanel shortcutDropDownStackPanel;
|
||||
|
||||
// Button to type the shortcut
|
||||
Button typeShortcut;
|
||||
|
||||
@@ -22,9 +26,16 @@ public:
|
||||
static KeyboardManagerState* keyboardManagerState;
|
||||
// Stores the current list of remappings
|
||||
static std::vector<std::vector<Shortcut>> shortcutRemapBuffer;
|
||||
// Vector to store dynamically allocated KeyDropDownControl objects to avoid early destruction
|
||||
std::vector<std::unique_ptr<KeyDropDownControl>> keyDropDownControlObjects;
|
||||
|
||||
ShortcutControl(const int& rowIndex, const int& colIndex)
|
||||
ShortcutControl(const size_t rowIndex, const size_t colIndex)
|
||||
{
|
||||
shortcutDropDownStackPanel.RequestedTheme(ElementTheme::Light);
|
||||
shortcutDropDownStackPanel.Spacing(10);
|
||||
shortcutDropDownStackPanel.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||
KeyDropDownControl::AddDropDown(shortcutDropDownStackPanel, rowIndex, colIndex, shortcutRemapBuffer, keyDropDownControlObjects);
|
||||
|
||||
typeShortcut.Content(winrt::box_value(winrt::to_hstring("Type Shortcut")));
|
||||
typeShortcut.Click([&, rowIndex, colIndex](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectShortcutWindowActivated, EditShortcutsWindowHandle);
|
||||
@@ -37,15 +48,19 @@ public:
|
||||
shortcutControlLayout.Spacing(10);
|
||||
|
||||
shortcutControlLayout.Children().Append(typeShortcut);
|
||||
shortcutControlLayout.Children().Append(shortcutText);
|
||||
shortcutControlLayout.Children().Append(shortcutDropDownStackPanel);
|
||||
shortcutControlLayout.UpdateLayout();
|
||||
}
|
||||
|
||||
// Function to add a new row to the shortcut table. If the originalKeys and newKeys args are provided, then the displayed shortcuts are set to those values.
|
||||
static void AddNewShortcutControlRow(StackPanel& parent, Shortcut originalKeys = Shortcut(), Shortcut newKeys = Shortcut());
|
||||
static void AddNewShortcutControlRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<ShortcutControl>>>& keyboardRemapControlObjects, Shortcut originalKeys = Shortcut(), Shortcut newKeys = Shortcut());
|
||||
|
||||
// Function to add a shortcut to the shortcut control as combo boxes
|
||||
void AddShortcutToControl(Shortcut& shortcut, StackPanel parent, KeyboardManagerState& keyboardManagerState, const size_t rowIndex, const size_t colIndex);
|
||||
|
||||
// Function to return the stack panel element of the ShortcutControl. This is the externally visible UI element which can be used to add it to other layouts
|
||||
StackPanel getShortcutControl();
|
||||
|
||||
// Function to create the detect shortcut UI window
|
||||
void createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex);
|
||||
void createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<Shortcut>>& shortcutRemapBuffer, KeyboardManagerState& keyboardManagerState, const size_t rowIndex, const size_t colIndex);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ KeyboardManagerState* SingleKeyRemapControl::keyboardManagerState = nullptr;
|
||||
std::vector<std::vector<DWORD>> SingleKeyRemapControl::singleKeyRemapBuffer;
|
||||
|
||||
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
|
||||
void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, const DWORD& originalKey, const DWORD& newKey)
|
||||
void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>>& keyboardRemapControlObjects, const DWORD originalKey, const DWORD newKey)
|
||||
{
|
||||
// Parent element for the row
|
||||
Windows::UI::Xaml::Controls::StackPanel tableRow;
|
||||
@@ -16,20 +16,31 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, const D
|
||||
tableRow.Spacing(100);
|
||||
tableRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
|
||||
|
||||
// Create new SingleKeyRemapControl objects dynamically so that we does not get destructed
|
||||
std::vector<std::unique_ptr<SingleKeyRemapControl>> newrow;
|
||||
newrow.push_back(std::move(std::unique_ptr<SingleKeyRemapControl>(new SingleKeyRemapControl(singleKeyRemapBuffer.size(), 0))));
|
||||
newrow.push_back(std::move(std::unique_ptr<SingleKeyRemapControl>(new SingleKeyRemapControl(singleKeyRemapBuffer.size(), 1))));
|
||||
keyboardRemapControlObjects.push_back(std::move(newrow));
|
||||
// SingleKeyRemapControl for the original key.
|
||||
SingleKeyRemapControl originalRemapKeyControl(singleKeyRemapBuffer.size(), 0);
|
||||
tableRow.Children().Append(originalRemapKeyControl.getSingleKeyRemapControl());
|
||||
|
||||
// SingleKeyRemapControl for the new remap key.
|
||||
SingleKeyRemapControl newRemapKeyControl(singleKeyRemapBuffer.size(), 1);
|
||||
tableRow.Children().Append(newRemapKeyControl.getSingleKeyRemapControl());
|
||||
tableRow.Children().Append(keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->getSingleKeyRemapControl());
|
||||
// SingleKeyRemapControl for the new remap key
|
||||
tableRow.Children().Append(keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->getSingleKeyRemapControl());
|
||||
|
||||
// Set the key text if the two keys are not null (i.e. default args)
|
||||
if (originalKey != NULL && newKey != NULL)
|
||||
{
|
||||
singleKeyRemapBuffer.push_back(std::vector<DWORD>{ originalKey, newKey });
|
||||
originalRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring(keyboardManagerState->keyboardMap.GetKeyName(originalKey).c_str()));
|
||||
newRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring(keyboardManagerState->keyboardMap.GetKeyName(newKey).c_str()));
|
||||
std::vector<DWORD> keyCodes = keyboardManagerState->keyboardMap.GetKeyCodeList();
|
||||
auto it = std::find(keyCodes.begin(), keyCodes.end(), originalKey);
|
||||
if (it != keyCodes.end())
|
||||
{
|
||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][0]->singleKeyRemapDropDown.SetSelectedIndex((int32_t)std::distance(keyCodes.begin(), it));
|
||||
}
|
||||
it = std::find(keyCodes.begin(), keyCodes.end(), newKey);
|
||||
if (it != keyCodes.end())
|
||||
{
|
||||
keyboardRemapControlObjects[keyboardRemapControlObjects.size() - 1][1]->singleKeyRemapDropDown.SetSelectedIndex((int32_t)std::distance(keyCodes.begin(), it));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -52,6 +63,8 @@ void SingleKeyRemapControl::AddNewControlKeyRemapRow(StackPanel& parent, const D
|
||||
parent.Children().RemoveAt(index);
|
||||
// delete the row from the buffer. Since first child of the stackpanel is the header, the effective index starts from 1
|
||||
singleKeyRemapBuffer.erase(singleKeyRemapBuffer.begin() + (index - 1));
|
||||
// delete the SingleKeyRemapControl objects so that they get destructed
|
||||
keyboardRemapControlObjects.erase(keyboardRemapControlObjects.begin() + (index - 1));
|
||||
});
|
||||
tableRow.Children().Append(deleteRemapKeys);
|
||||
parent.Children().Append(tableRow);
|
||||
@@ -64,7 +77,7 @@ StackPanel SingleKeyRemapControl::getSingleKeyRemapControl()
|
||||
}
|
||||
|
||||
// Function to create the detect remap key UI window
|
||||
void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex)
|
||||
void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer, KeyboardManagerState& keyboardManagerState, const size_t rowIndex, const size_t colIndex)
|
||||
{
|
||||
// ContentDialog for detecting remap key. This is the parent UI element.
|
||||
ContentDialog detectRemapKeyBox;
|
||||
@@ -78,7 +91,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
|
||||
detectRemapKeyBox.IsSecondaryButtonEnabled(false);
|
||||
|
||||
// Get the linked text block for the "Type Key" button that was clicked
|
||||
TextBlock linkedRemapText = getSiblingElement(sender).as<TextBlock>();
|
||||
ComboBox linkedRemapDropDown = getSiblingElement(sender).as<ComboBox>();
|
||||
|
||||
auto unregisterKeys = [&keyboardManagerState]() {
|
||||
std::thread t1(&KeyboardManagerState::UnregisterKeyDelay, &keyboardManagerState, VK_ESCAPE);
|
||||
@@ -87,7 +100,7 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
|
||||
t2.detach();
|
||||
};
|
||||
|
||||
auto onAccept = [linkedRemapText,
|
||||
auto onAccept = [linkedRemapDropDown,
|
||||
detectRemapKeyBox,
|
||||
&keyboardManagerState,
|
||||
&singleKeyRemapBuffer,
|
||||
@@ -99,8 +112,14 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
|
||||
|
||||
if (detectedKey != NULL)
|
||||
{
|
||||
singleKeyRemapBuffer[rowIndex][colIndex] = detectedKey;
|
||||
linkedRemapText.Text(winrt::to_hstring(keyboardManagerState.keyboardMap.GetKeyName(detectedKey).c_str()));
|
||||
std::vector<DWORD> 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());
|
||||
auto it = std::find(keyCodeList.begin(), keyCodeList.end(), detectedKey);
|
||||
if (it != keyCodeList.end())
|
||||
{
|
||||
linkedRemapDropDown.SelectedIndex((int32_t)std::distance(keyCodeList.begin(), it));
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the keyboard manager UI state
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
#include "KeyDropDownControl.h"
|
||||
|
||||
class SingleKeyRemapControl
|
||||
{
|
||||
private:
|
||||
// Textblock to display the selected remap key
|
||||
TextBlock singleKeyRemapText;
|
||||
// Drop down to display the selected remap key
|
||||
KeyDropDownControl singleKeyRemapDropDown;
|
||||
|
||||
// Button to type the remap key
|
||||
Button typeKey;
|
||||
@@ -21,7 +22,8 @@ public:
|
||||
// Stores the current list of remappings
|
||||
static std::vector<std::vector<DWORD>> singleKeyRemapBuffer;
|
||||
|
||||
SingleKeyRemapControl(const int& rowIndex, const int& colIndex)
|
||||
SingleKeyRemapControl(const size_t rowIndex, const size_t colIndex) :
|
||||
singleKeyRemapDropDown(rowIndex, colIndex, singleKeyRemapBuffer)
|
||||
{
|
||||
typeKey.Content(winrt::box_value(winrt::to_hstring("Type Key")));
|
||||
typeKey.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
|
||||
@@ -37,15 +39,16 @@ public:
|
||||
singleKeyRemapControlLayout.Spacing(10);
|
||||
|
||||
singleKeyRemapControlLayout.Children().Append(typeKey);
|
||||
singleKeyRemapControlLayout.Children().Append(singleKeyRemapText);
|
||||
singleKeyRemapControlLayout.Children().Append(singleKeyRemapDropDown.GetComboBox());
|
||||
singleKeyRemapControlLayout.UpdateLayout();
|
||||
}
|
||||
|
||||
// Function to add a new row to the remap keys table. If the originalKey and newKey args are provided, then the displayed remap keys are set to those values.
|
||||
static void AddNewControlKeyRemapRow(StackPanel& parent, const DWORD& originalKey = NULL, const DWORD& newKey = NULL);
|
||||
static void AddNewControlKeyRemapRow(StackPanel& parent, std::vector<std::vector<std::unique_ptr<SingleKeyRemapControl>>>& keyboardRemapControlObjects, const DWORD originalKey = NULL, const DWORD newKey = NULL);
|
||||
|
||||
// Function to return the stack panel element of the SingleKeyRemapControl. This is the externally visible UI element which can be used to add it to other layouts
|
||||
StackPanel getSingleKeyRemapControl();
|
||||
|
||||
// Function to create the detect remap keys UI window
|
||||
void createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer, KeyboardManagerState& keyboardManagerState, const int& rowIndex, const int& colIndex);
|
||||
void createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, std::vector<std::vector<DWORD>>& singleKeyRemapBuffer, KeyboardManagerState& keyboardManagerState, const size_t rowIndex, const size_t colIndex);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user