C# 关键事件:ProcessCmdKey
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10468200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Key Events: ProcessCmdKey
提问by 3Pi
I am trying to get some keyboard response happening on a little test Windows Form Application, and I have a rough solution, which is to override ProcessCmdKey. However, there are several issues I am encountering, and inconsistencies I am finding.
我试图在一个小的测试 Windows 窗体应用程序上获得一些键盘响应,我有一个粗略的解决方案,即覆盖 ProcessCmdKey。但是,我遇到了几个问题,并且发现了不一致之处。
Different Events:Is there a way to tell, in the arguments ref Message msg, Keys keyData, whether the even is a KeyDown, a KeyUp, or a KeyPress?
不同的事件:有没有办法在参数ref Message msg, Keys keyData中判断偶数是 KeyDown、KeyUp 还是 KeyPress?
KeyPress:Everywhere I have looked says that KeyPress, ie a repeated keyboard input, only happens for character keys, which the arrow keys are not. However, the event handler is being called as frequently, and in the same mannor/with the same behaviour, for the arrow keys as character keys. Is this in face a KeyPress event, or is it something else?
KeyPress:我看过的所有地方都说 KeyPress,即重复的键盘输入,只发生在字符键上,而箭头键则不然。但是,对于箭头键和字符键,事件处理程序被频繁地调用,并且以相同的方式/具有相同的行为。这是面对 KeyPress 事件,还是别的什么?
I would ideally like a way to handle, at form level, all keyboard events without letting them get passed to the controls on the form. However, all the documentation sufficiently confused me, and missed key points, so that I have not been able to complete this.
理想情况下,我想要一种在表单级别处理所有键盘事件而不让它们传递给表单上的控件的方法。但是,所有的文档都让我感到困惑,并且错过了关键点,以至于我无法完成此操作。
Help on any of these topics is appreciated. Thanks!
对任何这些主题的帮助表示赞赏。谢谢!
采纳答案by Frédéric Hamidi
The Messagestructure passed to ProcessCmdKey()contains the WINAPI message number in its Msgproperty:
传递给ProcessCmdKey()的Message结构在其Msg属性中包含 WINAPI 消息编号:
WM_KEYDOWNis0x100(256),WM_KEYUPis0x101(257),WM_CHAR(roughly equivalent toKeyPress) is0x102(258),WM_SYSKEYDOWNis0x104(260),WM_SYSKEYUPis0x105(261).
WM_KEYDOWN是0x100(256),WM_KEYUP是0x101(257),WM_CHAR(大致相当于KeyPress)是0x102(258),WM_SYSKEYDOWN是0x104(260),WM_SYSKEYUP是0x105(261)。
Concerning your question about KeyPress, it is true that non-character keys such as the arrow keys do not generate WM_CHARmessages internally, but they do generate WM_KEYDOWN, and that message is also sent multiple times for repeated input.
关于您关于 的问题KeyPress,箭头键等非字符键确实不会在WM_CHAR内部生成消息,但它们确实会生成WM_KEYDOWN,并且该消息也会多次发送以进行重复输入。
Also note that I'm not sure ProcessCmdKey()is the right method to achieve what you want. The documentation describes it as only handling main menu command keys and MDI accelerators, which may only be a subset of the keys you want to catch. You might want to override ProcessKeyPreview()instead, which handles all the keyboard messages received by child controls.
另请注意,我不确定ProcessCmdKey()是否是实现您想要的正确方法。该文档将其描述为仅处理main menu command keys and MDI accelerators,这可能只是您想要捕获的键的子集。您可能希望改写ProcessKeyPreview(),它处理子控件接收到的所有键盘消息。
回答by Hans Passant
Overriding ProcessCmdKey in your form is explicitly intended to allow you to implement custom short-cut keystroke handling beyond the built-in mnemonic handling in buttons and menu items.
在您的表单中覆盖 ProcessCmdKey 明确旨在允许您实现自定义快捷键处理超出按钮和菜单项中的内置助记符处理。
It is only ever called on a key down event, beforethe control with the focus gets the KeyDown event and regardless of which client control has the focus. So not associated with KeyUp and not with KeyPress. You return true from your override when you recognize the key, after executing the shortcut function. This prevents the key from being processed any further, it won't generate any KeyDown/Press/Up events.
它只在键按下事件上调用,在具有焦点的控件获得 KeyDown 事件之前,无论哪个客户端控件具有焦点。所以与 KeyUp 和 KeyPress 无关。在执行快捷功能后,当您识别出该键时,您会从覆盖中返回 true。这可以防止键被进一步处理,它不会生成任何 KeyDown/Press/Up 事件。
It is very rare to use the msgargument of the method, the msg.Msg value will only ever be WM_KEYDOWN or WM_SYSKEYDOWN with the latter message produced when the user held down the Alt key. Which you don't care about since you can always get if from the keyDataargument. Like this:
很少使用该方法的msg参数,msg.Msg 值将永远是 WM_KEYDOWN 或 WM_SYSKEYDOWN,当用户按住 Alt 键时会产生后一条消息。你不关心,因为你总是可以从keyData参数中得到 if 。像这样:
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);
}
The other modifiers you might want to check with the | operator as used here are Keys.Shift and Keys.Control. So (Keys.Shift | Keys.Control | Keys.F1) checks for Ctrl+Shift+F1. You caninterpret the msg data when you want to do something unusual like checking for repeating keys. Check the MSDN docs for the WM_KEYDOWN notification. The msg.LParam value contains a bunch of info about the key stroke.
您可能想要检查的其他修饰符 | 此处使用的运算符是 Keys.Shift 和 Keys.Control。所以 (Keys.Shift | Keys.Control | Keys.F1) 检查 Ctrl+Shift+F1。当您想做一些不寻常的事情时,例如检查重复键,您可以解释 msg 数据。检查 WM_KEYDOWN 通知的 MSDN 文档。msg.LParam 值包含一堆关于击键的信息。
Note that you only get virtualkeys in this method. Keys.F is the F key on the English keyboard layout but not necessarily the same letter for the key in the same location on the user's layout. Favor the function keys to avoid a documentation headache.
请注意,您只能在此方法中获得虚拟密钥。Keys.F 是英文键盘布局上的 F 键,但不一定是用户布局上相同位置的键的相同字母。优先使用功能键以避免文档问题。
Key repetition is a feature of the keyboard controller and is not limited to typing keys. The arrow and function keys will certainly repeat when held down. You want to ignore KeyPress in this scenario. But if you assign a shortcut key for a key that's also a typing key (like Keys.F) then you want to alwaysalso check for a modifier key so you don't break controls like TextBox.
按键重复是键盘控制器的一项功能,不限于键入按键。按住箭头键和功能键肯定会重复。在这种情况下,您想忽略 KeyPress。但是,如果您为一个也是键入键的键(如 Keys.F)指定一个快捷键,那么您还希望始终检查修饰键,这样您就不会破坏像 TextBox 这样的控件。
Last but not least, don't forget about the built-in support for mnemonics in the button and menu item controls. Writing their Text property like &OKproduces a self-documenting shortcut without needing any code. Operated by the user, in this example, by typing Alt+O.
最后但并非最不重要的一点是,不要忘记按钮和菜单项控件中对助记符的内置支持。编写他们的 Text 属性就像&OK生成一个自我记录的快捷方式,而无需任何代码。由用户操作,在本例中,通过键入 Alt+O。

