Remap Keyboard UI (dev/keyboardManager) (#1698)

* Added initial UI implementation

* Added backend logic for remap key interaction

* Added single key remap control

* Updated Edit keyboardWindow UI

* Commented out ui logic

* Fixed issue with remap window UI and uncommented the code

* Updated customdialog window foreground color

* Updated buttons foreground color

* Added info header

* Added null check for detected key

* Removed fully qualified namespaces

* updated the background color as ligtht gray
This commit is contained in:
udit3333
2020-03-27 08:38:58 -07:00
committed by Udit Singh
parent 90ddcb30bf
commit f48040a4d7
8 changed files with 392 additions and 14 deletions

View File

@@ -1,5 +1,6 @@
#include "pch.h"
#include "EditKeyboardWindow.h"
#include "SingleKeyRemapControl.h"
LRESULT CALLBACK EditKeyboardWindowProc(HWND, UINT, WPARAM, LPARAM);
@@ -38,8 +39,8 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
400,
400,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
@@ -63,14 +64,148 @@ void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardMan
// Update the xaml island window size becuase initially is 0,0
SetWindowPos(hWndXamlIslandEditKeyboardWindow, 0, 0, 0, 400, 400, SWP_SHOWWINDOW);
//Creating the Xaml content
// Creating the Xaml content. xamlContainer is the parent UI element
Windows::UI::Xaml::Controls::StackPanel xamlContainer;
xamlContainer.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
Windows::UI::Xaml::Controls::Button bt;
bt.Content(winrt::box_value(winrt::to_hstring("Don't Type key")));
xamlContainer.Children().Append(bt);
// Header for the window
Windows::UI::Xaml::Controls::StackPanel header;
header.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
header.Margin({ 10, 10, 10, 30 });
header.Spacing(10);
// Header text
TextBlock headerText;
headerText.Text(winrt::to_hstring("Remap Keyboard"));
headerText.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
headerText.FontSize(30);
headerText.Margin({ 0, 0, 1000, 0 });
// Header Cancel button
Button cancelButton;
cancelButton.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
cancelButton.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
cancelButton.Content(winrt::box_value(winrt::to_hstring("Cancel")));
cancelButton.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
// Close the window since settings do not need to be saved
PostMessage(_hWndEditKeyboardWindow, WM_CLOSE, 0, 0);
});
// Text block for information about remap key section.
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 });
// Table to display the key remaps
Windows::UI::Xaml::Controls::StackPanel keyRemapTable;
keyRemapTable.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
keyRemapTable.Margin({ 10, 10, 10, 20 });
keyRemapTable.Spacing(10);
// Header row of the keys remap table
Windows::UI::Xaml::Controls::StackPanel tableHeaderRow;
tableHeaderRow.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
tableHeaderRow.Spacing(100);
tableHeaderRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
// First header textblock in the header row of the keys remap table
TextBlock originalKeyRemapHeader;
originalKeyRemapHeader.Text(winrt::to_hstring("Original Key:"));
originalKeyRemapHeader.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
originalKeyRemapHeader.FontWeight(Text::FontWeights::Bold());
originalKeyRemapHeader.Margin({ 0, 0, 0, 10 });
tableHeaderRow.Children().Append(originalKeyRemapHeader);
// Second header textblock in the header row of the keys remap table
TextBlock newKeyRemapHeader;
newKeyRemapHeader.Text(winrt::to_hstring("New Key:"));
newKeyRemapHeader.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
newKeyRemapHeader.FontWeight(Text::FontWeights::Bold());
newKeyRemapHeader.Margin({ 0, 0, 0, 10 });
tableHeaderRow.Children().Append(newKeyRemapHeader);
keyRemapTable.Children().Append(tableHeaderRow);
// Message to display success/failure of saving settings.
TextBlock settingsMessage;
// Main Header Apply button
Button applyButton;
applyButton.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
applyButton.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
applyButton.Content(winrt::box_value(winrt::to_hstring("Apply")));
applyButton.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
bool isSuccess = true;
// Clear existing Key Remaps
keyboardManagerState.ClearSingleKeyRemaps();
// Save the keys that are valid and report if any of them were invalid
for (unsigned int i = 1; i < keyRemapTable.Children().Size(); i++)
{
StackPanel currentRow = keyRemapTable.Children().GetAt(i).as<StackPanel>();
hstring originalKeyString = currentRow.Children().GetAt(0).as<StackPanel>().Children().GetAt(1).as<TextBlock>().Text();
hstring newKeyString = currentRow.Children().GetAt(1).as<StackPanel>().Children().GetAt(1).as<TextBlock>().Text();
if (!originalKeyString.empty() && !newKeyString.empty())
{
DWORD originalKey = std::stoi(originalKeyString.c_str());
DWORD newKey = std::stoi(newKeyString.c_str());
keyboardManagerState.AddSingleKeyRemap(originalKey, newKey);
}
else
{
isSuccess = false;
}
}
if (isSuccess)
{
settingsMessage.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Green() });
settingsMessage.Text(winrt::to_hstring("Remapping successful!"));
}
else
{
settingsMessage.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Red() });
settingsMessage.Text(winrt::to_hstring("All remappings were not successfully applied."));
}
});
header.Children().Append(headerText);
header.Children().Append(cancelButton);
header.Children().Append(applyButton);
header.Children().Append(settingsMessage);
// Store handle of edit keyboard window
SingleKeyRemapControl::EditKeyboardWindowHandle = _hWndEditKeyboardWindow;
// Store keyboard manager state
SingleKeyRemapControl::keyboardManagerState = &keyboardManagerState;
// Load existing remaps into UI
for (const auto& it : keyboardManagerState.singleKeyReMap)
{
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable, it.first, it.second);
}
// Add remap key button
Windows::UI::Xaml::Controls::Button addRemapKey;
addRemapKey.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
addRemapKey.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
FontIcon plusSymbol;
plusSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
plusSymbol.Glyph(L"\xE109");
addRemapKey.Content(plusSymbol);
addRemapKey.Margin({ 10 });
addRemapKey.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
SingleKeyRemapControl::AddNewControlKeyRemapRow(keyRemapTable);
});
xamlContainer.Children().Append(header);
xamlContainer.Children().Append(keyRemapInfoHeader);
xamlContainer.Children().Append(keyRemapTable);
xamlContainer.Children().Append(addRemapKey);
xamlContainer.UpdateLayout();
desktopSource.Content(xamlContainer);
////End XAML Island section
if (_hWndEditKeyboardWindow)
{

View File

@@ -104,6 +104,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ShortcutControl.cpp" />
<ClCompile Include="SingleKeyRemapControl.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="EditKeyboardWindow.h" />
@@ -111,6 +112,7 @@
<ClInclude Include="pch.h" />
<ClInclude Include="MainWindow.h" />
<ClInclude Include="ShortcutControl.h" />
<ClInclude Include="SingleKeyRemapControl.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -6,6 +6,7 @@
<ClCompile Include="EditShortcutsWindow.cpp" />
<ClCompile Include="ShortcutControl.cpp" />
<ClCompile Include="pch.cpp" />
<ClCompile Include="SingleKeyRemapControl.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="MainWindow.h" />
@@ -13,6 +14,7 @@
<ClInclude Include="EditShortcutsWindow.h" />
<ClInclude Include="ShortcutControl.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="SingleKeyRemapControl.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -0,0 +1,115 @@
#include "pch.h"
#include "SingleKeyRemapControl.h"
//Both static members are initialized to null
HWND SingleKeyRemapControl::EditKeyboardWindowHandle = nullptr;
KeyboardManagerState* SingleKeyRemapControl::keyboardManagerState = nullptr;
// 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 WORD& newKey)
{
// Parent element for the row
Windows::UI::Xaml::Controls::StackPanel tableRow;
tableRow.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
tableRow.Spacing(100);
tableRow.Orientation(Windows::UI::Xaml::Controls::Orientation::Horizontal);
// SingleKeyRemapControl for the original key.
SingleKeyRemapControl originalRemapKeyControl;
tableRow.Children().Append(originalRemapKeyControl.getSingleKeyRemapControl());
// SingleKeyRemapControl for the new remap key.
SingleKeyRemapControl newRemapKeyControl;
tableRow.Children().Append(newRemapKeyControl.getSingleKeyRemapControl());
// Set the key text if the two keys are not null (i.e. default args)
if (originalKey != NULL && newKey != NULL)
{
originalRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring((unsigned int)originalKey));
newRemapKeyControl.singleKeyRemapText.Text(winrt::to_hstring((unsigned int)newKey));
}
// Delete row button
Windows::UI::Xaml::Controls::Button deleteRemapKeys;
deleteRemapKeys.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
deleteRemapKeys.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
FontIcon deleteSymbol;
deleteSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
deleteSymbol.Glyph(L"\xE74D");
deleteRemapKeys.Content(deleteSymbol);
deleteRemapKeys.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
StackPanel currentRow = sender.as<Button>().Parent().as<StackPanel>();
uint32_t index;
parent.Children().IndexOf(currentRow, index);
parent.Children().RemoveAt(index);
});
tableRow.Children().Append(deleteRemapKeys);
parent.Children().Append(tableRow);
}
// 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 SingleKeyRemapControl::getSingleKeyRemapControl()
{
return singleKeyRemapControlLayout;
}
// Function to create the detect remap key UI window
void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState)
{
// ContentDialog for detecting remap key. This is the parent UI element.
ContentDialog detectRemapKeyBox;
// ContentDialog requires manually setting the XamlRoot (https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
detectRemapKeyBox.XamlRoot(xamlRoot);
detectRemapKeyBox.Title(box_value(L"Press a key on selected keyboard:"));
detectRemapKeyBox.PrimaryButtonText(to_hstring(L"OK"));
detectRemapKeyBox.IsSecondaryButtonEnabled(false);
detectRemapKeyBox.CloseButtonText(to_hstring(L"Cancel"));
detectRemapKeyBox.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
detectRemapKeyBox.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
// Get the linked text block for the "Type Key" button that was clicked
TextBlock linkedRemapText = getSiblingElement(sender).as<TextBlock>();
// OK button
detectRemapKeyBox.PrimaryButtonClick([=, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
// Save the detected key in the linked text block
DWORD detectedKey = keyboardManagerState.GetDetectedSingleRemapKey();
if (detectedKey != NULL)
{
linkedRemapText.Text(winrt::to_hstring((unsigned int)detectedKey));
}
// Reset the keyboard manager UI state
keyboardManagerState.ResetUIState();
});
// Cancel button
detectRemapKeyBox.CloseButtonClick([&keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
// Reset the keyboard manager UI state
keyboardManagerState.ResetUIState();
});
// StackPanel parent for the displayed text in the dialog
Windows::UI::Xaml::Controls::StackPanel stackPanel;
stackPanel.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
// Header textblock
TextBlock text;
text.Text(winrt::to_hstring("Key Pressed:"));
text.Margin({ 0, 0, 0, 10 });
// Textblock to display the detected key
TextBlock remapKey;
stackPanel.Children().Append(text);
stackPanel.Children().Append(remapKey);
stackPanel.UpdateLayout();
detectRemapKeyBox.Content(stackPanel);
// Configure the keyboardManagerState to store the UI information.
keyboardManagerState.ConfigureDetectSingleKeyRemapUI(remapKey);
// Show the dialog
detectRemapKeyBox.ShowAsync();
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include <keyboardmanager/common/KeyboardManagerState.h>
class SingleKeyRemapControl
{
private:
// Textblock to display the selected remap key
TextBlock singleKeyRemapText;
// Button to type the remap key
Button typeKey;
// StackPanel to parent the above controls
StackPanel singleKeyRemapControlLayout;
public:
// Handle to the current Edit Keyboard Window
static HWND EditKeyboardWindowHandle;
// Pointer to the keyboard manager state
static KeyboardManagerState* keyboardManagerState;
SingleKeyRemapControl()
{
typeKey.Content(winrt::box_value(winrt::to_hstring("Type Key")));
typeKey.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
typeKey.Foreground(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::Black() });
typeKey.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectSingleKeyRemapWindowActivated, EditKeyboardWindowHandle);
// Using the XamlRoot of the typeKey to get the root of the XAML host
createDetectKeyWindow(sender, sender.as<Button>().XamlRoot(), *keyboardManagerState);
});
singleKeyRemapControlLayout.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
singleKeyRemapControlLayout.Margin({ 0, 0, 0, 10 });
singleKeyRemapControlLayout.Spacing(10);
singleKeyRemapControlLayout.Children().Append(typeKey);
singleKeyRemapControlLayout.Children().Append(singleKeyRemapText);
}
// 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 WORD& 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, KeyboardManagerState& keyboardManagerState);
};