mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 10:46:33 +02:00
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:
committed by
Udit Singh
parent
fc7e7074ce
commit
b713083574
28
src/modules/keyboardmanager/common/Helpers.cpp
Normal file
28
src/modules/keyboardmanager/common/Helpers.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "pch.h"
|
||||
#include "Helpers.h"
|
||||
#include <sstream>
|
||||
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter)
|
||||
{
|
||||
std::wstringstream ss(input);
|
||||
std::wstring item;
|
||||
std::vector<std::wstring> splittedStrings;
|
||||
while (std::getline(ss, item, L' '))
|
||||
{
|
||||
splittedStrings.push_back(item);
|
||||
}
|
||||
|
||||
return splittedStrings;
|
||||
}
|
||||
|
||||
// Function to return the next sibling element for an element under a stack panel
|
||||
IInspectable getSiblingElement(IInspectable const& element)
|
||||
{
|
||||
FrameworkElement frameworkElement = element.as<FrameworkElement>();
|
||||
StackPanel parentElement = frameworkElement.Parent().as<StackPanel>();
|
||||
uint32_t index;
|
||||
|
||||
parentElement.Children().IndexOf(frameworkElement, index);
|
||||
return parentElement.Children().GetAt(index + 1);
|
||||
}
|
||||
34
src/modules/keyboardmanager/common/Helpers.h
Normal file
34
src/modules/keyboardmanager/common/Helpers.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
// Function to split a wstring based on a delimiter and return a vector of split strings
|
||||
std::vector<std::wstring> splitwstring(const std::wstring& input, wchar_t delimiter);
|
||||
|
||||
// Function to return the next sibling element for an element under a stack panel
|
||||
winrt::Windows::Foundation::IInspectable getSiblingElement(winrt::Windows::Foundation::IInspectable const& element);
|
||||
|
||||
// Function to convert an unsigned int vector to hstring by concatenating them
|
||||
template<typename T>
|
||||
winrt::hstring convertVectorToHstring(const std::vector<T>& input)
|
||||
{
|
||||
winrt::hstring output;
|
||||
for (int i = 0; i < input.size(); i++)
|
||||
{
|
||||
output = output + winrt::to_hstring((unsigned int)input[i]) + winrt::to_hstring(L" ");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Function to convert a wstring vector to a integer vector
|
||||
template<typename T>
|
||||
std::vector<T> convertWStringVectorToIntegerVector(const std::vector<std::wstring>& input)
|
||||
{
|
||||
std::vector<T> typeVector;
|
||||
for (int i = 0; i < input.size(); i++)
|
||||
{
|
||||
typeVector.push_back((T)std::stoi(input[i]));
|
||||
}
|
||||
|
||||
return typeVector;
|
||||
}
|
||||
110
src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj
Normal file
110
src/modules/keyboardmanager/common/KeyboardManagerCommon.vcxproj
Normal file
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<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>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}</ProjectGuid>
|
||||
<RootNamespace>KeyboardManagerCommon</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</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>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Helpers.cpp" />
|
||||
<ClCompile Include="KeyboardManagerState.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Helpers.h" />
|
||||
<ClInclude Include="KeyboardManagerState.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\common.vcxproj">
|
||||
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="KeyboardManagerState.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Helpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KeyboardManagerState.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Helpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
140
src/modules/keyboardmanager/common/KeyboardManagerState.cpp
Normal file
140
src/modules/keyboardmanager/common/KeyboardManagerState.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardManagerState.h"
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState::KeyboardManagerState() :
|
||||
uiState(KeyboardManagerUIState::Deactivated), currentUIWindow(nullptr), currentShortcutTextBlock(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with activated windows it also checks if the window is in focus.
|
||||
bool KeyboardManagerState::CheckUIState(KeyboardManagerUIState state)
|
||||
{
|
||||
if (uiState == state)
|
||||
{
|
||||
if (uiState == KeyboardManagerUIState::Deactivated)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If the UI state is activated then we also have to ensure that the UI window is in focus.
|
||||
// GetForegroundWindow can be used here since we only need to check the main parent window and not the sub windows within the content dialog. Using GUIThreadInfo will give more specific sub-windows within the XAML window which is not needed.
|
||||
else if (currentUIWindow == GetForegroundWindow())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to set the window handle of the current UI window that is activated
|
||||
void KeyboardManagerState::SetCurrentUIWindow(HWND windowHandle)
|
||||
{
|
||||
currentUIWindow = windowHandle;
|
||||
}
|
||||
|
||||
// Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument.
|
||||
void KeyboardManagerState::SetUIState(KeyboardManagerUIState state, HWND windowHandle)
|
||||
{
|
||||
uiState = state;
|
||||
currentUIWindow = windowHandle;
|
||||
}
|
||||
|
||||
// Function to reset the UI state members
|
||||
void KeyboardManagerState::ResetUIState()
|
||||
{
|
||||
SetUIState(KeyboardManagerUIState::Deactivated);
|
||||
currentShortcutTextBlock = nullptr;
|
||||
detectedShortcut.clear();
|
||||
}
|
||||
|
||||
// Function to clear the OS Level shortcut remapping table
|
||||
void KeyboardManagerState::ClearOSLevelShortcuts()
|
||||
{
|
||||
osLevelShortcutReMap.clear();
|
||||
}
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
void KeyboardManagerState::AddOSLevelShortcut(const std::vector<DWORD>& originalSC, const std::vector<WORD>& newSC)
|
||||
{
|
||||
osLevelShortcutReMap[originalSC] = std::make_pair(newSC, false);
|
||||
}
|
||||
|
||||
// Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook
|
||||
void KeyboardManagerState::ConfigureDetectShortcutUI(const TextBlock& textBlock)
|
||||
{
|
||||
currentShortcutTextBlock = textBlock;
|
||||
}
|
||||
|
||||
// Function to update the detect shortcut UI based on the entered keys
|
||||
void KeyboardManagerState::UpdateDetectShortcutUI()
|
||||
{
|
||||
if (currentShortcutTextBlock == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hstring shortcutString = convertVectorToHstring<DWORD>(detectedShortcut);
|
||||
|
||||
// Since this function is invoked from the back-end thread, in order to update the UI the dispatcher must be used.
|
||||
currentShortcutTextBlock.Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [=]() {
|
||||
currentShortcutTextBlock.Text(shortcutString);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to return the currently detected shortcut which is displayed on the UI
|
||||
std::vector<DWORD> KeyboardManagerState::GetDetectedShortcut()
|
||||
{
|
||||
hstring detectedShortcutString = currentShortcutTextBlock.Text();
|
||||
std::wstring detectedShortcutWstring = detectedShortcutString.c_str();
|
||||
std::vector<std::wstring> detectedShortcutVector = splitwstring(detectedShortcutWstring, L' ');
|
||||
return convertWStringVectorToIntegerVector<DWORD>(detectedShortcutVector);
|
||||
}
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active.
|
||||
bool KeyboardManagerState::DetectKeyUIBackend(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// Check if the detect key UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectKeyWindowActivated))
|
||||
{
|
||||
// Suppress the keyboard event
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active.
|
||||
bool KeyboardManagerState::DetectShortcutUIBackend(LowlevelKeyboardEvent* data)
|
||||
{
|
||||
// Check if the detect shortcut UI window has been activated
|
||||
if (CheckUIState(KeyboardManagerUIState::DetectShortcutWindowActivated))
|
||||
{
|
||||
// Add the key if it is pressed down
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
if (std::find(detectedShortcut.begin(), detectedShortcut.end(), data->lParam->vkCode) == detectedShortcut.end())
|
||||
{
|
||||
detectedShortcut.push_back(data->lParam->vkCode);
|
||||
// Update the UI. This function is called here because it should store the set of keys pressed till the last key which was pressed down.
|
||||
UpdateDetectShortcutUI();
|
||||
}
|
||||
}
|
||||
// Remove the key if it has been released
|
||||
else if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
detectedShortcut.erase(std::remove(detectedShortcut.begin(), detectedShortcut.end(), data->lParam->vkCode), detectedShortcut.end());
|
||||
}
|
||||
|
||||
// Suppress the keyboard event
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the detect shortcut UI window is not activated, then clear the shortcut buffer if it isn't empty
|
||||
else if (!detectedShortcut.empty())
|
||||
{
|
||||
detectedShortcut.clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
84
src/modules/keyboardmanager/common/KeyboardManagerState.h
Normal file
84
src/modules/keyboardmanager/common/KeyboardManagerState.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
//#include "pch.h"
|
||||
#include "Helpers.h"
|
||||
#include <interface/lowlevel_keyboard_event_data.h>
|
||||
#include <winrt/Windows.UI.Xaml.Controls.h>
|
||||
|
||||
|
||||
// Enum type to store different states of the UI
|
||||
enum class KeyboardManagerUIState
|
||||
{
|
||||
// If set to this value then there is no keyboard manager window currently active that requires a hook
|
||||
Deactivated,
|
||||
// If set to this value then the detect key window is currently active and it requires a hook
|
||||
DetectKeyWindowActivated,
|
||||
// If set to this value then the detect shortcut window is currently active and it requires a hook
|
||||
DetectShortcutWindowActivated
|
||||
};
|
||||
|
||||
// Class to store the shared state of the keyboard manager between the UI and the hook
|
||||
class KeyboardManagerState
|
||||
{
|
||||
private:
|
||||
// State variable used to store which UI window is currently active that requires interaction with the hook
|
||||
KeyboardManagerUIState uiState;
|
||||
|
||||
// Window handle for the current UI window which is active. Should be set to nullptr if UI is deactivated
|
||||
HWND currentUIWindow;
|
||||
|
||||
// Vector to store the shortcut detected in the detect shortcut UI window. This is used in both the backend and the UI.
|
||||
std::vector<DWORD> detectedShortcut;
|
||||
|
||||
// Stores the UI element which is to be updated based on the shortcut entered
|
||||
winrt::Windows::UI::Xaml::Controls::TextBlock currentShortcutTextBlock;
|
||||
|
||||
public:
|
||||
// Maps which store the remappings for each of the features. The bool fields should be initalised to false. They are used to check the current state of the shortcut (i.e is that particular shortcut currently pressed down or not).
|
||||
// Stores single key remappings
|
||||
std::unordered_map<DWORD, WORD> singleKeyReMap;
|
||||
|
||||
// Stores keys which need to be changed from toggle behaviour to modifier behaviour. Eg. Caps Lock
|
||||
std::unordered_map<DWORD, bool> singleKeyToggleToMod;
|
||||
|
||||
// Stores the os level shortcut remappings
|
||||
std::map<std::vector<DWORD>, std::pair<std::vector<WORD>, bool>> osLevelShortcutReMap;
|
||||
|
||||
// Stores the app-specific shortcut remappings. Maps application name to the shortcut map
|
||||
std::map<std::wstring, std::map<std::vector<DWORD>, std::pair<std::vector<WORD>, bool>>> appSpecificShortcutReMap;
|
||||
|
||||
// Constructor
|
||||
KeyboardManagerState();
|
||||
|
||||
// Function to reset the UI state members
|
||||
void ResetUIState();
|
||||
|
||||
// Function to check the if the UI state matches the argument state. For states with activated windows it also checks if the window is in focus.
|
||||
bool CheckUIState(KeyboardManagerUIState state);
|
||||
|
||||
// Function to set the window handle of the current UI window that is activated
|
||||
void SetCurrentUIWindow(HWND windowHandle);
|
||||
|
||||
// Function to set the UI state. When a window is activated, the handle to the window can be passed in the windowHandle argument.
|
||||
void SetUIState(KeyboardManagerUIState state, HWND windowHandle = nullptr);
|
||||
|
||||
// Function to clear the OS Level shortcut remapping table
|
||||
void ClearOSLevelShortcuts();
|
||||
|
||||
// Function to add a new OS level shortcut remapping
|
||||
void AddOSLevelShortcut(const std::vector<DWORD>& originalSC, const std::vector<WORD>& newSC);
|
||||
|
||||
// Function to set the textblock of the detect shortcut UI so that it can be accessed by the hook
|
||||
void ConfigureDetectShortcutUI(const winrt::Windows::UI::Xaml::Controls::TextBlock& textBlock);
|
||||
|
||||
// Function to update the detect shortcut UI based on the entered keys
|
||||
void UpdateDetectShortcutUI();
|
||||
|
||||
// Function to return the currently detected shortcut which is displayed on the UI
|
||||
std::vector<DWORD> GetDetectedShortcut();
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the single key remap event to use the UI and suppress events while the remap window is active.
|
||||
bool DetectKeyUIBackend(LowlevelKeyboardEvent* data);
|
||||
|
||||
// Function which can be used in HandleKeyboardHookEvent before the os level shortcut remap event to use the UI and suppress events while the remap window is active.
|
||||
bool DetectShortcutUIBackend(LowlevelKeyboardEvent* data);
|
||||
};
|
||||
1
src/modules/keyboardmanager/common/pch.cpp
Normal file
1
src/modules/keyboardmanager/common/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
24
src/modules/keyboardmanager/common/pch.h
Normal file
24
src/modules/keyboardmanager/common/pch.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#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"
|
||||
#include <stdlib.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;
|
||||
32
src/modules/keyboardmanager/dll/PowerKeys.rc
Normal file
32
src/modules/keyboardmanager/dll/PowerKeys.rc
Normal file
@@ -0,0 +1,32 @@
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,1,0,0
|
||||
PRODUCTVERSION 0,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Company Name"
|
||||
VALUE "FileDescription", "$projectname$ Module"
|
||||
VALUE "FileVersion", "0.1.0.0"
|
||||
VALUE "InternalName", "$projectname$"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2019 Company Name"
|
||||
VALUE "OriginalFilename", "$projectname$.dll"
|
||||
VALUE "ProductName", "$projectname$"
|
||||
VALUE "ProductVersion", "0.1.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
138
src/modules/keyboardmanager/dll/PowerKeys.vcxproj
Normal file
138
src/modules/keyboardmanager/dll/PowerKeys.vcxproj
Normal file
@@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<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>{89f34af7-1c34-4a72-aa6e-534bcf972bd9}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>PowerKeys</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>PowerKeys</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)\modules\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\;$(SolutionDir)src\modules;$(SolutionDir)src\common\Telemetry;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">shlwapi.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>
|
||||
<Link>
|
||||
<AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">shlwapi.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>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(SolutionDir)src\common\common.vcxproj">
|
||||
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\common\KeyboardManagerCommon.vcxproj">
|
||||
<Project>{8affa899-0b73-49ec-8c50-0fadda57b2fc}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ui\PowerKeysUI.vcxproj">
|
||||
<Project>{eaf23649-ef6e-478b-980e-81fad96cca2a}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PowerKeys.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
621
src/modules/keyboardmanager/dll/dllmain.cpp
Normal file
621
src/modules/keyboardmanager/dll/dllmain.cpp
Normal file
@@ -0,0 +1,621 @@
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include <interface/lowlevel_keyboard_event_data.h>
|
||||
#include <interface/win_hook_event_data.h>
|
||||
#include <common/settings_objects.h>
|
||||
#include "trace.h"
|
||||
#include <keyboardmanager/ui/MainWindow.h>
|
||||
#include <keyboardmanager/common/KeyboardManagerState.h>
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// The PowerToy name that will be shown in the settings.
|
||||
const static wchar_t* MODULE_NAME = L"PowerKeys";
|
||||
// Add a description that will we shown in the module settings page.
|
||||
const static wchar_t* MODULE_DESC = L"Customize your experience by remapping keys or creating new shortcuts!";
|
||||
|
||||
// Implement the PowerToy Module Interface and all the required methods.
|
||||
class PowerKeys : public PowertoyModuleIface
|
||||
{
|
||||
private:
|
||||
// The PowerToy state.
|
||||
bool m_enabled = false;
|
||||
|
||||
// Flags used for distinguishing key events sent by PowerKeys
|
||||
static const ULONG_PTR POWERKEYS_INJECTED_FLAG = 0x1;
|
||||
static const ULONG_PTR POWERKEYS_SINGLEKEY_FLAG = 0x11;
|
||||
static const ULONG_PTR POWERKEYS_SHORTCUT_FLAG = 0x101;
|
||||
|
||||
// Dummy key event used in between key up and down events to prevent certain global events from happening
|
||||
static const DWORD DUMMY_KEY = 0xFF;
|
||||
|
||||
// Low level hook handles
|
||||
static HHOOK hook_handle;
|
||||
|
||||
// Required for Unhook in old versions of Windows
|
||||
static HHOOK hook_handle_copy;
|
||||
|
||||
// Static pointer to the current powerkeys object required for accessing the HandleKeyboardHookEvent function in the hook procedure (Only global or static variables can be accessed in a hook procedure CALLBACK)
|
||||
static PowerKeys* powerkeys_object_ptr;
|
||||
|
||||
// Variable which stores all the state information to be shared between the UI and back-end
|
||||
KeyboardManagerState keyboardManagerState;
|
||||
|
||||
// Vector to store the detected shortcut in the detect shortcut UI. Acts as a shortcut buffer while detecting the shortcuts in the UI.
|
||||
std::vector<DWORD> detectedShortcutKeys;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
PowerKeys()
|
||||
{
|
||||
init_map();
|
||||
|
||||
// Set the static pointer to the newest object of the class
|
||||
powerkeys_object_ptr = this;
|
||||
};
|
||||
|
||||
// This function is used to add the hardcoded mappings
|
||||
void init_map()
|
||||
{
|
||||
//// If mapped to 0x0 then key is disabled.
|
||||
//keyboardManagerState.singleKeyReMap[0x41] = 0x42;
|
||||
//keyboardManagerState.singleKeyReMap[0x42] = 0x43;
|
||||
//keyboardManagerState.singleKeyReMap[0x43] = 0x41;
|
||||
//keyboardManagerState.singleKeyReMap[VK_LWIN] = VK_LCONTROL;
|
||||
//keyboardManagerState.singleKeyReMap[VK_LCONTROL] = VK_LWIN;
|
||||
//keyboardManagerState.singleKeyReMap[VK_CAPITAL] = 0x0;
|
||||
//keyboardManagerState.singleKeyReMap[VK_LSHIFT] = VK_CAPITAL;
|
||||
//keyboardManagerState.singleKeyToggleToMod[VK_CAPITAL] = false;
|
||||
|
||||
//// OS-level shortcut remappings
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LMENU, 0x44 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x56 }), false);
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LMENU, 0x45 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x58 }), false);
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LWIN, 0x46 })] = std::make_pair(std::vector<WORD>({ VK_LWIN, 0x53 }), false);
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LWIN, 0x41 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x58 }), false);
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LCONTROL, 0x58 })] = std::make_pair(std::vector<WORD>({ VK_LWIN, 0x41 }), false);
|
||||
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LWIN, 0x41 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x58 }), false);
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LCONTROL, 0x58 })] = std::make_pair(std::vector<WORD>({ VK_LMENU, 0x44 }), false);
|
||||
//keyboardManagerState.osLevelShortcutReMap[std::vector<DWORD>({ VK_LCONTROL, 0x56 })] = std::make_pair(std::vector<WORD>({ VK_LWIN, 0x41 }), false);
|
||||
|
||||
////App-specific shortcut remappings
|
||||
//keyboardManagerState.appSpecificShortcutReMap[L"msedge.exe"][std::vector<DWORD>({ VK_LCONTROL, 0x43 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x56 }), false); // Ctrl+C to Ctrl+V
|
||||
//keyboardManagerState.appSpecificShortcutReMap[L"msedge.exe"][std::vector<DWORD>({ VK_LMENU, 0x44 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x46 }), false); // Alt+D to Ctrl+F
|
||||
//keyboardManagerState.appSpecificShortcutReMap[L"OUTLOOK.EXE"][std::vector<DWORD>({ VK_LCONTROL, 0x46 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x45 }), false); // Ctrl+F to Ctrl+E
|
||||
//keyboardManagerState.appSpecificShortcutReMap[L"MicrosoftEdge.exe"][std::vector<DWORD>({ VK_LCONTROL, 0x58 })] = std::make_pair(std::vector<WORD>({ VK_LCONTROL, 0x56 }), false); // Ctrl+X to Ctrl+V
|
||||
//keyboardManagerState.appSpecificShortcutReMap[L"Calculator.exe"][std::vector<DWORD>({ VK_LCONTROL, 0x47 })] = std::make_pair(std::vector<WORD>({ VK_LSHIFT, 0x32 }), false); // Ctrl+G to Shift+2
|
||||
}
|
||||
|
||||
// Destroy the powertoy and free memory
|
||||
virtual void destroy() override
|
||||
{
|
||||
stop_lowlevel_keyboard_hook();
|
||||
delete this;
|
||||
}
|
||||
|
||||
// Return the display name of the powertoy, this will be cached by the runner
|
||||
virtual const wchar_t* get_name() override
|
||||
{
|
||||
return MODULE_NAME;
|
||||
}
|
||||
|
||||
// Return array of the names of all events that this powertoy listens for, with
|
||||
// nullptr as the last element of the array. Nullptr can also be retured for empty
|
||||
// list.
|
||||
virtual const wchar_t** get_events() override
|
||||
{
|
||||
static const wchar_t* events[] = { ll_keyboard, nullptr };
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
// Return JSON with the configuration options.
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||
{
|
||||
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
|
||||
// Create a Settings object.
|
||||
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||
settings.set_description(MODULE_DESC);
|
||||
|
||||
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||
}
|
||||
|
||||
// Signal from the Settings editor to call a custom action.
|
||||
// This can be used to spawn more complex editors.
|
||||
virtual void call_custom_action(const wchar_t* action) override
|
||||
{
|
||||
static UINT custom_action_num_calls = 0;
|
||||
try
|
||||
{
|
||||
// Parse the action values, including name.
|
||||
PowerToysSettings::CustomActionObject action_object =
|
||||
PowerToysSettings::CustomActionObject::from_json_string(action);
|
||||
|
||||
//if (action_object.get_name() == L"custom_action_id") {
|
||||
// // Execute your custom action
|
||||
//}
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the runner to pass the updated settings values as a serialized JSON.
|
||||
virtual void set_config(const wchar_t* config) override
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the input JSON string.
|
||||
PowerToysSettings::PowerToyValues values =
|
||||
PowerToysSettings::PowerToyValues::from_json_string(config);
|
||||
|
||||
// If you don't need to do any custom processing of the settings, proceed
|
||||
// to persists the values calling:
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Improper JSON.
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the powertoy
|
||||
virtual void enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||
std::thread(createMainWindow, hInstance, std::ref(keyboardManagerState)).detach();
|
||||
start_lowlevel_keyboard_hook();
|
||||
}
|
||||
|
||||
// Disable the powertoy
|
||||
virtual void disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
stop_lowlevel_keyboard_hook();
|
||||
}
|
||||
|
||||
// Returns if the powertoys is enabled
|
||||
virtual bool is_enabled() override
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
// Handle incoming event, data is event-specific
|
||||
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) override {}
|
||||
|
||||
virtual void signal_system_menu_action(const wchar_t* name) override {}
|
||||
|
||||
// Hook procedure definition
|
||||
static LRESULT CALLBACK hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
LowlevelKeyboardEvent event;
|
||||
if (nCode == HC_ACTION)
|
||||
{
|
||||
event.lParam = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
event.wParam = wParam;
|
||||
if (powerkeys_object_ptr->HandleKeyboardHookEvent(&event) == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(hook_handle_copy, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
// Prevent system-wide input lagging while paused in the debugger
|
||||
//#define DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED
|
||||
void start_lowlevel_keyboard_hook()
|
||||
{
|
||||
#if defined(_DEBUG) && defined(DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED)
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!hook_handle)
|
||||
{
|
||||
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
|
||||
hook_handle_copy = hook_handle;
|
||||
if (!hook_handle)
|
||||
{
|
||||
throw std::runtime_error("Cannot install keyboard listener");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to terminate the low level hook
|
||||
void stop_lowlevel_keyboard_hook()
|
||||
{
|
||||
if (hook_handle)
|
||||
{
|
||||
UnhookWindowsHookEx(hook_handle);
|
||||
hook_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Function called by the hook procedure to handle the events. This is the starting point function for remapping
|
||||
intptr_t HandleKeyboardHookEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// If the Detect Key Window is currently activated, then suppress the keyboard event
|
||||
if (keyboardManagerState.DetectKeyUIBackend(data))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remap a key
|
||||
intptr_t SingleKeyRemapResult = HandleSingleKeyRemapEvent(data);
|
||||
|
||||
// Single key remaps have priority. If a key is remapped, only the remapped version should be visible to the shortcuts and hence the event should be suppressed here.
|
||||
if (SingleKeyRemapResult == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If the Detect Shortcut Window is currently activated, then suppress the keyboard event
|
||||
if (keyboardManagerState.DetectShortcutUIBackend(data))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Remap a key to behave like a modifier instead of a toggle
|
||||
intptr_t SingleKeyToggleToModResult = HandleSingleKeyToggleToModEvent(data);
|
||||
|
||||
// Handle an app-specific shortcut remapping
|
||||
intptr_t AppSpecificShortcutRemapResult = HandleAppSpecificShortcutRemapEvent(data);
|
||||
|
||||
// If an app-specific shortcut is remapped then the os-level shortcut remapping should be suppressed.
|
||||
if (AppSpecificShortcutRemapResult == 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Handle an os-level shortcut remapping
|
||||
intptr_t OSLevelShortcutRemapResult = HandleOSLevelShortcutRemapEvent(data);
|
||||
|
||||
// If any of the supported types of remappings took place, then suppress the key event
|
||||
if ((SingleKeyRemapResult + SingleKeyToggleToModResult + OSLevelShortcutRemapResult + AppSpecificShortcutRemapResult) > 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to a handle a single key remap
|
||||
intptr_t HandleSingleKeyRemapEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (!(data->lParam->dwExtraInfo & POWERKEYS_INJECTED_FLAG))
|
||||
{
|
||||
auto it = keyboardManagerState.singleKeyReMap.find(data->lParam->vkCode);
|
||||
if (it != keyboardManagerState.singleKeyReMap.end())
|
||||
{
|
||||
// If mapped to 0x0 then the key is disabled
|
||||
if (it->second == 0x0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int key_count = 1;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = it->second;
|
||||
keyEventList[0].ki.dwFlags = 0;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SINGLEKEY_FLAG;
|
||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
keyEventList[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
}
|
||||
|
||||
UINT res = SendInput(key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to a change a key's behaviour from toggle to modifier
|
||||
intptr_t HandleSingleKeyToggleToModEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (!(data->lParam->dwExtraInfo & POWERKEYS_INJECTED_FLAG))
|
||||
{
|
||||
auto it = keyboardManagerState.singleKeyToggleToMod.find(data->lParam->vkCode);
|
||||
if (it != keyboardManagerState.singleKeyToggleToMod.end())
|
||||
{
|
||||
// To avoid long presses (which leads to continuous keydown messages) from toggling the key on and off
|
||||
if (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN)
|
||||
{
|
||||
if (it->second == false)
|
||||
{
|
||||
keyboardManagerState.singleKeyToggleToMod[data->lParam->vkCode] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
int key_count = 2;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = (WORD)data->lParam->vkCode;
|
||||
keyEventList[0].ki.dwFlags = 0;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SINGLEKEY_FLAG;
|
||||
keyEventList[1].type = INPUT_KEYBOARD;
|
||||
keyEventList[1].ki.wVk = (WORD)data->lParam->vkCode;
|
||||
keyEventList[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[1].ki.dwExtraInfo = POWERKEYS_SINGLEKEY_FLAG;
|
||||
|
||||
UINT res = SendInput(key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
|
||||
// Reset the long press flag when the key has been lifted.
|
||||
if (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP)
|
||||
{
|
||||
keyboardManagerState.singleKeyToggleToMod[data->lParam->vkCode] = false;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to a handle a shortcut remap
|
||||
intptr_t HandleShortcutRemapEvent(LowlevelKeyboardEvent* data, std::map<std::vector<DWORD>, std::pair<std::vector<WORD>, bool>>& reMap) noexcept
|
||||
{
|
||||
for (auto& it : reMap)
|
||||
{
|
||||
DWORD src_1 = it.first[0];
|
||||
DWORD src_2 = it.first[1];
|
||||
WORD dest_1 = it.second.first[0];
|
||||
WORD dest_2 = it.second.first[1];
|
||||
// If the shortcut has been pressed down
|
||||
if ((GetAsyncKeyState(src_1) & 0x8000) && !it.second.second)
|
||||
{
|
||||
if (data->lParam->vkCode == src_2 && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||
{
|
||||
int key_count = 4;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
if (src_1 == dest_1)
|
||||
{
|
||||
key_count = 1;
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = dest_2;
|
||||
keyEventList[0].ki.dwFlags = 0;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = (WORD)DUMMY_KEY;
|
||||
keyEventList[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[1].type = INPUT_KEYBOARD;
|
||||
keyEventList[1].ki.wVk = (WORD)src_1;
|
||||
keyEventList[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[1].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[2].type = INPUT_KEYBOARD;
|
||||
keyEventList[2].ki.wVk = dest_1;
|
||||
keyEventList[2].ki.dwFlags = 0;
|
||||
keyEventList[2].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[3].type = INPUT_KEYBOARD;
|
||||
keyEventList[3].ki.wVk = dest_2;
|
||||
keyEventList[3].ki.dwFlags = 0;
|
||||
keyEventList[3].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
}
|
||||
|
||||
it.second.second = true;
|
||||
UINT res = SendInput(key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// The shortcut has already been pressed down at least once, i.e. the shortcut has been invoked
|
||||
else if (it.second.second)
|
||||
{
|
||||
// If the modifier key of the original shortcut is released before the normal key
|
||||
if (data->lParam->vkCode == src_1 && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||
{
|
||||
int key_count = 2;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = dest_2;
|
||||
keyEventList[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[1].type = INPUT_KEYBOARD;
|
||||
keyEventList[1].ki.wVk = dest_1;
|
||||
keyEventList[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[1].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
it.second.second = false;
|
||||
UINT res = SendInput(key_count, keyEventList, sizeof(INPUT));
|
||||
|
||||
delete[] keyEventList;
|
||||
return 1;
|
||||
}
|
||||
// The system will see dest_1 as being held down because of the shortcut remap
|
||||
if (GetAsyncKeyState(dest_1) & 0x8000)
|
||||
{
|
||||
// If the original shortcut is still held down the keyboard will see the original normal key along with the new modifier (keys held down send repeated keydown messages)
|
||||
if (data->lParam->vkCode == src_2 && (data->wParam == WM_KEYDOWN || data->wParam == WM_SYSKEYDOWN))
|
||||
{
|
||||
int key_count = 1;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = dest_2;
|
||||
keyEventList[0].ki.dwFlags = 0;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
|
||||
it.second.second = true;
|
||||
UINT res = SendInput(key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
return 1;
|
||||
}
|
||||
// If the normal key is released from the original shortcut then revert the keyboard state to just the original modifier being held down
|
||||
if (data->lParam->vkCode == src_2 && (data->wParam == WM_KEYUP || data->wParam == WM_SYSKEYUP))
|
||||
{
|
||||
int key_count = 4;
|
||||
LPINPUT keyEventList = new INPUT[size_t(key_count)]();
|
||||
memset(keyEventList, 0, sizeof(keyEventList));
|
||||
if (src_1 == dest_1)
|
||||
{
|
||||
key_count = 1;
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = dest_2;
|
||||
keyEventList[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyEventList[0].type = INPUT_KEYBOARD;
|
||||
keyEventList[0].ki.wVk = dest_2;
|
||||
keyEventList[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[0].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[1].type = INPUT_KEYBOARD;
|
||||
keyEventList[1].ki.wVk = dest_1;
|
||||
keyEventList[1].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[1].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[2].type = INPUT_KEYBOARD;
|
||||
keyEventList[2].ki.wVk = (WORD)src_1;
|
||||
keyEventList[2].ki.dwFlags = 0;
|
||||
keyEventList[2].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
keyEventList[3].type = INPUT_KEYBOARD;
|
||||
keyEventList[3].ki.wVk = (WORD)DUMMY_KEY;
|
||||
keyEventList[3].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
keyEventList[3].ki.dwExtraInfo = POWERKEYS_SHORTCUT_FLAG;
|
||||
}
|
||||
it.second.second = false;
|
||||
UINT res = SendInput(key_count, keyEventList, sizeof(INPUT));
|
||||
delete[] keyEventList;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to a handle an os-level shortcut remap
|
||||
intptr_t HandleOSLevelShortcutRemapEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (data->lParam->dwExtraInfo != POWERKEYS_SHORTCUT_FLAG)
|
||||
{
|
||||
return HandleShortcutRemapEvent(data, keyboardManagerState.osLevelShortcutReMap);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to return the window in focus
|
||||
HWND GetFocusWindowHandle()
|
||||
{
|
||||
// Using GetGUIThreadInfo for getting the process of the window in focus. GetForegroundWindow has issues with UWP apps as it returns the Application Frame Host as its linked process
|
||||
GUITHREADINFO guiThreadInfo;
|
||||
guiThreadInfo.cbSize = sizeof(GUITHREADINFO);
|
||||
GetGUIThreadInfo(0, &guiThreadInfo);
|
||||
|
||||
// If no window in focus, use the active window
|
||||
if (guiThreadInfo.hwndFocus == nullptr)
|
||||
{
|
||||
return guiThreadInfo.hwndActive;
|
||||
}
|
||||
return guiThreadInfo.hwndFocus;
|
||||
}
|
||||
|
||||
// Function to return the executable name of the application in focus
|
||||
std::wstring GetCurrentApplication(bool keepPath)
|
||||
{
|
||||
HWND current_window_handle = GetFocusWindowHandle();
|
||||
DWORD process_id;
|
||||
DWORD nSize = MAX_PATH;
|
||||
WCHAR buffer[MAX_PATH] = { 0 };
|
||||
|
||||
// Get process ID of the focus window
|
||||
DWORD thread_id = GetWindowThreadProcessId(current_window_handle, &process_id);
|
||||
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_id);
|
||||
|
||||
// Get full path of the executable
|
||||
bool res = QueryFullProcessImageName(hProc, 0, buffer, &nSize);
|
||||
std::wstring process_name;
|
||||
CloseHandle(hProc);
|
||||
|
||||
process_name = buffer;
|
||||
if (res)
|
||||
{
|
||||
PathStripPath(buffer);
|
||||
|
||||
if (!keepPath)
|
||||
{
|
||||
process_name = buffer;
|
||||
}
|
||||
}
|
||||
return process_name;
|
||||
}
|
||||
|
||||
// Function to a handle an app-specific shortcut remap
|
||||
intptr_t HandleAppSpecificShortcutRemapEvent(LowlevelKeyboardEvent* data) noexcept
|
||||
{
|
||||
// Check if the key event was generated by KeyboardManager to avoid remapping events generated by us.
|
||||
if (data->lParam->dwExtraInfo != POWERKEYS_SHORTCUT_FLAG)
|
||||
{
|
||||
std::wstring process_name = GetCurrentApplication(false);
|
||||
if (process_name.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto it = keyboardManagerState.appSpecificShortcutReMap.find(process_name);
|
||||
if (it != keyboardManagerState.appSpecificShortcutReMap.end())
|
||||
{
|
||||
return HandleShortcutRemapEvent(data, keyboardManagerState.appSpecificShortcutReMap[process_name]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
HHOOK PowerKeys::hook_handle = nullptr;
|
||||
HHOOK PowerKeys::hook_handle_copy = nullptr;
|
||||
PowerKeys* PowerKeys::powerkeys_object_ptr = nullptr;
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
return new PowerKeys();
|
||||
}
|
||||
2
src/modules/keyboardmanager/dll/pch.cpp
Normal file
2
src/modules/keyboardmanager/dll/pch.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "pch.h"
|
||||
#pragma comment(lib, "windowsapp")
|
||||
8
src/modules/keyboardmanager/dll/pch.h
Normal file
8
src/modules/keyboardmanager/dll/pch.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <common/common.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
#include <shlwapi.h>
|
||||
#include <stdexcept>
|
||||
#include <unordered_set>
|
||||
0
src/modules/keyboardmanager/dll/resource.h
Normal file
0
src/modules/keyboardmanager/dll/resource.h
Normal file
29
src/modules/keyboardmanager/dll/trace.cpp
Normal file
29
src/modules/keyboardmanager/dll/trace.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::MyEvent()
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"PowerToyName_MyEvent",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
9
src/modules/keyboardmanager/dll/trace.h
Normal file
9
src/modules/keyboardmanager/dll/trace.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
static void MyEvent();
|
||||
};
|
||||
109
src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp
Normal file
109
src/modules/keyboardmanager/ui/EditKeyboardWindow.cpp
Normal 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;
|
||||
}
|
||||
5
src/modules/keyboardmanager/ui/EditKeyboardWindow.h
Normal file
5
src/modules/keyboardmanager/ui/EditKeyboardWindow.h
Normal 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);
|
||||
239
src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp
Normal file
239
src/modules/keyboardmanager/ui/EditShortcutsWindow.cpp
Normal 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;
|
||||
}
|
||||
6
src/modules/keyboardmanager/ui/EditShortcutsWindow.h
Normal file
6
src/modules/keyboardmanager/ui/EditShortcutsWindow.h
Normal 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);
|
||||
152
src/modules/keyboardmanager/ui/MainWindow.cpp
Normal file
152
src/modules/keyboardmanager/ui/MainWindow.cpp
Normal 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;
|
||||
}
|
||||
6
src/modules/keyboardmanager/ui/MainWindow.h
Normal file
6
src/modules/keyboardmanager/ui/MainWindow.h
Normal 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);
|
||||
134
src/modules/keyboardmanager/ui/PowerKeysUI.vcxproj
Normal file
134
src/modules/keyboardmanager/ui/PowerKeysUI.vcxproj
Normal 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>
|
||||
20
src/modules/keyboardmanager/ui/PowerKeysUI.vcxproj.filters
Normal file
20
src/modules/keyboardmanager/ui/PowerKeysUI.vcxproj.filters
Normal 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>
|
||||
109
src/modules/keyboardmanager/ui/ShortcutControl.cpp
Normal file
109
src/modules/keyboardmanager/ui/ShortcutControl.cpp
Normal 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();
|
||||
}
|
||||
48
src/modules/keyboardmanager/ui/ShortcutControl.h
Normal file
48
src/modules/keyboardmanager/ui/ShortcutControl.h
Normal 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);
|
||||
};
|
||||
4
src/modules/keyboardmanager/ui/packages.config
Normal file
4
src/modules/keyboardmanager/ui/packages.config
Normal 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>
|
||||
1
src/modules/keyboardmanager/ui/pch.cpp
Normal file
1
src/modules/keyboardmanager/ui/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
26
src/modules/keyboardmanager/ui/pch.h
Normal file
26
src/modules/keyboardmanager/ui/pch.h
Normal 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;
|
||||
Reference in New Issue
Block a user