如何在WPF KeyDown事件中正确检索修饰键?

时间:2012-08-25 20:57:54

标签: wpf keyboard-shortcuts

我已经看到了许多答案,建议使用Keyboard.Modifiers来确定KeyDown事件是否适用于具有修饰符集的键。不幸的是,因为Keyboard.Modifiers返回修饰符的当前状态(而不是按下键时修饰符的状态),这会给快速打字员带来一个非常恼人的间歇性错误。< / p>

具体来说,想象某人按下Ctrl + A,并在按下A后几毫秒才释放Ctrl。现在想象一下系统负载很重;密钥处理程序开始执行但被抢占了50ms。当密钥处理程序再次执行时,Ctrl的当前状态为“已释放”。密钥处理程序现在认为没有Ctrl就按下“A”,这是

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

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

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

2 个答案:

答案 0 :(得分:2)

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

e.g。

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,并返回输入转换为的文本。

答案 1 :(得分:2)

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

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

实际上有一种正确的方法来实现你的目标: 使用命令模式。

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

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

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

(如果这种模式在GENERAL中不适合你,你可能必须使用带有pinvoke的原生api。)

欢呼声。