基於MFC對話框的應用程序在響應按鍵消息和熱鍵方面都力不從心,CDialog類的消息循環中去掉了TranslateAccelerator函數,因此不能響應熱鍵;同時由於對話框上可能有很多控件,且默認情況下這些子窗口已經截獲了焦點,因此鍵盤消息已經被控件捕獲了;同時為了實現控件焦點切換和對話框默認行為, VK_TAB、VK_LEFT、VK_RIGHT、VK_UP、VK_DOWN、 VK_RETURN、VK_ESCAPE 等鍵已經被截獲處理,因此對話框沒有控件時仍然不能完全響應按鍵消息。
那么我們怎么讓對話框程序響應按鍵消息呢?答案就是重載PreTranslateMessage,在其中截獲鍵盤消息進行處理。
與按鍵相關的消息大概有4個:WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP,需要說明的包括以下幾點:
1、KEY與SYSKEY消息的區別在於:如果某個按鍵動作的同時,ALT鍵或F10鍵被按下,則發送SYSKEY消息,否則發送KEY消息;
2、某個按鍵動作依次產生WM_KEYDOWN和WM_KEYUP消息;
3、一個按鍵一直按着不放,會按一定間隔時間不斷發送WM_KEYDOWN消息;
4、單鍵動作最好響應WM_KEYUP,組合鍵動作響應WM_KEYDOWN或WM_SYSKEYDOWN;
關於幾個按鍵消息的具體解釋,請參考MSDN。
以下是一個響應單鍵消息的示例代碼:
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_KEYUP) { // 響應keyup消息 if(pMsg->wParam == VK_RETURN) { // 回車 } } return CDialog::PreTranslateMessage(pMsg); }
那么怎樣判斷組合鍵呢?使用GetKeyState函數。示例代碼如下:
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_KEYDOWN) { // 組合鍵響應keydown消息 if( pMsg->wParam == VK_SPACE&& (GetKeyState(VK_SHIFT)& 0x8000)) { // 空格 + Shift } } else if(pMsg->message == WM_SYSKEYDOWN) { // Alt組合鍵響應syskeydown消息 if( pMsg->wParam == 'A'&& (HIWORD(pMsg->lParam) & KF_ALTDOWN)) { // A + Alt } } return CDialog::PreTranslateMessage(pMsg); }
另外,還有GetAsyncKeyState和GetKeyboardState等類似函數,涉及到邏輯按鍵和物理按鍵值等問題,大家可以參考MSDN的說明。