KeyDown/PreviewKeyDown事件中监听Alt键按下

一个坑

在WPF应用程序(或者其他Windows应用程序中),为了监听Alt键按下,我们可以尝试写出这样的代码:

PreviewKeyDown += (s, e) =>
{
    if (e.Key == Key.LeftAlt || e.Key == Key.RightAlt)
    {
        // A: 做些什么。
    }
};

然而,运行一看,发现并没有什么用。A处的代码根本就没执行。

打个断点看下,会发现, e.Key 的值是 Key.System 。这就奇怪了, Key.System 是个什么鬼?

一段源码

看看KeyEventArgs中的源码,我们发现微软写了这么个注释:

/// <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某一层特殊处理了这个按键。继续阅读源码,发现这个属性后面还有这样一个属性:

/// <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 属性相反,这个属性指进行特殊处理时返回的按键。所以,截至这里,问题算是解决了,因为我们可以写出这样的代码:

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)事件。

这段解释可以在这里http://stackoverflow.com/questions/3099472/previewkeydown-is-not-seeing-alt-modifiers得到更详细的信息。

原文地址:https://www.cnblogs.com/walterlv/p/previewkeydown-is-not-seeing-alt-modifiers.html