天天看點

【MFC】基于對話框的鍵盤響應

VC中鍵盤事件處理主要是通過對相應的消息的響應,這些事件有如:WM_CHAR、

WM_KEYDOWN、WM_KEYUP等他們分别對應OnChar、OnKeyDown、OnKeyUp消息處

理函數;當然在有些時候我們也可能需要用到對PreTranslateMessage函數的重載。

從這些事件的名稱我們可以看出WM_CHAR表示字元事件,WM_KEYDOWN表示鍵

盤的鍵被按下時事件,而WM_KEYUP則表示鍵盤的鍵被放開時的事件;我們在鍵盤上按

下某個鍵時系統先調用OnKeyDown函數接着調用OnChar函數最後調用OnKeyUp函數;

這些消息函數的原形如下:

afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);

afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);

nChar代表虛拟鍵,nRepCnt代表重複次數;而對于nFlags則有點麻煩但大多數時候我們不

管這個參數,nFlags的具體意義請參考MSDN相關文檔。

在大多數時候我們隻要用到OnChar、OnKeyDown、OnKeyUp這些消息處理函數就夠

了,但有時候我們會發理這些函數并不會被調用(特别是對話框程式)這時我們就必需去重

載PreTranslateMessage函數;些函數的使用也比較簡單但在處理組合按鍵時我們必需用到相

鍵盤消息被攔截而得不到正常響應,其中的關鍵就是Run函數對消息的預處理。在Run

函數中,調用了函數CWinThread::PumpMessage,就是利用這一函數,MFC實作了對消息

的分流,使得消息沿着MFC對各種消息規定的路線流動,直到被正确響應。函數PumpMessage調用了函數CWinThread::PreTranslateMessage對消息進行處理,如

果該函數不對消息進行處理,則調用API函數TranslateMessage函數将虛拟鍵消息轉換為字

符消息并調用DispatchMessage分發消息給視窗處理程式。在對話框中,程式用

CWinThread::PreTranslateMessage函數處理了鍵盤消息,是以對話框程式是否要響應鍵盤消

息,将完全由CWinThread::PreTranslateMessage函數來決定了。

在CWnd及其派生類的成員函數PreTranslateMessage函數是一個虛函數,可以通過重

載來改變其處理過程。在預設情況下,沒有重載這一函數。

例子1:

在VC6中建立基于對話框的工程,在Class view中找到相應的對話框類單擊右鍵,在右鍵

菜單中選擇Add Virtual Fuction...項,然後找到PreTranslateMessage虛函數進行加載。相應的

代碼中如下:

BOOL CTestDlg::PreTranslateMessage(MSG* pMsg) 

{

    // TODO: Add your specialized code here and/or call the base class

    //判斷是否是按鍵消息

    if( pMsg->message == WM_KEYDOWN )

    {

        MessageBox("有鍵被按下");

        //判斷具體鍵

        switch( pMsg->wParam )

        { 

          case VK_LEFT://按下左鍵

              MessageBox(_T("左"));

              return TRUE;

              break; 

          case VK_RIGHT://按下右鍵

              MessageBox(_T("右"));

              return TRUE;

               break;   

          case VK_UP://按下上鍵

              MessageBox(_T("上"));

              return TRUE;

              break; 

         case VK_DOWN://按下下鍵

              MessageBox(_T("下"));

              return TRUE;

              break; 

        default: 

              return TRUE;

              break; 

      }

      return CDialog::PreTranslateMessage(pMsg);

    }

}

///

将return CDialog::PreTranslateMessage(pMsg);放在if裡将導緻程式無法正常關閉!

最起碼應該放到if的外面去。

下面是一個用WASD這幾個按鍵控制滑塊的代碼:(用→這樣的按鈕控制時老是出問題)

其中m_X,和m_Y為滑塊的控制變量

BOOL CTestDlg::PreTranslateMessage(MSG *pMsg)

{

 if (pMsg->wParam == 'W')

 {

  Y = m_Y.GetPos();

  Y++;

  m_Y.SetPos(Y);

 }

 else if (pMsg->wParam == 'S')

 {

  Y = m_Y.GetPos();

  Y--;

  m_Y.SetPos(Y);

 }

 else if (pMsg->wParam == 'A')

 {

  X = m_X.GetPos();

  X--;

  m_X.SetPos(X);

 }

 else if (pMsg->wParam == 'D')

 {

  X = m_X.GetPos();

  X++;

  m_X.SetPos(X);

 }

 return CDialog::PreTranslateMessage(pMsg);

}

