当对话框或formview界面上有控件时,由于焦点在控件上,因此wm_char,wm_keydown等按键消息会被控件捕获,而导致对话框或formview无法接受该类按键消息。这时候通常的解决方法是在对话框类或者forview类中重写PreTranslateMessage函数,该函数是在消息路由前的预处理函数,(经测试)该函数能够在控件处理按键消息之前对消息进行预处理。通常的解决思路是在该函数中将消息路由途径改变,即将消息的窗口句柄属性改变,由于该函数捕获到的按键消息是发送给控件的,因此pMsg->hwnd是控件的窗口句柄,只需将该句柄替换为formview或对话框的句柄即可。代码如下:
BOOL CMyDialog::PreTranslateMessage(MSG* pMsg) { if (pMsg->message==WM_CHAR) { pMsg->hwnd=m_hWnd; return FALSE; } return CFormView::PreTranslateMessage(pMsg); }
另外,也可以在该函数中直接对wm_char或者wm_keydown进行相应的处理,通过pMsg->wparam参数即可判断是那个键被按下,对于wm_char消息,该参数保存的是按键的ASCII码;对于wm_keydown消息,该参数保存的按键的虚拟键值。
引用:
1、http://blog.sina.com.cn/s/blog_a9fa057b0101gz1p.html
2、http://bbs.csdn.net/topics/30336368
另外,还有一种更加彻底的方法,该方法不太常用,因为对消息路由途径的更改比第一种方法更大,所以可能会由于对底层不了解造成一些处理的遗漏(我只是试验成功,但具体有什么不好的影响还没发现)。该方法的主要思路为在app类中截获按键消息,由于我的程序使用了大量的第三方库和一些特殊的按钮类造成即使是formview类或者对话框类的PreTranslateMessage函数也无法捕捉到按键消息,我猜想可能是被一些控件截获,具体原因还未找出。这个时候可以重写app类的ProcessMessageFilter函数,该函数是对任何发送给应用程序消息进行过滤,所以会在任何控件或窗口截获到消息之前得到消息。我对于该函数的处理方法如下:
BOOL CMyApp::ProcessMessageFilter(int code, LPMSG lpMsg) { // TODO: 在此添加专用代码和/或调用基类 CMainFrame* pWnd=(CMainFrame*)m_pMainWnd; CMyView* pView=(CMyView*)pWnd->GetActiveView(); if (lpMsg->message==WM_KEYDOWN) { ::PostMessageA(pView->m_hWnd,WM_CHAR,(WPARAM)'a',(LPARAM)0); } return CWinApp::ProcessMessageFilter(code, lpMsg); }