【问题标题】:Key Events: ProcessCmdKey关键事件:ProcessCmdKey
【发布时间】:2012-05-06 04:51:16
【问题描述】:

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

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

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

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

感谢您就任何这些主题提供帮助。谢谢!

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    在您的表单中覆盖 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 值包含一堆关于击键的信息。

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

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

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

    【讨论】:

      【解决方案2】:

      传递给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(),它会处理子控件收到的所有键盘消息。

      【讨论】:

        猜你喜欢
        • 2014-08-10
        • 1970-01-01
        • 2011-12-18
        • 1970-01-01
        • 2013-02-06
        • 2016-06-06
        • 2018-03-17
        • 1970-01-01
        • 2013-09-08
        相关资源
        最近更新 更多