在 WPF 应用程序(或者其他 Windows 应用程序中),为了监听 Alt 键按下,我们可以在 KeyDown
事件中写源码。然而,运行一看,发现并没有什么用。打个断点看下会发现,e.Key
的值是 Key.System
。这就奇怪了,Key.System
是个什么鬼?
一个坑
在WPF应用程序(或者其他 Windows 应用程序中),为了监听 Alt 键按下,我们可以尝试写出这样的代码:
1
2
3
4
5
6
7
PreviewKeyDown += (s, e) =>
{
if (e.Key == Key.LeftAlt || e.Key == Key.RightAlt)
{
// A: 做些什么。
}
};
然而,运行一看,发现并没有什么用。A处的代码根本就没执行。
打个断点看下,会发现,e.Key
的值是 Key.System
。这就奇怪了,Key.System
是个什么鬼?
一段源码
看看 KeyEventArgs
中的源码,我们发现微软写了这么个注释:
1
2
3
4
5
6
7
8
/// <summary>
/// The Key referenced by the event, if the key is not being
/// handled specially.
/// </summary>
public Key Key
{
get {return _key;}
}
如果按键没有被特殊处理, Key
属性才会返回正确的按键。这么说,当我们按下 Alt 键时,其实 Windows 或者 WPF 某一层特殊处理了这个按键。继续阅读源码,发现这个属性后面还有这样一个属性:
1
2
3
4
5
6
7
8
/// <summary>
/// The Key referenced by the event, if the key is going to be
/// processed by an system.
/// </summary>
public Key SystemKey
{
get { return (_key == Key.System) ? _realKey : Key.None;}
}
跟刚刚的 Key
属性相反,这个属性指进行特殊处理时返回的按键。所以,截至这里,问题算是解决了,因为我们可以写出这样的代码:
1
2
3
4
5
6
7
8
PreviewKeyDown += (s, e) =>
{
Key key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftAlt || key == Key.RightAlt)
{
// A: 做些什么。
}
};
一个解释
然而事情肯定不能这样就结束了,微软为什么要设计这样奇怪的机制?为什么 Alt 键要成为特殊系统按键?
经过一系列搜索,我找到了解释:
在 Windows 系统中,Alt 键会被特殊处理。当单独按下 Alt 键,或者按下一个带有 Alt 的组合键时,操作系统会将此事件视为“系统按键”(System keypress)。系统按键与普通按键相比,其处理过程是不同的。
首先,无论是系统按键还是普通按键,Windows都会将这些事件传递给应用程序。如果是普通按键,则传递
WM_KEYDOWN
,但如果是 Alt 键,则传递WM_SYSKEYDOWN
;同理,WM_KEYUP
也会转变成WM_SYSKEYUP
。在 Windows 中(包括 WPF 中),Alt 键如此特殊是为了处理应用程序中那些带有“特殊标记”文字的菜单项(MenuItems)、按钮(Buttons)和其它标签(Labels)的。举个例子,如果按钮的文字内容被设置成“Say _Hi”,那么 Alt+H 快捷键就会被转变成为一次按钮点击(Click)事件。
这段解释可以在这里 https://stackoverflow.com/questions/3099472/previewkeydown-is-not-seeing-alt-modifiers 得到更详细的信息。
本文会经常更新,请阅读原文: https://blog.walterlv.com/wpf/2016/05/09/know-alt-is-pressed-in-key-down-event.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。