Edit Shortcuts UI (dev/keyboardManager) (#1647)

* Added EditShortcuts Window and added Detecting shortcuts functionality

* Fixed build error

* Changed detection to take place only when window is in focus

* Added solution folder

* Added a common project and refactored shared variables to an object with wrapper functions

* Added dynamic addition of shortcuts

* Moved all shared variables in detection to state variable with wrapper functions

* Added code to re-load saved shortcuts in the UI

* Added comments

* Fixed argument modifiers in Helpers

* Updated arg modifiers in all functions

* Removed unused headers and added precompiled headers
This commit is contained in:
Arjun Balgovind
2020-03-23 10:44:02 -07:00
committed by Udit Singh
parent fc7e7074ce
commit b713083574
31 changed files with 1062 additions and 214 deletions

View File

@@ -0,0 +1,109 @@
#include "pch.h"
#include "EditKeyboardWindow.h"
LRESULT CALLBACK EditKeyboardWindowProc(HWND, UINT, WPARAM, LPARAM);
// This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml.
HWND hWndXamlIslandEditKeyboardWindow = nullptr;
// This variable is used to check if window registration has been done to avoid repeated registration leading to an error.
bool isEditKeyboardWindowRegistrationCompleted = false;
// Function to create the Edit Keyboard Window
void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
{
// Window Registration
const wchar_t szWindowClass[] = L"EditKeyboardWindow";
if (!isEditKeyboardWindowRegistrationCompleted)
{
WNDCLASSEX windowClass = {};
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpfnWndProc = EditKeyboardWindowProc;
windowClass.hInstance = hInst;
windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
if (RegisterClassEx(&windowClass) == NULL)
{
MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
return;
}
isEditKeyboardWindowRegistrationCompleted = true;
}
// Window Creation
HWND _hWndEditKeyboardWindow = CreateWindow(
szWindowClass,
L"PowerKeys Remap Keyboard",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
400,
400,
NULL,
NULL,
hInst,
NULL);
if (_hWndEditKeyboardWindow == NULL)
{
MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
return;
}
// 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(_hWndEditKeyboardWindow));
// Get the new child window's hwnd
interop->get_WindowHandle(&hWndXamlIslandEditKeyboardWindow);
// Update the xaml island window size becuase initially is 0,0
SetWindowPos(hWndXamlIslandEditKeyboardWindow, 0, 0, 0, 400, 400, 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::Button bt;
bt.Content(winrt::box_value(winrt::to_hstring("Don't Type key")));
xamlContainer.Children().Append(bt);
xamlContainer.UpdateLayout();
desktopSource.Content(xamlContainer);
////End XAML Island section
if (_hWndEditKeyboardWindow)
{
ShowWindow(_hWndEditKeyboardWindow, SW_SHOW);
UpdateWindow(_hWndEditKeyboardWindow);
}
// Message loop:
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
desktopSource.Close();
}
LRESULT CALLBACK EditKeyboardWindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam)
{
RECT rcClient;
switch (messageCode)
{
case WM_PAINT:
GetClientRect(hWnd, &rcClient);
SetWindowPos(hWndXamlIslandEditKeyboardWindow, 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;
}

View File

@@ -0,0 +1,5 @@
#pragma once
#include <keyboardmanager/common/KeyboardManagerState.h>
// Function to create the Edit Keyboard Window
__declspec(dllexport) void createEditKeyboardWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState);

View File

@@ -0,0 +1,239 @@
#include "pch.h"
#include "EditShortcutsWindow.h"
#include "ShortcutControl.h"
LRESULT CALLBACK EditShortcutsWindowProc(HWND, UINT, WPARAM, LPARAM);
// This Hwnd will be the window handler for the Xaml Island: A child window that contains Xaml.
HWND hWndXamlIslandEditShortcutsWindow = nullptr;
// This variable is used to check if window registration has been done to avoid repeated registration leading to an error.
bool isEditShortcutsWindowRegistrationCompleted = false;
// Function to create the Edit Shortcuts Window
void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState)
{
// Window Registration
const wchar_t szWindowClass[] = L"EditShortcutsWindow";
if (!isEditShortcutsWindowRegistrationCompleted)
{
WNDCLASSEX windowClass = {};
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpfnWndProc = EditShortcutsWindowProc;
windowClass.hInstance = hInst;
windowClass.lpszClassName = szWindowClass;
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
if (RegisterClassEx(&windowClass) == NULL)
{
MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
return;
}
isEditShortcutsWindowRegistrationCompleted = true;
}
// Window Creation
HWND _hWndEditShortcutsWindow = CreateWindow(
szWindowClass,
L"PowerKeys Edit Shortcuts",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (_hWndEditShortcutsWindow == NULL)
{
MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
return;
}
// 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(_hWndEditShortcutsWindow));
// Get the new child window's hwnd
interop->get_WindowHandle(&hWndXamlIslandEditShortcutsWindow);
// Update the xaml island window size becuase initially is 0,0
SetWindowPos(hWndXamlIslandEditShortcutsWindow, 0, 0, 0, 400, 400, SWP_SHOWWINDOW);
// 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() });
// Header for the window
Windows::UI::Xaml::Controls::StackPanel header;
header.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
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("Edit Shortcuts"));
headerText.FontSize(30);
headerText.Margin({ 0, 0, 100, 0 });
// Cancel button
Button cancelButton;
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(_hWndEditShortcutsWindow, WM_CLOSE, 0, 0);
});
// Table to display the shortcuts
Windows::UI::Xaml::Controls::StackPanel shortcutTable;
shortcutTable.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
shortcutTable.Margin({ 10, 10, 10, 20 });
shortcutTable.Spacing(10);
// Header row of the shortcut 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 shortcut table
TextBlock originalShortcutHeader;
originalShortcutHeader.Text(winrt::to_hstring("Original Shortcut:"));
originalShortcutHeader.FontWeight(Text::FontWeights::Bold());
originalShortcutHeader.Margin({ 0, 0, 0, 10 });
tableHeaderRow.Children().Append(originalShortcutHeader);
// Second header textblock in the header row of the shortcut table
TextBlock newShortcutHeader;
newShortcutHeader.Text(winrt::to_hstring("New Shortcut:"));
newShortcutHeader.FontWeight(Text::FontWeights::Bold());
newShortcutHeader.Margin({ 0, 0, 0, 10 });
tableHeaderRow.Children().Append(newShortcutHeader);
shortcutTable.Children().Append(tableHeaderRow);
// Message to display success/failure of saving settings.
TextBlock settingsMessage;
// Apply button
Button applyButton;
applyButton.Content(winrt::box_value(winrt::to_hstring("Apply")));
applyButton.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
bool isSuccess = true;
// Clear existing shortcuts
keyboardManagerState.ClearOSLevelShortcuts();
// Save the shortcuts that are valid and report if any of them were invalid
for (unsigned int i = 1; i < shortcutTable.Children().Size(); i++)
{
StackPanel currentRow = shortcutTable.Children().GetAt(i).as<StackPanel>();
hstring originalShortcut = currentRow.Children().GetAt(0).as<StackPanel>().Children().GetAt(1).as<TextBlock>().Text();
hstring newShortcut = currentRow.Children().GetAt(1).as<StackPanel>().Children().GetAt(1).as<TextBlock>().Text();
if (!originalShortcut.empty() && !newShortcut.empty())
{
std::vector<DWORD> originalKeys = convertWStringVectorToIntegerVector<DWORD>(splitwstring(originalShortcut.c_str(), L' '));
std::vector<WORD> newKeys = convertWStringVectorToIntegerVector<WORD>(splitwstring(newShortcut.c_str(), L' '));
// Check if number of keys is two since only that is currently implemented
if (originalKeys.size() == 2 && newKeys.size() == 2)
{
keyboardManagerState.AddOSLevelShortcut(originalKeys, newKeys);
}
else
{
isSuccess = false;
}
}
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 shortcuts window
ShortcutControl::EditShortcutsWindowHandle = _hWndEditShortcutsWindow;
// Store keyboard manager state
ShortcutControl::keyboardManagerState = &keyboardManagerState;
// Load existing shortcuts into UI
for (const auto& it: keyboardManagerState.osLevelShortcutReMap)
{
ShortcutControl::AddNewShortcutControlRow(shortcutTable, it.first, it.second.first);
}
// Add shortcut button
Windows::UI::Xaml::Controls::Button addShortcut;
FontIcon plusSymbol;
plusSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
plusSymbol.Glyph(L"\xE109");
addShortcut.Content(plusSymbol);
addShortcut.Margin({ 10 });
addShortcut.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
ShortcutControl::AddNewShortcutControlRow(shortcutTable);
});
xamlContainer.Children().Append(header);
xamlContainer.Children().Append(shortcutTable);
xamlContainer.Children().Append(addShortcut);
xamlContainer.UpdateLayout();
desktopSource.Content(xamlContainer);
////End XAML Island section
if (_hWndEditShortcutsWindow)
{
ShowWindow(_hWndEditShortcutsWindow, SW_SHOW);
UpdateWindow(_hWndEditShortcutsWindow);
}
// Message loop:
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
desktopSource.Close();
}
LRESULT CALLBACK EditShortcutsWindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam)
{
RECT rcClient;
switch (messageCode)
{
case WM_PAINT:
GetClientRect(hWnd, &rcClient);
SetWindowPos(hWndXamlIslandEditShortcutsWindow, 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;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "keyboardmanager/common/KeyboardManagerState.h"
#include "keyboardmanager/common/Helpers.h"
// Function to create the Edit Shortcuts Window
__declspec(dllexport) void createEditShortcutsWindow(HINSTANCE hInst, KeyboardManagerState& keyboardManagerState);

View File

@@ -0,0 +1,152 @@
#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"PowerKeys 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&) {
//keyboardManagerState.SetUIState(KeyboardManagerUIState::DetectKeyWindowActivated);
std::thread th(createEditKeyboardWindow, _hInstance, std::ref(keyboardManagerState));
th.join();
//keyboardManagerState.ResetUIState();
});
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;
}

