【问题标题】:How to correctly retrieve modifier keys in a WPF KeyDown event?如何在 WPF KeyDown 事件中正确检索修饰键?
【发布时间】:2012-08-25 20:57:53
【问题描述】:

我看到许多答案建议使用Keyboard.Modifiers 来确定@​​987654323@ 事件是否适用于具有修饰符集的键。不幸的是,因为Keyboard.Modifiers 返回修饰符的当前状态(而不是按下键时修饰符的状态),这会导致快速打字者非常烦人的间歇性错误。

具体来说,假设有人按下 Ctrl+A,然后在按下 A 几毫秒后松开 Ctrl。现在假设系统负载很重;密钥处理程序开始执行但被抢占了 50 毫秒。当键处理程序再次执行时,Ctrl 的 当前 状态为“已释放”。键处理程序现在会认为在没有 Ctrl 的情况下按下了“A”,这是错误

类似地,如果快速打字员输入 A、Ctrl+End 并且我的应用程序使用 Keyboard.Modifiers,它最终可能会观察到 Ctrl+A...

在 WinForms 中,KeyDown 事件告诉我 Ctrl 确切的状态,即使在处理事件时它已经释放。如何在 WPF 中获得相同的行为?

编辑:Keyboard.Modifiers 可能实际上并未检索“当前”修饰键,而是检索与当前正在处理的按键消息相关的修饰键。在 WinAPI 中,这是“异步”和非异步键状态函数之间的区别。不幸的是,the documentation 没有提到“当前”的确切含义。如果有人知道,请说出来。

【问题讨论】:

  • 你确定吗?我在 msdn 上找不到任何提示,这将证明你的理论......这真的很奇怪,处理程序参数不包括最初按下的键......如果你绑定到“onkeyDown”并且用户按下CONTROL(按住)然后a,然后释放CONTROL,该事件将被触发2次!首先仅使用“Control”,然后使用 CONTROL+A...有点奇怪--恕我直言,我们可以通过 thread.sleep 轻松解决...我现在必须启动 VS 吗? ;)
  • @TheHe 处理程序参数包括最初按下的,但不包括修饰键信息。在良好的旧 WinAPI 中,修饰键与消息一起传递。在 WinForms 中也会发生同样的情况。该文档实际上警告您不要尝试处理 current 状态;例如,如果应用程序由于任何原因(例如 HDD 抖动)没有响应,则可能会在事后 调用处理程序。

标签: wpf keyboard-shortcuts


【解决方案1】:

由于事件 args 中似乎没有任何修饰符信息,您可以自己在某些字段中跟踪状态并同时处理 KeyUpKeyDown 以相应地更新它们。

例如

private bool ctrl = false;
private void This_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.LeftCtrl) //or switch, also: `LeftCtrl` & `RightCtrl` are treated as separate keys
        ctrl = true;
    //etc..
}

private void This_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Key.LeftCtrl)
        ctrl = false;
    //etc..
}

这是否真的是个好主意我不能说...


如果您想处理关键手势,我建议您使用像 KeyBindings 这样的专用方法,它们应该只在手势发生时触发。对于其他输入,您可能还想查看TextInput,它更抽象并返回输入被翻译成的文本。

【讨论】:

    【解决方案2】:

    很抱歉这个破坏性的答案,但是......

    经过一些研究,我变得很清楚...... 该事件被称为“KeyDown”而不是“KeyCombinationDown”,因此它完全独立于之前按下的任何修饰符......

    其实有一个正确的方法可以实现你的目标: 使用命令模式。

    您定义一个命令(有关 WPF 命令,请参见 google)并向您的应用程序添加一个 KeyBinding,您可以在其中定义将启动命令的键或键/键组合...

    请参见此处的示例: http://msdn.microsoft.com/en-us/library/system.windows.input.keybinding.aspx

    恕我直言,这是唯一的方式,并且在语义上也更优雅。

    (如果此模式在 GENERAL 中不适合您,您可能必须使用带有 pinvoke 的本机 api)。

    干杯。

    【讨论】:

    • 我不认为这是破坏性的。毕竟,你建议了一个替代方案。只是如果你用谷歌搜索,你只会看到“use Keyboard.Modifiers”,因此这个问题......
    • 不幸的是,这有一个副作用(错误?):当按键绑定匹配时,按键按下事件总是标记为已处理,即使命令无法执行。因此,在这种情况下,按键永远不会被转换为 TextInput。
    猜你喜欢
    • 2013-02-02
    • 2010-10-15
    • 2021-12-17
    • 1970-01-01
    • 2011-08-10
    • 2011-05-05
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多