15

我试图在一个小小的测试 Windows 窗体应用程序上发生一些键盘响应,我有一个粗略的解决方案,即覆盖 ProcessCmdKey。但是,我遇到了几个问题,并且发现了不一致的地方。

不同的事件:有没有办法在参数ref Message msg, Keys keyData中判断偶数是 KeyDown、KeyUp 还是 KeyPress?

KeyPress:我看过的所有地方都说KeyPress,即重复的键盘输入,只发生在字符键上,而箭头键则没有。但是,对于箭头键和字符键,事件处理程序被频繁调用,并且以相同的方式/具有相同的行为。这是面对 KeyPress 事件,还是别的什么?

理想情况下,我希望有一种方法可以在表单级别处理所有键盘事件,而不会让它们传递给表单上的控件。然而,所有的文档都让我很困惑,错过了关键点,以至于我一直无法完成。

对任何这些主题的帮助表示赞赏。谢谢!

4

2 回答 2

51

在您的表单中覆盖 ProcessCmdKey 明确旨在允许您在按钮和菜单项中的内置助记符处理之外实现自定义快捷键处理。

仅在具有焦点的控件获得 KeyDown 事件之前,无论哪个客户端控件具有焦点,都只会在按键按下事件上调用它。因此与 KeyUp 和 KeyPress 无关。在执行快捷方式功能后,当您识别出该键时,您会从覆盖中返回 true。这可以防止密钥被进一步处理,它不会生成任何 KeyDown/Press/Up 事件。

很少使用该方法的msg参数,msg.Msg 值只会是 WM_KEYDOWN 或 WM_SYSKEYDOWN,当用户按住 Alt 键时会产生后一个消息。你不关心的,因为你总是可以从keyData参数中得到。像这样:

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
        if (keyData == (Keys.Alt | Keys.F)) {
            // Alt+F pressed
            doSomething();
            return true;
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }

您可能要使用 | 检查的其他修饰符 此处使用的运算符是 Keys.Shift 和 Keys.Control。因此 (Keys.Shift | Keys.Control | Keys.F1) 检查 Ctrl+Shift+F1。当您想做一些不寻常的事情(例如检查重复键)时,您可以解释 msg 数据。检查 MSDN 文档以获取 WM_KEYDOWN 通知。msg.LParam 值包含一堆关于击键的信息。

请注意,您只能在此方法中获得虚拟键。Keys.F 是英文键盘布局上的 F 键,但不一定是用户布局上相同位置的键的相同字母。偏爱功能键以避免文档问题。

按键重复是键盘控制器的一项功能,不仅限于键入按键。按住时箭头和功能键肯定会重复。在这种情况下,您想忽略 KeyPress。但是,如果您为同时也是键入键的键(如 Keys.F)分配快捷键,那么您希望始终检查修饰键,以免破坏 TextBox 等控件。

最后但同样重要的是,不要忘记按钮和菜单项控件中对助记符的内置支持。编写它们的 Text 属性就像&OK生成一个自记录的快捷方式,而不需要任何代码。由用户操作,在本例中,通过键入 Alt+O。

于 2012-05-06T13:41:12.777 回答
18

传递给ProcessCmdKey()Message结构在其Msg属性中包含 WINAPI 消息编号:

  • WM_KEYDOWN0x100(256),
  • WM_KEYUP0x101(257),
  • WM_CHAR(大致相当于KeyPress)是0x102(258),
  • WM_SYSKEYDOWN0x104(260),
  • WM_SYSKEYUP0x105(261)。

关于您的问题KeyPress,确实,诸如箭头键之类的非字符键不会在WM_CHAR内部生成消息,但它们确实会生成WM_KEYDOWN,并且该消息也会多次发送以进行重复输入。

另请注意,我不确定ProcessCmdKey()是否是实现您想要的正确方法。文档将其描述为仅处理main menu command keys and MDI accelerators,它可能只是您要捕获的键的子集。您可能想要改写ProcessKeyPreview(),它处理子控件接收到的所有键盘消息。

于 2012-05-06T07:14:28.700 回答