當然也可以分開寫:

   1.先添加PreTranslateMessage(pMsg);裡面隻加入:

     return   CDialog::PreTranslateMessage(pMsg);

     即:

     BOOL CKEYDlg::PreTranslateMessage(MSG *pMsg)

    {

       // TODO: Add your specialized code here and/or call the base class

       return CDialog::PreTranslateMessage(pMsg);

     }

   2.然後添加單獨添加WM_KEYDOWN等消息:

   void CKEYDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

   {

      // TODO: Add your message handler code here and/or call default

      if (nChar == VK_SPACE)

      {

        MessageBox("空格鍵被按下","提示!");

       }

     CDialog::OnKeyDown(nChar, nRepCnt, nFlags);

    }

另附上 虛拟碼:

   後面括号的是對應的ASCII碼

   ESC鍵         VK_ESCAPE (27) 

   Enter鍵:      VK_RETURN (13) 

   TAB鍵:       VK_TAB (9) 

   Caps Lock鍵: VK_CAPITAL (20) 

   Shift鍵:     VK_SHIFT ($10) 

   Ctrl鍵:      VK_CONTROL (17) 

   Alt鍵:       VK_MENU (18) 

   空格鍵:      VK_SPACE ($20/32) 

   倒退鍵:      VK_BACK (8) 

   左徽标鍵:    VK_LWIN (91) 

   右徽标鍵:    VK_LWIN (92) 

   滑鼠右鍵快捷鍵:VK_APPS (93)

    Insert鍵:   VK_INSERT (45) 

    Home鍵:     VK_HOME (36) 

    Page Up:    VK_PRIOR (33) 

    PageDown:   VK_NEXT (34) 

    End鍵:      VK_END (35) 

    Delete鍵:   VK_DELETE (46)

方向鍵(←): VK_LEFT (37) 

方向鍵(↑): VK_UP (38) 

方向鍵(→): VK_RIGHT (39) 

方向鍵(↓): VK_DOWN (40)

F1鍵: VK_F1 (112) 

F2鍵: VK_F2 (113) 

F3鍵: VK_F3 (114) 

F4鍵: VK_F4 (115) 

F5鍵: VK_F5 (116) 

F6鍵: VK_F6 (117) 

F7鍵: VK_F7 (118) 

F8鍵: VK_F8 (119) 

F9鍵: VK_F9 (120) 

F10鍵: VK_F10 (121) 

F11鍵: VK_F11 (122) 

F12鍵: VK_F12 (123)

Num Lock鍵: VK_NUMLOCK (144) 

小鍵盤0: VK_NUMPAD0 (96) 

小鍵盤1: VK_NUMPAD0 (97) 

小鍵盤2: VK_NUMPAD0 (98) 

小鍵盤3: VK_NUMPAD0 (99) 

小鍵盤4: VK_NUMPAD0 (100) 

小鍵盤5: VK_NUMPAD0 (101) 

小鍵盤6: VK_NUMPAD0 (102) 

小鍵盤7: VK_NUMPAD0 (103) 

小鍵盤8: VK_NUMPAD0 (104) 

小鍵盤9: VK_NUMPAD0 (105) 

小鍵盤.: VK_DECIMAL (110) 

小鍵盤*: VK_MULTIPLY (106) 

小鍵盤+: VK_MULTIPLY (107) 

小鍵盤-: VK_SUBTRACT (109) 

小鍵盤/: VK_DIVIDE (111)

Pause Break鍵: VK_PAUSE (19) 

Scroll Lock鍵: VK_SCROLL (145) 

字母的虛拟碼直接使用ASCII碼即可

另外需要注意:

VK_?? 定義在 winuser.h 中,而對于字母123...,ABC..卻沒有VK_A,VK_B...

MFC中恰恰沒有VK_0 -- VK_9,VK_A --VK_Z ,倒是有VK_NUMPAD0   --VK_NUMPAD9

在delphi,BCB,JAVA中都有。

當然,你可以直接定義,但是打開winuser.h會找到:

是以直接用'A'就行了!