Fix ctrl alt key in Keyboard Hook and Advanced Paste custom actions

This commit is contained in:
Noraa Junker
2025-12-02 21:19:19 +01:00
parent 231f59c7a9
commit 43e9959df4
3 changed files with 84 additions and 30 deletions

View File

@@ -21,6 +21,11 @@ namespace RunnerV2.Helpers
private static void OnKeyDown(int key)
{
if ((VirtualKey)key == VirtualKey.RightMenu && _ctrlState)
{
_ctrlAltState = true;
}
switch ((VirtualKey)key)
{
case VirtualKey.Control:
@@ -41,6 +46,20 @@ namespace RunnerV2.Helpers
case VirtualKey.LeftWindows:
case VirtualKey.RightWindows:
_winState = true;
break;
default:
if (OnKeyboardEvent(new HotkeySettings
{
Code = key,
Ctrl = _ctrlState,
Alt = _altState,
Shift = _shiftState,
Win = _winState,
}))
{
return;
}
break;
}
@@ -70,16 +89,15 @@ namespace RunnerV2.Helpers
case VirtualKey.RightWindows:
_winState = false;
break;
default:
OnKeyboardEvent(new HotkeySettings
{
Code = key,
Ctrl = _ctrlState,
Alt = _altState,
Shift = _shiftState,
Win = _winState,
});
break;
}
// Correctly release Ctrl key if Ctrl+Alt (AltGr) was used.
if (_ctrlAltState && (VirtualKey)key == VirtualKey.RightMenu)
{
_ctrlAltState = false;
_ctrlState = false;
SendSingleKeyboardInput((short)VirtualKey.LeftControl, (uint)NativeKeyboardHelper.KeyEventF.KeyUp);
}
SendSingleKeyboardInput((short)key, (uint)NativeKeyboardHelper.KeyEventF.KeyUp);
@@ -89,6 +107,7 @@ namespace RunnerV2.Helpers
private static bool _altState;
private static bool _shiftState;
private static bool _winState;
private static bool _ctrlAltState;
private static bool _isActive;
@@ -114,8 +133,10 @@ namespace RunnerV2.Helpers
_keyboardHooks.Remove(moduleName);
}
private static void OnKeyboardEvent(HotkeySettings pressedHotkey)
private static bool OnKeyboardEvent(HotkeySettings pressedHotkey)
{
bool shortcutHandled = false;
foreach (var moduleHooks in _keyboardHooks.Values)
{
foreach (var (hotkeySettings, action) in moduleHooks)
@@ -123,9 +144,12 @@ namespace RunnerV2.Helpers
if (hotkeySettings == pressedHotkey)
{
action();
shortcutHandled = true;
}
}
}
return shortcutHandled;
}
public static void Start()
@@ -147,7 +171,12 @@ namespace RunnerV2.Helpers
// Function to send a single key event to the system which would be ignored by the hotkey control.
private static void SendSingleKeyboardInput(short keyCode, uint keyStatus)
{
NativeKeyboardHelper.INPUT inputShift = new()
if (IsExtendedVirtualKey(keyCode))
{
keyStatus |= (uint)NativeKeyboardHelper.KeyEventF.ExtendedKey;
}
NativeKeyboardHelper.INPUT input = new()
{
type = NativeKeyboardHelper.INPUTTYPE.INPUT_KEYBOARD,
data = new NativeKeyboardHelper.InputUnion
@@ -161,9 +190,30 @@ namespace RunnerV2.Helpers
},
};
NativeKeyboardHelper.INPUT[] inputs = [inputShift];
NativeKeyboardHelper.INPUT[] inputs = [input];
_ = NativeMethods.SendInput(1, inputs, NativeKeyboardHelper.INPUT.Size);
}
private static bool IsExtendedVirtualKey(short vk)
{
return vk switch
{
0xA5 => true, // VK_RMENU (Right Alt - AltGr)
0xA3 => true, // VK_RCONTROL
0x2D => true, // VK_INSERT
0x2E => true, // VK_DELETE
0x23 => true, // VK_END
0x24 => true, // VK_HOME
0x21 => true, // VK_PRIOR (Page Up)
0x22 => true, // VK_NEXT (Page Down)
0x25 => true, // VK_LEFT
0x26 => true, // VK_UP
0x27 => true, // VK_RIGHT
0x28 => true, // VK_DOWN
0x90 => true, // VK_NUMLOCK
_ => false,
};
}
}
}

