我有一个带有主窗口的应用程序,它有一堆控件,包括空格键,它由一个名为onSpacebar()
的简单方法处理。在那个主窗口的顶部,我有一个持久的无模式对话框。
无论对话框是否具有焦点,或者主窗口具有焦点,我都需要空格键的行为方式完全相同。
此对话框由DialogProc支持,如下所示:
BOOL CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_NOTIFY:
std::cout<< "WM_NOTIFY" <<std::endl;
switch(LOWORD(wParam))
{
// which component caused the message?
case COMP_TREE:
if(((LPNMHDR)lParam)->code == NM_DBLCLK){
onDoubleclk()
}
//...
break;
// other components...
}
break;
case WM_CLOSE:
// the dialog can only be closed when the whole app is closed
//EndDialog(hDlg, IDCANCEL);
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
从我收集的内容中,我应该在DialogProc中调用我的onSpacebar()
方法,类似于我如何处理双击。我可以看到按下空格键时对话框收到WM_NOTIFY
(短语WM_NOTIFY被打印到cout),但我似乎无法将空格键通知与对话框收到的其他众多通知区分开来。 / p>
请告诉我如何识别特定WM_NOTIFY
是对空格键按键的响应。
答案 0 :(得分:5)
WM_NOTIFY
消息不是窗口处理按键事件的标准方式。按下某个键后,您的窗口应该会收到WM_KEYDOWN
,WM_KEYUP
和可能的WM_CHAR
消息。 WM_NOTIFY
完全用于完全不同的目的:将消息从公共控件传递到其父窗口。
因此,您在收到按键时收到WM_NOTIFY
消息的事实是一件非常不寻常的事情,当您了解焦点的工作原理时(这是解决问题的关键)你的终极问题。)
在Windows中,一次只能聚焦一个窗口,当前聚焦的窗口是接收所有键盘输入的窗口。因此,如果对话框具有焦点,它将接收按键通知。如果该对话框上的子控件具有焦点,则 it (不是其父对话框)将接收按键通知。并且在对话框上有一个可聚焦的子控件,它将始终优先于其父对话框接收焦点,因此它也将始终接收按键通知。
因此,对您好奇的WM_NOTIFY
消息的可能解释是,对话框中的common controls之一具有焦点,它正在接收空格键按下事件,并且在处理之后,传递给以WM_NOTIFY
消息的形式通知其父窗口(您的对话框)。如您所想,这不是检测空格键被按下的可靠方法。
相反,您需要找出一些方法来捕获按键通知,然后才会将发送到焦点控件。为此,您需要修改应用程序的消息循环,以便在调用DispatchMessage
或IsDialogMessage
之前捕获WM_KEYDOWN
或WM_KEYUP
条消息。
onSpacebar
函数并指示该消息已被处理,从而阻止其传递并由另一个窗口处理。由于这种方法在全局范围内过滤掉空格键按下,因此它解决了窃取按键的对话框中的子控件和其他无模式对话框的问题。但是,你需要小心,因为它很容易搞砸,因此用户根本无法使用键盘导航对话框。
更重要的是,我认为处理空格键的按键的想法从根本上是有缺陷的。某些常见控件的逻辑基本上要求他们处理空格键的按下。例如,考虑一个文本框:如果您在全局级别过滤掉空格键的所有按下,则用户将永远无法在文本框中键入空格。如果您坚持处理空格键,则需要检查全局处理程序中的焦点控件,如果它是文本框(或您希望接收空格的其他常用控件),则将其传递给;否则,自己处理。
老实说,我要做的是选择一个更独特的组合键(比如,我不知道, Ctrl + Space )并将其设置为加速器。据推测,您的全局消息循环已经通过调用TranslateAccelerator
函数处理加速键,因此将为您处理所有脏工作。甚至不需要代码 - 只需编辑项目中的加速器资源文件即可完成所有操作。键盘加速器上的MSDN文档是here,但您可能更容易在Visual C ++上查阅自己喜爱的书籍。