mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-24 04:12:32 +08:00
[PowerAccent] Move low-level keyboard hook to c++ (#20190)
* Move llkeyboardhook to c++ * expect.txt * Address PR comment - Resolve namespaces * Address PR comments - CallNextHook and correct char selection * Also unpress the letter key Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
This commit is contained in:
parent
7f8c5c9f0c
commit
7b0f97597d
2
.github/actions/spell-check/expect.txt
vendored
2
.github/actions/spell-check/expect.txt
vendored
@ -742,7 +742,7 @@ HKCC
|
||||
HKCR
|
||||
HKCU
|
||||
hkey
|
||||
hkl
|
||||
HKL
|
||||
HKLM
|
||||
HKPD
|
||||
HKU
|
||||
|
@ -117,6 +117,7 @@
|
||||
"modules\\PowerAccent\\PowerToys.PowerAccent.dll",
|
||||
"modules\\PowerAccent\\PowerToys.PowerAccent.exe",
|
||||
"modules\\PowerAccent\\PowerToys.PowerAccentModuleInterface.dll",
|
||||
"modules\\PowerAccent\\PowerToys.PowerAccentKeyboardService.dll",
|
||||
|
||||
"modules\\PowerRename\\PowerToys.PowerRenameExt.dll",
|
||||
"modules\\PowerRename\\PowerToys.PowerRename.exe",
|
||||
|
@ -447,6 +447,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MeasureToolModuleInterface"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MeasureToolUI", "src\modules\MeasureTool\MeasureToolUI\MeasureToolUI.csproj", "{515554D1-D004-4F7F-A107-2211FC0F6B2C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerAccentKeyboardService", "src\modules\poweraccent\PowerAccentKeyboardService\PowerAccentKeyboardService.vcxproj", "{C97D9A5D-206C-454E-997E-009E227D7F02}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
@ -1790,6 +1792,18 @@ Global
|
||||
{515554D1-D004-4F7F-A107-2211FC0F6B2C}.Release|x86.ActiveCfg = Release|x86
|
||||
{515554D1-D004-4F7F-A107-2211FC0F6B2C}.Release|x86.Build.0 = Release|x86
|
||||
{515554D1-D004-4F7F-A107-2211FC0F6B2C}.Release|x86.Deploy.0 = Release|x86
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Debug|x64.Build.0 = Debug|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Debug|x86.Build.0 = Debug|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Release|x64.ActiveCfg = Release|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Release|x64.Build.0 = Release|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Release|x86.ActiveCfg = Release|x64
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -1941,6 +1955,7 @@ Global
|
||||
{54A93AF7-60C7-4F6C-99D2-FBB1F75F853A} = {7AC943C9-52E8-44CF-9083-744D8049667B}
|
||||
{92C39820-9F84-4529-BC7D-22AAE514D63B} = {7AC943C9-52E8-44CF-9083-744D8049667B}
|
||||
{515554D1-D004-4F7F-A107-2211FC0F6B2C} = {7AC943C9-52E8-44CF-9083-744D8049667B}
|
||||
{C97D9A5D-206C-454E-997E-009E227D7F02} = {0F14491C-6369-4C45-AAA8-135814E66E6B}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -125,7 +125,7 @@
|
||||
|
||||
<?define MeasureToolMicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
|
||||
|
||||
<?define PowerAccentFiles=ControlzEx.dll;GongSolutions.WPF.DragDrop.dll;Ijwhost.dll;MahApps.Metro.dll;Microsoft.Xaml.Behaviors.dll;PowerAccent.Core.dll;PowerAccent.deps.json;PowerAccent.dll;PowerAccent.exe;PowerAccent.runtimeconfig.json;PowerToys.PowerAccentModuleInterface.dll;PowerToys.Interop.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerAccent.deps.json;PowerToys.PowerAccent.dll;PowerToys.PowerAccent.exe;PowerToys.PowerAccent.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;System.IO.Abstractions.dll;System.Management.dll;System.Text.Json.dll;Vanara.Core.dll;Vanara.PInvoke.Gdi32.dll;Vanara.PInvoke.Kernel32.dll;Vanara.PInvoke.Shared.dll;Vanara.PInvoke.User32.dll?>
|
||||
<?define PowerAccentFiles=ControlzEx.dll;GongSolutions.WPF.DragDrop.dll;Ijwhost.dll;MahApps.Metro.dll;Microsoft.Xaml.Behaviors.dll;PowerAccent.Core.dll;PowerAccent.deps.json;PowerAccent.dll;PowerAccent.exe;PowerAccent.runtimeconfig.json;PowerToys.PowerAccentModuleInterface.dll;PowerToys.Interop.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerAccent.deps.json;PowerToys.PowerAccent.dll;PowerToys.PowerAccent.exe;PowerToys.PowerAccent.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;System.IO.Abstractions.dll;System.Management.dll;System.Text.Json.dll;Vanara.Core.dll;Vanara.PInvoke.Gdi32.dll;Vanara.PInvoke.Kernel32.dll;Vanara.PInvoke.Shared.dll;Vanara.PInvoke.User32.dll;PowerToys.PowerAccentKeyboardService.dll;Microsoft.Windows.SDK.NET.dll;WinRT.Runtime.dll?>
|
||||
|
||||
<Product Id="*"
|
||||
Name="PowerToys (Preview)"
|
||||
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace PowerAccent.Core;
|
||||
|
||||
public enum LetterKey
|
||||
{
|
||||
A = User32.VK.VK_A,
|
||||
C = User32.VK.VK_C,
|
||||
E = User32.VK.VK_E,
|
||||
I = User32.VK.VK_I,
|
||||
N = User32.VK.VK_N,
|
||||
O = User32.VK.VK_O,
|
||||
S = User32.VK.VK_S,
|
||||
U = User32.VK.VK_U,
|
||||
Y = User32.VK.VK_Y,
|
||||
}
|
||||
|
||||
public enum TriggerKey
|
||||
{
|
||||
Left = User32.VK.VK_LEFT,
|
||||
Right = User32.VK.VK_RIGHT,
|
||||
Space = User32.VK.VK_SPACE,
|
||||
}
|
@ -1,20 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<CsWinRTIncludes>PowerToys.PowerAccentKeyboardService</CsWinRTIncludes>
|
||||
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
|
||||
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.0" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.3.15" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
<ProjectReference Include="..\PowerAccentKeyboardService\PowerAccentKeyboardService.vcxproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -2,64 +2,67 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using System.Windows;
|
||||
using PowerAccent.Core.Services;
|
||||
using PowerAccent.Core.Tools;
|
||||
using PowerToys.PowerAccentKeyboardService;
|
||||
|
||||
namespace PowerAccent.Core;
|
||||
|
||||
public class PowerAccent : IDisposable
|
||||
{
|
||||
private readonly SettingsService _settingService = new SettingsService();
|
||||
private readonly KeyboardListener _keyboardListener = new KeyboardListener();
|
||||
private readonly SettingsService _settingService;
|
||||
|
||||
private LetterKey? letterPressed;
|
||||
private bool _visible;
|
||||
private char[] _characters = Array.Empty<char>();
|
||||
private int _selectedIndex = -1;
|
||||
private Stopwatch _stopWatch;
|
||||
private bool _triggeredWithSpace;
|
||||
|
||||
public event Action<bool, char[]> OnChangeDisplay;
|
||||
|
||||
public event Action<int, char> OnSelectCharacter;
|
||||
|
||||
private KeyboardListener _keyboardListener;
|
||||
|
||||
public PowerAccent()
|
||||
{
|
||||
_keyboardListener.KeyDown += PowerAccent_KeyDown;
|
||||
_keyboardListener.KeyUp += PowerAccent_KeyUp;
|
||||
_keyboardListener = new KeyboardListener();
|
||||
_keyboardListener.InitHook();
|
||||
_settingService = new SettingsService(_keyboardListener);
|
||||
|
||||
SetEvents();
|
||||
}
|
||||
|
||||
private bool PowerAccent_KeyDown(object sender, KeyboardListener.RawKeyEventArgs args)
|
||||
private void SetEvents()
|
||||
{
|
||||
if (Enum.IsDefined(typeof(LetterKey), (int)args.Key))
|
||||
_keyboardListener.SetShowToolbarEvent(new PowerToys.PowerAccentKeyboardService.ShowToolbar((LetterKey letterKey) =>
|
||||
{
|
||||
_stopWatch = Stopwatch.StartNew();
|
||||
letterPressed = (LetterKey)args.Key;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
ShowToolbar(letterKey);
|
||||
});
|
||||
}));
|
||||
|
||||
_keyboardListener.SetHideToolbarEvent(new PowerToys.PowerAccentKeyboardService.HideToolbar((InputType inputType) =>
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
SendInputAndHideToolbar(inputType);
|
||||
});
|
||||
}));
|
||||
|
||||
_keyboardListener.SetNextCharEvent(new PowerToys.PowerAccentKeyboardService.NextChar((TriggerKey triggerKey) =>
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
ProcessNextChar(triggerKey);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
TriggerKey? triggerPressed = null;
|
||||
if (letterPressed.HasValue)
|
||||
private void ShowToolbar(LetterKey letterKey)
|
||||
{
|
||||
if (Enum.IsDefined(typeof(TriggerKey), (int)args.Key))
|
||||
{
|
||||
triggerPressed = (TriggerKey)args.Key;
|
||||
|
||||
if ((triggerPressed == TriggerKey.Space && _settingService.ActivationKey == PowerAccentActivationKey.LeftRightArrow) ||
|
||||
((triggerPressed == TriggerKey.Left || triggerPressed == TriggerKey.Right) && _settingService.ActivationKey == PowerAccentActivationKey.Space))
|
||||
{
|
||||
triggerPressed = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_visible && letterPressed.HasValue && triggerPressed.HasValue)
|
||||
{
|
||||
// Keep track if it was triggered with space so that it can be typed on false starts.
|
||||
_triggeredWithSpace = triggerPressed.Value == TriggerKey.Space;
|
||||
_visible = true;
|
||||
_characters = WindowsFunctions.IsCapitalState() ? ToUpper(_settingService.GetLetterKey(letterPressed.Value)) : _settingService.GetLetterKey(letterPressed.Value);
|
||||
_characters = WindowsFunctions.IsCapitalState() ? ToUpper(SettingsService.GetDefaultLetterKey(letterKey)) : SettingsService.GetDefaultLetterKey(letterKey);
|
||||
Task.Delay(_settingService.InputTime).ContinueWith(
|
||||
t =>
|
||||
{
|
||||
@ -70,21 +73,47 @@ public class PowerAccent : IDisposable
|
||||
}, TaskScheduler.FromCurrentSynchronizationContext());
|
||||
}
|
||||
|
||||
if (_visible && triggerPressed.HasValue)
|
||||
private void SendInputAndHideToolbar(InputType inputType)
|
||||
{
|
||||
if (_selectedIndex == -1)
|
||||
switch (inputType)
|
||||
{
|
||||
if (triggerPressed.Value == TriggerKey.Left)
|
||||
case InputType.Space:
|
||||
{
|
||||
WindowsFunctions.Insert(' ');
|
||||
break;
|
||||
}
|
||||
|
||||
case InputType.Char:
|
||||
{
|
||||
if (_selectedIndex != -1)
|
||||
{
|
||||
WindowsFunctions.Insert(_characters[_selectedIndex], true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OnChangeDisplay?.Invoke(false, null);
|
||||
_selectedIndex = -1;
|
||||
_visible = false;
|
||||
}
|
||||
|
||||
private void ProcessNextChar(TriggerKey triggerKey)
|
||||
{
|
||||
if (_visible && _selectedIndex == -1)
|
||||
{
|
||||
if (triggerKey == TriggerKey.Left)
|
||||
{
|
||||
_selectedIndex = (_characters.Length / 2) - 1;
|
||||
}
|
||||
|
||||
if (triggerPressed.Value == TriggerKey.Right)
|
||||
if (triggerKey == TriggerKey.Right)
|
||||
{
|
||||
_selectedIndex = _characters.Length / 2;
|
||||
}
|
||||
|
||||
if (triggerPressed.Value == TriggerKey.Space)
|
||||
if (triggerKey == TriggerKey.Space)
|
||||
{
|
||||
_selectedIndex = 0;
|
||||
}
|
||||
@ -100,10 +129,10 @@ public class PowerAccent : IDisposable
|
||||
}
|
||||
|
||||
OnSelectCharacter?.Invoke(_selectedIndex, _characters[_selectedIndex]);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (triggerPressed.Value == TriggerKey.Space)
|
||||
if (triggerKey == TriggerKey.Space)
|
||||
{
|
||||
if (_selectedIndex < _characters.Length - 1)
|
||||
{
|
||||
@ -115,60 +144,17 @@ public class PowerAccent : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
if (triggerPressed.Value == TriggerKey.Left && _selectedIndex > 0)
|
||||
if (triggerKey == TriggerKey.Left && _selectedIndex > 0)
|
||||
{
|
||||
--_selectedIndex;
|
||||
}
|
||||
|
||||
if (triggerPressed.Value == TriggerKey.Right && _selectedIndex < _characters.Length - 1)
|
||||
if (triggerKey == TriggerKey.Right && _selectedIndex < _characters.Length - 1)
|
||||
{
|
||||
++_selectedIndex;
|
||||
}
|
||||
|
||||
OnSelectCharacter?.Invoke(_selectedIndex, _characters[_selectedIndex]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool PowerAccent_KeyUp(object sender, KeyboardListener.RawKeyEventArgs args)
|
||||
{
|
||||
if (Enum.IsDefined(typeof(LetterKey), (int)args.Key))
|
||||
{
|
||||
letterPressed = null;
|
||||
_stopWatch.Stop();
|
||||
if (_visible)
|
||||
{
|
||||
if (_stopWatch.ElapsedMilliseconds < _settingService.InputTime)
|
||||
{
|
||||
/* Debug.WriteLine("Insert before inputTime - " + _stopWatch.ElapsedMilliseconds); */
|
||||
|
||||
// False start, we should output the space if it was the trigger.
|
||||
if (_triggeredWithSpace)
|
||||
{
|
||||
WindowsFunctions.Insert(' ');
|
||||
}
|
||||
|
||||
OnChangeDisplay?.Invoke(false, null);
|
||||
_selectedIndex = -1;
|
||||
_visible = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Debug.WriteLine("Insert after inputTime - " + _stopWatch.ElapsedMilliseconds); */
|
||||
OnChangeDisplay?.Invoke(false, null);
|
||||
if (_selectedIndex != -1)
|
||||
{
|
||||
WindowsFunctions.Insert(_characters[_selectedIndex], true);
|
||||
}
|
||||
|
||||
_selectedIndex = -1;
|
||||
_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Point GetDisplayCoordinates(Size window)
|
||||
@ -182,14 +168,9 @@ public class PowerAccent : IDisposable
|
||||
return Calculation.GetRawCoordinatesFromPosition(position, screen, window);
|
||||
}
|
||||
|
||||
public char[] GetLettersFromKey(LetterKey letter)
|
||||
{
|
||||
return _settingService.GetLetterKey(letter);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_keyboardListener.Dispose();
|
||||
_keyboardListener.UnInitHook();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ namespace PowerAccent.Core.Services;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using PowerToys.PowerAccentKeyboardService;
|
||||
using System.IO.Abstractions;
|
||||
using System.Text.Json;
|
||||
|
||||
@ -16,10 +17,12 @@ public class SettingsService
|
||||
private readonly ISettingsUtils _settingsUtils;
|
||||
private readonly IFileSystemWatcher _watcher;
|
||||
private readonly object _loadingSettingsLock = new object();
|
||||
private KeyboardListener _keyboardListener;
|
||||
|
||||
public SettingsService()
|
||||
public SettingsService(KeyboardListener keyboardListener)
|
||||
{
|
||||
_settingsUtils = new SettingsUtils();
|
||||
_keyboardListener = keyboardListener;
|
||||
ReadSettings();
|
||||
_watcher = Helper.GetFileWatcher(PowerAccentModuleName, "settings.json", () => { ReadSettings(); });
|
||||
}
|
||||
@ -48,7 +51,10 @@ public class SettingsService
|
||||
if (settings != null)
|
||||
{
|
||||
ActivationKey = settings.Properties.ActivationKey;
|
||||
_keyboardListener.UpdateActivationKey((int)ActivationKey);
|
||||
|
||||
InputTime = settings.Properties.InputTime.Value;
|
||||
_keyboardListener.UpdateInputTime(InputTime);
|
||||
switch (settings.Properties.ToolbarPosition.Value)
|
||||
{
|
||||
case "Top center":
|
||||
@ -79,6 +85,8 @@ public class SettingsService
|
||||
Position = Position.Center;
|
||||
break;
|
||||
}
|
||||
|
||||
_keyboardListener.UpdateInputTime(InputTime);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -134,32 +142,27 @@ public class SettingsService
|
||||
}
|
||||
}
|
||||
|
||||
public char[] GetLetterKey(LetterKey letter)
|
||||
{
|
||||
return GetDefaultLetterKey(letter);
|
||||
}
|
||||
|
||||
public static char[] GetDefaultLetterKey(LetterKey letter)
|
||||
{
|
||||
switch (letter)
|
||||
{
|
||||
case LetterKey.A:
|
||||
case LetterKey.VK_A:
|
||||
return new char[] { 'à', 'â', 'á', 'ä', 'ã', 'å', 'æ' };
|
||||
case LetterKey.C:
|
||||
case LetterKey.VK_C:
|
||||
return new char[] { 'ć', 'ĉ', 'č', 'ċ', 'ç', 'ḉ' };
|
||||
case LetterKey.E:
|
||||
case LetterKey.VK_E:
|
||||
return new char[] { 'é', 'è', 'ê', 'ë', 'ē', 'ė', '€' };
|
||||
case LetterKey.I:
|
||||
case LetterKey.VK_I:
|
||||
return new char[] { 'î', 'ï', 'í', 'ì', 'ī' };
|
||||
case LetterKey.N:
|
||||
case LetterKey.VK_N:
|
||||
return new char[] { 'ñ', 'ń' };
|
||||
case LetterKey.O:
|
||||
case LetterKey.VK_O:
|
||||
return new char[] { 'ô', 'ö', 'ó', 'ò', 'õ', 'ø', 'œ' };
|
||||
case LetterKey.S:
|
||||
case LetterKey.VK_S:
|
||||
return new char[] { 'š', 'ß', 'ś' };
|
||||
case LetterKey.U:
|
||||
case LetterKey.VK_U:
|
||||
return new char[] { 'û', 'ù', 'ü', 'ú', 'ū' };
|
||||
case LetterKey.Y:
|
||||
case LetterKey.VK_Y:
|
||||
return new char[] { 'ÿ', 'ý' };
|
||||
}
|
||||
|
||||
|
@ -1,359 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
#pragma warning disable SA1310 // FieldNamesMustNotContainUnderscore
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace PowerAccent.Core.Tools;
|
||||
|
||||
internal class KeyboardListener : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeyboardListener"/> class.
|
||||
/// Creates global keyboard listener.
|
||||
/// </summary>
|
||||
public KeyboardListener()
|
||||
{
|
||||
// We have to store the LowLevelKeyboardProc, so that it is not garbage collected by runtime
|
||||
_hookedLowLevelKeyboardProc = LowLevelKeyboardProc;
|
||||
|
||||
// Set the hook
|
||||
_hookId = InterceptKeys.SetHook(_hookedLowLevelKeyboardProc);
|
||||
|
||||
// Assign the asynchronous callback event
|
||||
hookedKeyboardCallbackAsync = new KeyboardCallbackAsync(KeyboardListener_KeyboardCallbackAsync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fired when any of the keys is pressed down.
|
||||
/// </summary>
|
||||
public event RawKeyEventHandler KeyDown;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when any of the keys is released.
|
||||
/// </summary>
|
||||
public event RawKeyEventHandler KeyUp;
|
||||
|
||||
/// <summary>
|
||||
/// Hook ID
|
||||
/// </summary>
|
||||
private readonly IntPtr _hookId = IntPtr.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the hooked callback in runtime.
|
||||
/// </summary>
|
||||
private readonly InterceptKeys.LowLevelKeyboardProc _hookedLowLevelKeyboardProc;
|
||||
|
||||
/// <summary>
|
||||
/// Event to be invoked asynchronously (BeginInvoke) each time key is pressed.
|
||||
/// </summary>
|
||||
private KeyboardCallbackAsync hookedKeyboardCallbackAsync;
|
||||
|
||||
/// <summary>
|
||||
/// Raw keyevent handler.
|
||||
/// </summary>
|
||||
/// <param name="sender">sender</param>
|
||||
/// <param name="args">raw keyevent arguments</param>
|
||||
public delegate bool RawKeyEventHandler(object sender, RawKeyEventArgs args);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronous callback hook.
|
||||
/// </summary>
|
||||
/// <param name="keyEvent">Keyboard event</param>
|
||||
/// <param name="vkCode">VKCode</param>
|
||||
/// <param name="character">Character</param>
|
||||
private delegate bool KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode, string character);
|
||||
|
||||
/// <summary>
|
||||
/// Actual callback hook.
|
||||
/// <remarks>Calls asynchronously the asyncCallback.</remarks>
|
||||
/// </summary>
|
||||
/// <param name="nCode">VKCode</param>
|
||||
/// <param name="wParam">wParam</param>
|
||||
/// <param name="lParam">lParam</param>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
if (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||
|
||||
wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYUP)
|
||||
{
|
||||
// Captures the character(s) pressed only on WM_KEYDOWN
|
||||
var chars = InterceptKeys.VKCodeToString(
|
||||
(uint)Marshal.ReadInt32(lParam),
|
||||
wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN);
|
||||
|
||||
if (!hookedKeyboardCallbackAsync.Invoke((InterceptKeys.KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), chars))
|
||||
{
|
||||
return (IntPtr)1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return InterceptKeys.CallNextHookEx(_hookId, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events.
|
||||
/// </summary>
|
||||
/// <param name="keyEvent">Keyboard event</param>
|
||||
/// <param name="vkCode">VKCode</param>
|
||||
/// <param name="character">Character as string.</param>
|
||||
private bool KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode, string character)
|
||||
{
|
||||
switch (keyEvent)
|
||||
{
|
||||
// KeyDown events
|
||||
case InterceptKeys.KeyEvent.WM_KEYDOWN:
|
||||
if (KeyDown != null)
|
||||
{
|
||||
return KeyDown.Invoke(this, new RawKeyEventArgs(vkCode, character));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// KeyUp events
|
||||
case InterceptKeys.KeyEvent.WM_KEYUP:
|
||||
if (KeyUp != null)
|
||||
{
|
||||
return KeyUp.Invoke(this, new RawKeyEventArgs(vkCode, character));
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
InterceptKeys.UnhookWindowsHookEx(_hookId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw KeyEvent arguments.
|
||||
/// </summary>
|
||||
public class RawKeyEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// WPF Key of the key.
|
||||
/// </summary>
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
public uint Key;
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
|
||||
/// <summary>
|
||||
/// Convert to string.
|
||||
/// </summary>
|
||||
/// <returns>Returns string representation of this key, if not possible empty string is returned.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return character;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unicode character of key pressed.
|
||||
/// </summary>
|
||||
private string character;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RawKeyEventArgs"/> class.
|
||||
/// Create raw keyevent arguments.
|
||||
/// </summary>
|
||||
/// <param name="vKCode">VKCode</param>
|
||||
/// <param name="character">Character</param>
|
||||
public RawKeyEventArgs(int vKCode, string character)
|
||||
{
|
||||
this.character = character;
|
||||
Key = (uint)vKCode; // User32.MapVirtualKey((uint)VKCode, User32.MAPVK.MAPVK_VK_TO_VSC_EX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Winapi Key interception helper class.
|
||||
/// </summary>
|
||||
internal static class InterceptKeys
|
||||
{
|
||||
public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
|
||||
|
||||
private const int WH_KEYBOARD_LL = 13;
|
||||
|
||||
/// <summary>
|
||||
/// Key event
|
||||
/// </summary>
|
||||
public enum KeyEvent : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Key down
|
||||
/// </summary>
|
||||
WM_KEYDOWN = 256,
|
||||
|
||||
/// <summary>
|
||||
/// Key up
|
||||
/// </summary>
|
||||
WM_KEYUP = 257,
|
||||
|
||||
/// <summary>
|
||||
/// System key up
|
||||
/// </summary>
|
||||
WM_SYSKEYUP = 261,
|
||||
|
||||
/// <summary>
|
||||
/// System key down
|
||||
/// </summary>
|
||||
WM_SYSKEYDOWN = 260,
|
||||
}
|
||||
|
||||
public static IntPtr SetHook(LowLevelKeyboardProc proc)
|
||||
{
|
||||
using (Process curProcess = Process.GetCurrentProcess())
|
||||
using (ProcessModule curModule = curProcess.MainModule)
|
||||
{
|
||||
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, (IntPtr)0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
// Note: Sometimes single VKCode represents multiple chars, thus string.
|
||||
// E.g. typing "^1" (notice that when pressing 1 the both characters appear,
|
||||
// because of this behavior, "^" is called dead key)
|
||||
[DllImport("user32.dll")]
|
||||
#pragma warning disable CA1838 // Éviter les paramètres 'StringBuilder' pour les P/Invoke
|
||||
private static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);
|
||||
#pragma warning restore CA1838 // Éviter les paramètres 'StringBuilder' pour les P/Invoke
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetKeyboardState(byte[] lpKeyState);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint MapVirtualKeyEx(uint uCode, uint uMapType, IntPtr dwhkl);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
private static extern IntPtr GetKeyboardLayout(uint dwLayout);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
private static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern uint GetCurrentThreadId();
|
||||
|
||||
private static uint lastVKCode;
|
||||
private static uint lastScanCode;
|
||||
private static byte[] lastKeyState = new byte[255];
|
||||
|
||||
/// <summary>
|
||||
/// Convert VKCode to Unicode.
|
||||
/// <remarks>isKeyDown is required for because of keyboard state inconsistencies!</remarks>
|
||||
/// </summary>
|
||||
/// <param name="vKCode">VKCode</param>
|
||||
/// <param name="isKeyDown">Is the key down event?</param>
|
||||
/// <returns>String representing single unicode character.</returns>
|
||||
public static string VKCodeToString(uint vKCode, bool isKeyDown)
|
||||
{
|
||||
// ToUnicodeEx needs StringBuilder, it populates that during execution.
|
||||
System.Text.StringBuilder sbString = new System.Text.StringBuilder(5);
|
||||
|
||||
byte[] bKeyState = new byte[255];
|
||||
bool bKeyStateStatus;
|
||||
|
||||
// Gets the current windows window handle, threadID, processID
|
||||
IntPtr currentHWnd = GetForegroundWindow();
|
||||
uint currentProcessID;
|
||||
uint currentWindowThreadID = GetWindowThreadProcessId(currentHWnd, out currentProcessID);
|
||||
|
||||
// This programs Thread ID
|
||||
uint thisProgramThreadId = GetCurrentThreadId();
|
||||
|
||||
// Attach to active thread so we can get that keyboard state
|
||||
if (AttachThreadInput(thisProgramThreadId, currentWindowThreadID, true))
|
||||
{
|
||||
// Current state of the modifiers in keyboard
|
||||
bKeyStateStatus = GetKeyboardState(bKeyState);
|
||||
|
||||
// Detach
|
||||
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could not attach, perhaps it is this process?
|
||||
bKeyStateStatus = GetKeyboardState(bKeyState);
|
||||
}
|
||||
|
||||
// On failure we return empty string.
|
||||
if (!bKeyStateStatus)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Gets the layout of keyboard
|
||||
IntPtr hkl = GetKeyboardLayout(currentWindowThreadID);
|
||||
|
||||
// Maps the virtual keycode
|
||||
uint lScanCode = MapVirtualKeyEx(vKCode, 0, hkl);
|
||||
|
||||
// Keyboard state goes inconsistent if this is not in place. In other words, we need to call above commands in UP events also.
|
||||
if (!isKeyDown)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// Converts the VKCode to unicode
|
||||
const uint wFlags = 1 << 2; // If bit 2 is set, keyboard state is not changed (Windows 10, version 1607 and newer)
|
||||
int relevantKeyCountInBuffer = ToUnicodeEx(vKCode, lScanCode, bKeyState, sbString, sbString.Capacity, wFlags, hkl);
|
||||
|
||||
string ret = string.Empty;
|
||||
|
||||
switch (relevantKeyCountInBuffer)
|
||||
{
|
||||
// dead key
|
||||
case -1:
|
||||
break;
|
||||
|
||||
case 0:
|
||||
break;
|
||||
|
||||
// Single character in buffer
|
||||
case 1:
|
||||
ret = sbString.Length == 0 ? string.Empty : sbString[0].ToString();
|
||||
break;
|
||||
|
||||
// Two or more (only two of them is relevant)
|
||||
case 2:
|
||||
default:
|
||||
ret = sbString.ToString().Substring(0, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
// Save these
|
||||
lastScanCode = lScanCode;
|
||||
lastVKCode = vKCode;
|
||||
lastKeyState = (byte[])bKeyState.Clone();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -27,9 +27,10 @@ internal static class WindowsFunctions
|
||||
}
|
||||
|
||||
// Letter
|
||||
var inputsInsert = new User32.INPUT[1]
|
||||
var inputsInsert = new User32.INPUT[]
|
||||
{
|
||||
new User32.INPUT { type = User32.INPUTTYPE.INPUT_KEYBOARD, ki = new User32.KEYBDINPUT { wVk = 0, dwFlags = User32.KEYEVENTF.KEYEVENTF_UNICODE, wScan = c } },
|
||||
new User32.INPUT { type = User32.INPUTTYPE.INPUT_KEYBOARD, ki = new User32.KEYBDINPUT { wVk = 0, dwFlags = User32.KEYEVENTF.KEYEVENTF_UNICODE | User32.KEYEVENTF.KEYEVENTF_KEYUP, wScan = c } },
|
||||
};
|
||||
var temp2 = User32.SendInput((uint)inputsInsert.Length, inputsInsert, sizeof(User32.INPUT));
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<Nullable>disable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
@ -26,6 +26,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="gong-wpf-dragdrop" Version="3.1.1" />
|
||||
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\..\..\Version.props" />
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Nullable>disable</Nullable>
|
||||
@ -12,6 +12,9 @@
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<AssemblyName>PowerToys.PowerAccent</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
|
@ -0,0 +1,207 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardListener.h"
|
||||
#include "KeyboardListener.g.cpp"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
KeyboardListener::KeyboardListener() :
|
||||
m_toolbarVisible(false), m_triggeredWithSpace(false)
|
||||
{
|
||||
s_instance = this;
|
||||
LoggerHelpers::init_logger(L"PowerAccent", L"PowerAccentKeyboardService", "PowerAccent");
|
||||
}
|
||||
|
||||
void KeyboardListener::InitHook()
|
||||
{
|
||||
#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED)
|
||||
const bool hook_disabled = IsDebuggerPresent();
|
||||
#else
|
||||
const bool hook_disabled = false;
|
||||
#endif
|
||||
|
||||
if (!hook_disabled)
|
||||
{
|
||||
s_llKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
|
||||
if (!s_llKeyboardHook)
|
||||
{
|
||||
DWORD errorCode = GetLastError();
|
||||
show_last_error_message(L"SetWindowsHookEx", errorCode, L"PowerToys - PowerAccent");
|
||||
auto errorMessage = get_last_error_message(errorCode);
|
||||
Logger::error(errorMessage.has_value() ? errorMessage.value() : L"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::UnInitHook()
|
||||
{
|
||||
if (s_llKeyboardHook)
|
||||
{
|
||||
if (UnhookWindowsHookEx(s_llKeyboardHook))
|
||||
{
|
||||
s_llKeyboardHook = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardListener::SetShowToolbarEvent(ShowToolbar showToolbarEvent)
|
||||
{
|
||||
m_showToolbarCb = [trigger = std::move(showToolbarEvent)](LetterKey key) {
|
||||
trigger(key);
|
||||
};
|
||||
}
|
||||
|
||||
void KeyboardListener::SetHideToolbarEvent(HideToolbar hideToolbarEvent)
|
||||
{
|
||||
m_hideToolbarCb = [trigger = std::move(hideToolbarEvent)](InputType inputType) {
|
||||
trigger(inputType);
|
||||
};
|
||||
}
|
||||
|
||||
void KeyboardListener::SetNextCharEvent(NextChar nextCharEvent)
|
||||
{
|
||||
m_nextCharCb = [trigger = std::move(nextCharEvent)](TriggerKey triggerKey) {
|
||||
trigger(triggerKey);
|
||||
};
|
||||
}
|
||||
|
||||
void KeyboardListener::UpdateActivationKey(int32_t activationKey)
|
||||
{
|
||||
m_settings.activationKey = static_cast<PowerAccentActivationKey>(activationKey);
|
||||
}
|
||||
|
||||
void KeyboardListener::UpdateInputTime(int32_t inputTime)
|
||||
{
|
||||
m_settings.inputTime = std::chrono::milliseconds(inputTime);
|
||||
}
|
||||
|
||||
bool KeyboardListener::OnKeyDown(KBDLLHOOKSTRUCT info) noexcept
|
||||
{
|
||||
if (std::find(std::begin(letters), end(letters), static_cast<LetterKey>(info.vkCode)) != end(letters))
|
||||
{
|
||||
m_stopwatch.reset();
|
||||
letterPressed = static_cast<LetterKey>(info.vkCode);
|
||||
}
|
||||
|
||||
UINT triggerPressed = 0;
|
||||
if (letterPressed != LetterKey::None)
|
||||
{
|
||||
if (std::find(std::begin(triggers), end(triggers), static_cast<TriggerKey>(info.vkCode)) != end(triggers))
|
||||
{
|
||||
triggerPressed = info.vkCode;
|
||||
|
||||
if ((triggerPressed == VK_SPACE && m_settings.activationKey == PowerAccentActivationKey::LeftRightArrow) ||
|
||||
((triggerPressed == VK_LEFT || triggerPressed == VK_RIGHT) && m_settings.activationKey == PowerAccentActivationKey::Space))
|
||||
{
|
||||
triggerPressed = 0;
|
||||
Logger::info(L"Reset trigger key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_toolbarVisible && letterPressed != LetterKey::None && triggerPressed)
|
||||
{
|
||||
Logger::info(L"Show toolbar. Letter: %d, Trigger: %d", letterPressed, triggerPressed);
|
||||
|
||||
// Keep track if it was triggered with space so that it can be typed on false starts.
|
||||
m_triggeredWithSpace = triggerPressed == VK_SPACE;
|
||||
m_toolbarVisible = true;
|
||||
|
||||
m_showToolbarCb(letterPressed);
|
||||
}
|
||||
|
||||
if (m_toolbarVisible && triggerPressed)
|
||||
{
|
||||
if (triggerPressed == VK_LEFT)
|
||||
{
|
||||
Logger::info(L"Next toolbar position - left");
|
||||
m_nextCharCb(TriggerKey::Left);
|
||||
}
|
||||
else if (triggerPressed == VK_RIGHT)
|
||||
{
|
||||
Logger::info(L"Next toolbar position - right");
|
||||
m_nextCharCb(TriggerKey::Right);
|
||||
}
|
||||
else if (triggerPressed == VK_SPACE)
|
||||
{
|
||||
Logger::info(L"Next toolbar position - space");
|
||||
m_nextCharCb(TriggerKey::Space);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KeyboardListener::OnKeyUp(KBDLLHOOKSTRUCT info) noexcept
|
||||
{
|
||||
if (std::find(std::begin(letters), end(letters), static_cast<LetterKey>(info.vkCode)) != end(letters))
|
||||
{
|
||||
letterPressed = LetterKey::None;
|
||||
|
||||
if (m_toolbarVisible)
|
||||
{
|
||||
if (m_stopwatch.elapsed() < m_settings.inputTime)
|
||||
{
|
||||
Logger::info(L"Activation too fast. Do nothing.");
|
||||
|
||||
// False start, we should output the space if it was the trigger.
|
||||
if (m_triggeredWithSpace)
|
||||
{
|
||||
m_hideToolbarCb(InputType::Space);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hideToolbarCb(InputType::None);
|
||||
}
|
||||
|
||||
m_toolbarVisible = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Logger::info(L"Hide toolbar event and input char");
|
||||
|
||||
m_hideToolbarCb(InputType::Char);
|
||||
|
||||
m_toolbarVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LRESULT KeyboardListener::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
{
|
||||
if (nCode == HC_ACTION && s_instance != nullptr)
|
||||
{
|
||||
KBDLLHOOKSTRUCT* key = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
switch (wParam)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
{
|
||||
if (s_instance->OnKeyDown(*key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
{
|
||||
if (s_instance->OnKeyUp(*key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "KeyboardListener.g.h"
|
||||
|
||||
#include <spdlog/stopwatch.h>
|
||||
|
||||
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
|
||||
{
|
||||
enum PowerAccentActivationKey
|
||||
{
|
||||
LeftRightArrow,
|
||||
Space,
|
||||
Both,
|
||||
};
|
||||
|
||||
struct PowerAccentSettings
|
||||
{
|
||||
PowerAccentActivationKey activationKey{ PowerAccentActivationKey::Both };
|
||||
std::chrono::milliseconds inputTime{ 200 };
|
||||
};
|
||||
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener>
|
||||
{
|
||||
using LetterKey = winrt::PowerToys::PowerAccentKeyboardService::LetterKey;
|
||||
using TriggerKey = winrt::PowerToys::PowerAccentKeyboardService::TriggerKey;
|
||||
using InputType = winrt::PowerToys::PowerAccentKeyboardService::InputType;
|
||||
|
||||
KeyboardListener();
|
||||
|
||||
void KeyboardListener::InitHook();
|
||||
void KeyboardListener::UnInitHook();
|
||||
void SetShowToolbarEvent(ShowToolbar showToolbarEvent);
|
||||
void SetHideToolbarEvent(HideToolbar hideToolbarEvent);
|
||||
void SetNextCharEvent(NextChar NextCharEvent);
|
||||
|
||||
void UpdateActivationKey(int32_t activationKey);
|
||||
void UpdateInputTime(int32_t inputTime);
|
||||
|
||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
private:
|
||||
bool OnKeyDown(KBDLLHOOKSTRUCT info) noexcept;
|
||||
bool OnKeyUp(KBDLLHOOKSTRUCT info) noexcept;
|
||||
|
||||
static inline KeyboardListener* s_instance;
|
||||
HHOOK s_llKeyboardHook = nullptr;
|
||||
bool m_toolbarVisible;
|
||||
PowerAccentSettings m_settings;
|
||||
std::function<void(LetterKey)> m_showToolbarCb;
|
||||
std::function<void(InputType)> m_hideToolbarCb;
|
||||
std::function<void(TriggerKey)> m_nextCharCb;
|
||||
bool m_triggeredWithSpace;
|
||||
spdlog::stopwatch m_stopwatch;
|
||||
|
||||
static inline const std::vector<LetterKey> letters = { LetterKey::VK_A,
|
||||
LetterKey::VK_C,
|
||||
LetterKey::VK_E,
|
||||
LetterKey::VK_I,
|
||||
LetterKey::VK_N,
|
||||
LetterKey::VK_O,
|
||||
LetterKey::VK_S,
|
||||
LetterKey::VK_U,
|
||||
LetterKey::VK_Y };
|
||||
LetterKey letterPressed{};
|
||||
|
||||
static inline const std::vector<TriggerKey> triggers = { TriggerKey::Right, TriggerKey::Left, TriggerKey::Space };
|
||||
};
|
||||
}
|
||||
|
||||
namespace winrt::PowerToys::PowerAccentKeyboardService::factory_implementation
|
||||
{
|
||||
struct KeyboardListener : KeyboardListenerT<KeyboardListener, implementation::KeyboardListener>
|
||||
{
|
||||
};
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
namespace PowerToys
|
||||
{
|
||||
namespace PowerAccentKeyboardService
|
||||
{
|
||||
enum LetterKey
|
||||
{
|
||||
None = 0x00,
|
||||
VK_A = 0x41,
|
||||
VK_C = 0x43,
|
||||
VK_E = 0x45,
|
||||
VK_I = 0x49,
|
||||
VK_N = 0x4E,
|
||||
VK_O = 0x4F,
|
||||
VK_S = 0x53,
|
||||
VK_U = 0x55,
|
||||
VK_Y = 0x59
|
||||
};
|
||||
|
||||
enum TriggerKey
|
||||
{
|
||||
Right = 0x27, // VK_RIGHT
|
||||
Left = 0x25, // VK_LEFT
|
||||
Space = 0x20 // VK_SPACE
|
||||
};
|
||||
|
||||
enum InputType
|
||||
{
|
||||
None,
|
||||
Space,
|
||||
Char
|
||||
};
|
||||
|
||||
[version(1.0), uuid(37197089-5438-4479-af57-30ab3f3c8be4)] delegate void ShowToolbar(LetterKey key);
|
||||
[version(1.0), uuid(8eb79d6b-1826-424f-9fbc-af21ae19725e)] delegate void HideToolbar(InputType inputType);
|
||||
[version(1.0), uuid(db72d45c-a5a2-446f-bdc1-506e9121764a)] delegate void NextChar(TriggerKey inputSpace);
|
||||
|
||||
[default_interface] runtimeclass KeyboardListener {
|
||||
KeyboardListener();
|
||||
void InitHook();
|
||||
void UnInitHook();
|
||||
void SetShowToolbarEvent(event ShowToolbar showToolbarEvent);
|
||||
void SetHideToolbarEvent(event HideToolbar hideToolbarEvent);
|
||||
void SetNextCharEvent(event NextChar nextCharEvent);
|
||||
void UpdateActivationKey(Int32 activationKey);
|
||||
void UpdateInputTime(Int32 inputTime);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
EXPORTS
|
||||
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
@ -0,0 +1,40 @@
|
||||
#include <windows.h>
|
||||
#include "resource.h"
|
||||
#include "../../../common/version/version.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
#include "winres.h"
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION FILE_VERSION
|
||||
PRODUCTVERSION PRODUCT_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
|
||||
BEGIN
|
||||
VALUE "CompanyName", COMPANY_NAME
|
||||
VALUE "FileDescription", FILE_DESCRIPTION
|
||||
VALUE "FileVersion", FILE_VERSION_STRING
|
||||
VALUE "InternalName", INTERNAL_NAME
|
||||
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||
VALUE "OriginalFilename", ORIGINAL_FILENAME
|
||||
VALUE "ProductName", PRODUCT_NAME
|
||||
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
|
||||
END
|
||||
END
|
@ -0,0 +1,139 @@
|
||||
<?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.220418.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<CppWinRTOptimized>true</CppWinRTOptimized>
|
||||
<CppWinRTRootNamespaceAutoMerge>true</CppWinRTRootNamespaceAutoMerge>
|
||||
<CppWinRTGenerateWindowsMetadata>true</CppWinRTGenerateWindowsMetadata>
|
||||
<MinimalCoreWin>true</MinimalCoreWin>
|
||||
<ProjectGuid>{c97d9a5d-206c-454e-997e-009e227d7f02}</ProjectGuid>
|
||||
<ProjectName>PowerAccentKeyboardService</ProjectName>
|
||||
<RootNamespace>PowerToys.PowerAccentKeyboardService</RootNamespace>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>false</AppContainerApplication>
|
||||
<AppxPackage>false</AppxPackage>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<WindowsTargetPlatformVersion Condition=" '$(WindowsTargetPlatformVersion)' == '' ">10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="PropertySheet.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToys.PowerAccentKeyboardService</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerAccent\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
|
||||
<!--Temporarily disable cppwinrt heap enforcement to work around xaml compiler generated std::shared_ptr use -->
|
||||
<AdditionalOptions Condition="'$(CppWinRTHeapEnforcement)'==''">/DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
|
||||
<ModuleDefinitionFile>PowerAccentKeyboardService.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="KeyboardListener.h">
|
||||
<DependentUpon>KeyboardListener.idl</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardListener.cpp">
|
||||
<DependentUpon>KeyboardListener.idl</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="KeyboardListener.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="PowerAccentKeyboardService.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\version\version.vcxproj">
|
||||
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PowerAccentKeyboardService.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.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.220418.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.220418.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>accd3aa8-1ba0-4223-9bbe-0c431709210b</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Generated Files">
|
||||
<UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Midl Include="KeyboardListener.idl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PowerAccentKeyboardService.def" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="PropertySheet.props" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PowerAccentKeyboardService.rc">
|
||||
<Filter>Resources</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<!--
|
||||
To customize common C++/WinRT project properties:
|
||||
* right-click the project node
|
||||
* expand the Common Properties item
|
||||
* select the C++/WinRT property page
|
||||
|
||||
For more advanced scenarios, and complete documentation, please see:
|
||||
https://github.com/Microsoft/cppwinrt/tree/master/nuget
|
||||
-->
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup />
|
||||
</Project>
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.220418.1" targetFramework="native" />
|
||||
</packages>
|
@ -0,0 +1 @@
|
||||
#include "pch.h"
|
4
src/modules/poweraccent/PowerAccentKeyboardService/pch.h
Normal file
4
src/modules/poweraccent/PowerAccentKeyboardService/pch.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <unknwn.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
@ -0,0 +1,13 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by PowerToys.MeasureToolCore.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys PowerAccentKeyboardService"
|
||||
#define INTERNAL_NAME "PowerToys.PowerAccentKeyboardService"
|
||||
#define ORIGINAL_FILENAME "PowerToys.PowerAccentKeyboardService.dll"
|
||||
|
||||
// Non-localizable
|
||||
//////////////////////////////
|
@ -25,7 +25,7 @@
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\PowerAccent\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup >
|
||||
<PropertyGroup>
|
||||
<TargetName>PowerToys.$(ProjectName)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user