View File

@@ -5,10 +5,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Forms;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using PowerToys.GPOWrapper;
@@ -64,18 +64,21 @@ namespace RunnerV2.ModuleInterfaces
Process.Start("WinUI3Apps\\PowerToys.AdvancedPaste.exe", $"{Environment.ProcessId} {ipcName}");
}
public void OnSettingsChanged()
public void OnSettingsChanged(string settingsKind, JsonElement jsonProperties)
{
PopulateShortcuts();
}
public void PopulateShortcuts()
{
ArgumentNullException.ThrowIfNull(_ipc);
if (_ipc is null)
{
_ipc = new TwoWayPipeMessageIPCManaged(string.Empty, @"\\.\pipe\PowerToys.AdvancedPaste", (_) => { });
}
Shortcuts.Clear();
AdvancedPasteSettings settings = new SettingsUtils().GetSettings<AdvancedPasteSettings>();
AdvancedPasteSettings settings = new SettingsUtils().GetSettingsOrDefault<AdvancedPasteSettings>(Name);
Shortcuts.Add((settings.Properties.AdvancedPasteUIShortcut, () =>
_ipc.Send("ShowUI")
));
@@ -84,10 +87,17 @@ namespace RunnerV2.ModuleInterfaces
Shortcuts.Add((settings.Properties.PasteAsJsonShortcut, () => _ipc.Send("PasteJson")));
HotkeyAccessor[] hotkeyAccessors = settings.GetAllHotkeyAccessors();
for (int i = 4; i < hotkeyAccessors.Length; i++)
int additionalActionsCount = settings.Properties.AdditionalActions.GetAllActions().Count() - 2;
for (int i = 0; i < additionalActionsCount; i++)
{
HotkeyAccessor hotkeyAccessor = hotkeyAccessors[i];
Shortcuts.Add((hotkeyAccessor.Value, () => _ipc.Send($"CustomPaste {i}")));
int scopedI = i;
Shortcuts.Add((hotkeyAccessors[4 + i].Value, () => _ipc.Send("AdditionalAction " + (3 + scopedI))));
}
for (int i = 4 + additionalActionsCount; i < hotkeyAccessors.Length; i++)
{
int scopedI = i;
Shortcuts.Add((hotkeyAccessors[i].Value, () => _ipc.Send("CustomAction " + (scopedI - 5 - additionalActionsCount))));
}
}

View File

@@ -25,6 +25,7 @@ using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using PowerToys.Interop;
using Windows.Graphics;
using WinRT;
using WinUIEx;
using static AdvancedPaste.Helpers.NativeMethods;
@@ -44,13 +45,6 @@ namespace AdvancedPaste
public ETWTrace EtwTrace { get; private set; } = new ETWTrace();
private static readonly Dictionary<string, PasteFormats> AdditionalActionIPCKeys =
typeof(PasteFormats).GetFields()
.Where(field => field.IsLiteral)
.Select(field => (Format: (PasteFormats)field.GetRawConstantValue(), field.GetCustomAttribute<PasteFormatMetadataAttribute>().IPCKey))
.Where(field => field.IPCKey != null)
.ToDictionary(field => field.IPCKey, field => field.Format);
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
private readonly OptionsViewModel viewModel;
@@ -187,14 +181,14 @@ namespace AdvancedPaste
}
else
{
if (!AdditionalActionIPCKeys.TryGetValue(messageParts[1], out PasteFormats pasteFormat))
if (!int.TryParse(messageParts[1], CultureInfo.InvariantCulture, out int customActionId))
{
Logger.LogWarning($"Unexpected additional action type {messageParts[1]}");
}
else
{
await ShowWindow();
await viewModel.ExecutePasteFormatAsync(pasteFormat, PasteActionSource.GlobalKeyboardShortcut);
await viewModel.ExecutePasteFormatAsync((PasteFormats)customActionId, PasteActionSource.GlobalKeyboardShortcut);
}
}
}