基於MFC對話框的應用程序在響應按鍵消息和熱鍵方面都力不從心,CDialog類的消息循環中去掉了TranslateAccelerator函數,因此不能響應熱鍵;同時由於對話框上可能有很多控件,且默認情況下這些子窗口已經截獲了焦點,因此鍵盤消息已經被控件捕獲了;同時為了實現控件焦點切換和對話框默認行為, VK_TAB、VK_LEFT、VK_RIGHT、VK_UP、VK_DOWN、 VK_RETURN、VK_ESCAPE 等鍵已經被截獲處理,因此對話框沒有控件時仍然不能完全響應按鍵消息。
關於熱鍵的響應請參考這篇文章:Keyboard messages/accelerators handling in MFC dialog based applications。 那麼我們怎麼讓對話框程序響應按鍵消息呢?答案就是重載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的說明。