[英]GetKeyState() false positive only on German keyboard layouts
When using GetKeyState
to check whether a key is pressed, I'm getting a strange false positive only on German keyboard layouts.当使用
GetKeyState
检查是否按下某个键时,我只会在德语键盘布局上得到一个奇怪的误报。 The check is within a low-level keyboard hook.检查在低级键盘挂钩内。
The specific key that seems to be causing issues is RMenu
(the right Alt key).似乎导致问题的特定键是
RMenu
(右 Alt 键)。
In the hook proc below, pressing RMenu+P
on a US keyboard will populate the pressedKeys
dictionary with Menu
, RMenu
, P
.在下面的钩子过程中,在美式键盘上按
RMenu+P
将使用Menu
、 RMenu
、 P
填充pressedKeys
字典。 Whereas pressing the same keybinding on a German layout will populate the dict with Menu
, RMenu
, ControlKey
, LControlKey
, P
(where ControlKey
, LControlKey
are falsely reported as down).而在德语布局上按下相同的键绑定将使用
Menu
、 RMenu
、 ControlKey
、 LControlKey
、 P
填充字典(其中ControlKey
、 LControlKey
被错误地报告为关闭)。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
internal static class Program
{
private const uint WM_KEYDOWN = 0x100;
private const uint WM_SYSKEYDOWN = 0x104;
[STAThread]
private static void Main()
{
_ = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, KeybindingHookProc, Process.GetCurrentProcess().MainModule.BaseAddress, 0);
// `SetWindowsHookEx` requires a message loop within the thread that is executing the code.
Application.Run();
}
private static IntPtr KeybindingHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
var shouldPassThrough = nCode != 0 || !((uint)wParam == WM_KEYDOWN || (uint)wParam == WM_SYSKEYDOWN);
// If nCode is less than zero, the hook procedure must pass on the hook notification.
if (shouldPassThrough)
return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
var inputEvent =
(LowLevelKeyboardInputEvent)Marshal.PtrToStructure(lParam, typeof(LowLevelKeyboardInputEvent));
var pressedKeys = new Dictionary<Keys, bool>
{
[inputEvent.Key] = true
};
foreach (var key in Enum.GetValues<Keys>())
{
if (IsKeyDown(key))
pressedKeys[key] = true;
}
// Check for arbitrary keybinding (Right alt + P):
// !!!!!
if (!pressedKeys.ContainsKey(Keys.P) && !pressedKeys.ContainsKey(Keys.LMenu))
return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
Debug.WriteLine("Keybinding triggered!");
return new IntPtr(1);
}
private static bool IsKeyDown(Keys key)
{
return (GetKeyState(key) & 0x8000) == 0x8000;
}
public enum HookType
{
WH_KEYBOARD_LL = 13,
}
public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr SetWindowsHookEx(HookType hookType, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx([Optional] IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern short GetKeyState(Keys nVirtKey);
[StructLayout(LayoutKind.Sequential)]
public struct LowLevelKeyboardInputEvent
{
public int VirtualCode;
public Keys Key => (Keys)VirtualCode;
public int HardwareScanCode;
public int Flags;
public int TimeStamp;
public IntPtr AdditionalInformation;
}
}
Is there any way to avoid this strange behavior?有什么办法可以避免这种奇怪的行为? Is this a bug?
这是一个错误吗?
As @HansPassant mentioned, the AltGr key is present on certain keyboard layouts, like German and US International.正如@HansPassant 所提到的,AltGr 键出现在某些键盘布局上,例如德语和美国国际键盘。 It generates both Control and Alt when pressed.
按下时它会同时生成 Control 和 Alt。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.