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

Rom*_*kov 7 wpf keyboard-shortcuts

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

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

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

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

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

H.B*_*.B. 2

由于事件参数中似乎没有任何修饰符信息,您可以自己跟踪某些字段中的状态并处理这两个字段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..
}
Run Code Online (Sandbox Code Playgroud)

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


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