Keyboard.IsKeyDown触发应用缩放及Ctrl键检测替代方案咨询
问题背景
Windows .NET Framework的PresentationCore.dll存在可稳定复现的DPI缩放bug:当显示器缩放比例设置大于100%时,调用如下WPF内置按键检测代码会触发应用缩放异常:
if (System.Windows.Input.Keyboard.IsKeyDown (System.Windows.Input.Key.LeftCtrl)) { // 业务逻辑代码 }
异常具体表现为窗口尺寸出现非预期缩放,但文本渲染尺寸保持原有大小,该问题已在.NET Framework 4.5.2、4.7.2、4.8多个版本验证复现。
替代实现方案
以下两种实现均可绕过PresentationCore的问题逻辑,稳定检测Ctrl键按下状态,不会触发缩放异常:
- 基于Win32原生API实现(无额外依赖,推荐)
直接调用user32.dll提供的GetKeyState接口读取按键硬件状态,不经过WPF输入层的问题逻辑,实现代码如下:
调用时直接使用using System.Runtime.InteropServices; internal static class KeyboardStateHelper { private const int VK_LCONTROL = 0xA2; private const int VK_RCONTROL = 0xA3; private const int KEY_PRESSED_BIT = 0x8000; [DllImport("user32.dll")] private static extern short GetKeyState(int virtualKeyCode); /// <summary> /// 检测左/右Ctrl键是否处于按下状态 /// </summary> public static bool IsCtrlPressed() { bool leftCtrlDown = (GetKeyState(VK_LCONTROL) & KEY_PRESSED_BIT) != 0; bool rightCtrlDown = (GetKeyState(VK_RCONTROL) & KEY_PRESSED_BIT) != 0; return leftCtrlDown || rightCtrlDown; } }KeyboardStateHelper.IsCtrlPressed()替换原有的Keyboard.IsKeyDown(Key.LeftCtrl)判断即可。 - 基于WinForms ModifierKeys属性实现
若项目允许引入WinForms程序集依赖,可直接使用System.Windows.Forms提供的按键状态检测属性,实现逻辑更简单:注意:使用前需要手动为项目添加
System.Windows.Forms程序集引用using System.Windows.Forms; internal static class KeyboardStateHelper { public static bool IsCtrlPressed() { return (Control.ModifierKeys & Keys.Control) == Keys.Control; } }
补充说明:在DPI高于100%的WPF应用中,除了Ctrl键检测外,尽量避免在DPI变更、窗口尺寸变更的高频回调中调用PresentationCore.dll提供的Keyboard类静态检测方法,部分场景下除了缩放异常外还会触发输入状态缓存错乱的问题。
内容的提问来源于stack exchange,提问作者Gunnar Olaussen
相关产品推荐
相关产品推荐