View File

@@ -0,0 +1,6 @@
#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);

View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{EAF23649-EF6E-478B-980E-81FAD96CCA2A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PowerKeysUI</RootNamespace>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<CppWinRTEnabled>true</CppWinRTEnabled>
<ProjectName>PowerKeysUI</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>UNICODE;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>windowsapp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>windowsapp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="EditKeyboardWindow.cpp" />
<ClCompile Include="EditShortcutsWindow.cpp" />
<ClCompile Include="MainWindow.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ShortcutControl.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="EditKeyboardWindow.h" />
<ClInclude Include="EditShortcutsWindow.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="MainWindow.h" />
<ClInclude Include="ShortcutControl.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common\KeyboardManagerCommon.vcxproj">
<Project>{8affa899-0b73-49ec-8c50-0fadda57b2fc}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200302.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +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" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="MainWindow.h" />
<ClInclude Include="EditKeyboardWindow.h" />
<ClInclude Include="EditShortcutsWindow.h" />
<ClInclude Include="ShortcutControl.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,109 @@
#include "pch.h"
#include "ShortcutControl.h"
//Both static members are initialized to null
HWND ShortcutControl::EditShortcutsWindowHandle = nullptr;
KeyboardManagerState* ShortcutControl::keyboardManagerState = nullptr;
// 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, const std::vector<DWORD>& originalKeys, const std::vector<WORD>& newKeys)
{
// 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);
// ShortcutControl for the original shortcut
ShortcutControl originalSC;
tableRow.Children().Append(originalSC.getShortcutControl());
// ShortcutControl for the new shortcut
ShortcutControl newSC;
tableRow.Children().Append(newSC.getShortcutControl());
// Set the shortcut text if the two vectors are not empty (i.e. default args)
if (!originalKeys.empty() && !newKeys.empty())
{
originalSC.shortcutText.Text(convertVectorToHstring<DWORD>(originalKeys));
newSC.shortcutText.Text(convertVectorToHstring<WORD>(newKeys));
}
// Delete row button
Windows::UI::Xaml::Controls::Button deleteShortcut;
FontIcon deleteSymbol;
deleteSymbol.FontFamily(Xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
deleteSymbol.Glyph(L"\xE74D");
deleteShortcut.Content(deleteSymbol);
deleteShortcut.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(deleteShortcut);
parent.Children().Append(tableRow);
}
// 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 ShortcutControl::getShortcutControl()
{
return shortcutControlLayout;
}
// Function to create the detect shortcut UI window
void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, XamlRoot xamlRoot, KeyboardManagerState& keyboardManagerState)
{
// ContentDialog for detecting shortcuts. This is the parent UI element.
ContentDialog detectShortcutBox;
// 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)
detectShortcutBox.XamlRoot(xamlRoot);
detectShortcutBox.Title(box_value(L"Press the keys in shortcut:"));
detectShortcutBox.PrimaryButtonText(to_hstring(L"OK"));
detectShortcutBox.IsSecondaryButtonEnabled(false);
detectShortcutBox.CloseButtonText(to_hstring(L"Cancel"));
detectShortcutBox.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
// Get the linked text block for the "Type shortcut" button that was clicked
TextBlock linkedShortcutText = getSiblingElement(sender).as<TextBlock>();
// OK button
detectShortcutBox.PrimaryButtonClick([=, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
// Save the detected shortcut in the linked text block
std::vector<DWORD> detectedShortcutKeys = keyboardManagerState.GetDetectedShortcut();
linkedShortcutText.Text(convertVectorToHstring<DWORD>(detectedShortcutKeys));
// Reset the keyboard manager UI state
keyboardManagerState.ResetUIState();
});
// Cancel button
detectShortcutBox.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("Keys Pressed:"));
text.Margin({ 0, 0, 0, 10 });
// Textblock to display the detected shortcut
TextBlock shortcutKeys;
stackPanel.Children().Append(text);
stackPanel.Children().Append(shortcutKeys);
stackPanel.UpdateLayout();
detectShortcutBox.Content(stackPanel);
// Configure the keyboardManagerState to store the UI information.
keyboardManagerState.ConfigureDetectShortcutUI(shortcutKeys);
// Show the dialog
detectShortcutBox.ShowAsync();
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <keyboardmanager/common/KeyboardManagerState.h>
#include <keyboardManager/common/Helpers.h>
class ShortcutControl
{
private:
// Textblock to display the selected shortcut
TextBlock shortcutText;
// Button to type the shortcut
Button typeShortcut;
// StackPanel to parent the above controls
StackPanel shortcutControlLayout;
public:
// Handle to the current Edit Shortcuts Window
static HWND EditShortcutsWindowHandle;
// Pointer to the keyboard manager state
static KeyboardManagerState* keyboardManagerState;
ShortcutControl()
{
typeShortcut.Content(winrt::box_value(winrt::to_hstring("Type Shortcut")));
typeShortcut.Click([&](IInspectable const& sender, RoutedEventArgs const&) {
keyboardManagerState->SetUIState(KeyboardManagerUIState::DetectShortcutWindowActivated, EditShortcutsWindowHandle);
// Using the XamlRoot of the typeShortcut to get the root of the XAML host
createDetectShortcutWindow(sender, sender.as<Button>().XamlRoot(), *keyboardManagerState);
});
shortcutControlLayout.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
shortcutControlLayout.Margin({ 0, 0, 0, 10 });
shortcutControlLayout.Spacing(10);
shortcutControlLayout.Children().Append(typeShortcut);
shortcutControlLayout.Children().Append(shortcutText);
}
// 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, const std::vector<DWORD>& originalKeys = std::vector<DWORD>(), const std::vector<WORD>& newKeys = std::vector<WORD>());
// 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, KeyboardManagerState& keyboardManagerState);
};

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.200302.1" targetFramework="native" />
</packages>

View File

@@ -0,0 +1 @@
#include "pch.h"

View File

@@ -0,0 +1,26 @@
#pragma once
// Do not define WIN32_LEAN_AND_MEAN as WinUI doesn't work when it is defined
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <thread>
#include <winrt/Windows.system.h>
#include <winrt/windows.ui.xaml.hosting.h>
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/windows.ui.xaml.controls.h>
#include <winrt/Windows.ui.xaml.media.h>
#include <winrt/Windows.Foundation.Collections.h>
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Foundation.Numerics.h"
#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
#include "winrt/Windows.UI.Text.h"
#include "winrt/Windows.UI.Core.h"
using namespace winrt;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;