关键事件:ProcessCmdKey

时间:2012-05-06 04:51:17

标签: c# .net winforms

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

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

KeyPress:我看过的任何地方都说KeyPress,即重复的键盘输入,只发生在字符键上,箭头键不是。但是,事件处理程序被频繁地调用,并且在相同的mannor /具有相同的行为中,箭头键作为字符键。这是面对KeyPress事件,还是其他什么?

理想情况下,我希望能够在表单级别处理所有键盘事件,而不会让它们传递给表单上的控件。但是,所有文档都让我感到困惑,并且错过了关键点,因此我无法完成此任务。

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

2 个答案:

答案 0 :(得分:44)

在表单中覆盖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这样的控件。 / p>

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

答案 1 :(得分:12)

传递给MessageProcessCmdKey()结构在其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(),它处理子控件接收的所有键盘消息。