C語言控制台窗口圖形界面編程(七):鍵盤事件


<知識分享>

輸入事件中的鍵盤事件通常有字符事件和按鍵事件,這些事件的附帶信息構成了鍵盤輸入的信息,而想要讀取這些信息,是要通過API函數ReadConsoleInput來獲取的,函數原型如下:


  1. BOOL ReadConsoleInput(              //讀取輸入信息  
  2.     HANDLE hConsoleInput,           //句柄  
  3.     PINPUT_RECORD lpBuffer,         //輸入事件結構體的指針  
  4.     DWORD nLength,                  //要讀取的記錄數  
  5.     LPDWORD lpNumberOfEventsRead    //用來接受成功讀取記錄數的指針  
  6. );  //如果該函數成功調用,返回非零值  
  7. //輸入事件結構體的指針可以是結構體數組的首地址,這樣就可以一次性讀取多個記錄數。  

 

       下面介紹幾個和讀取鍵盤輸入事件有關的結構體,各結構體原型如下:


  1. typedef struct _INPUT_RECORD    //輸入事件結構體  
  2. {  
  3.     WORD  EventType;    //事件類型  
  4.     union  
  5.     {  
  6.         KEY_EVENT_RECORD          KeyEvent;     //按鍵事件  
  7.         MOUSE_EVENT_RECORD        MouseEvent;   //鼠標事件  
  8.         WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;  
  9.         MENU_EVENT_RECORD         MenuEvent;  
  10.         FOCUS_EVENT_RECORD        FocusEvent;  
  11.     } Event;    //具體的事件  
  12. } INPUT_RECORD;  
  13. /* 
  14. 其中事件類型EventType的值有5種 
  15. KEY_EVENT                   代表Event包含一個KEY_EVENT_RECODE結構體 
  16. MOUSE_EVENT                 代表Event包含一個MOUSE_EVENT_RECODE結構體 
  17. WINDOW_BUFFER_SIZE_EVENT    代表Event包含一個WINDOW_BUFFER_SIZE_EVENT_RECORD結構體 
  18. MENU_EVENT                  代表Event包含一個MENU_EVENT_RECORD結構體 
  19. FOCUS_EVENT                 代表Event包含一個FOCUS_EVENT_RECORD結構體 
  20. */  
  21.   
  22. typedef struct _KEY_EVENT_RECORD    //鍵盤事件結構體   
  23. {  
  24.     BOOL  bKeyDown;             //按鍵狀態,true代表鍵按下,false代表鍵釋放  
  25.     WORD  wRepeatCount;         //按鍵次數  
  26.     WORD  wVirtualKeyCode;      //虛擬鍵  
  27.     WORD  wVirtualScanCode;     //虛擬鍵掃描碼  
  28.     union  
  29.     {  
  30.         WCHAR UnicodeChar;      //解釋成Unicode寬字符  
  31.         CHAR  AsciiChar;        //解釋成ASCII碼字符  
  32.     } uChar;  
  33.     DWORD dwControlKeyState;    //控制鍵狀態  
  34. } KEY_EVENT_RECORD;  
  35. /* 
  36. 控制鍵各狀態的值 
  37. ENHANCED_KEY        擴展鍵被按下 
  38. LEFT_ALT_PRESSED    左Alt鍵被按下 
  39. LEFT_CTRL_PRESSED   左Ctrl鍵被按下 
  40. RIGHT_ALT_PRESSED   右Alt鍵被按下 
  41. RIGHT_CTRL_PRESSED  右Ctrl鍵被按下 
  42. NUMLOCK_ON          數字鎖定被打開 
  43. SCROLLLOCK_ON       滾動鎖定被打開 
  44. CAPSLOCK_ON         大寫鎖定被打開 
  45. SHIFT_PRESSED       Shift鍵被按下 
  46. */  

 

 

       當輸入事件為鍵盤事件時,事件類型就為鍵盤事件,為其他事件時,事件類型就為對應的事件。另外,鍵盤上每個有意義的鍵都對應着一個唯一的掃描碼,雖然掃描碼可以作為鍵的標識,但是它是依賴於具體的設備的。因此,在應用程序中,使用的往往是與具體設備無關的虛擬鍵代碼。這種虛擬鍵代碼是一種與具體設備無關的鍵盤編碼。而控制鍵狀態比如大寫鎖定開啟狀態,Ctrl鍵按下狀態等、、、

 

       下面是部分常用虛擬鍵代碼表:


  1. /* 
  2. 虛擬鍵代碼      值          鍵名稱 
  3. -----------------------------------------------------             
  4. VK_BACK         0x08        退格鍵 
  5. VK_TAB          0x09        Tab鍵 
  6. VK_RETURN       0x0D        回車鍵 
  7. VK_SHIFT        0x10        Shift鍵 
  8. VK_LSHIFT       0xA0        左Shift鍵 
  9. VK_RSHIFT       0xA1        右Shift鍵 
  10. VK_CONTROL      0x11        Ctrl鍵 
  11. VK_LCONTROL     0xA2        左Ctrl鍵 
  12. VK_RCONTROL     0xA3        右Ctrl鍵 
  13. VK_MENU         0x12        Alt鍵 
  14. VK_LMENU        0xA4        左Alt鍵 
  15. VK_RMENU        0xA5        右Alt鍵 
  16. VK_PAUSE        0x13        Pause鍵 
  17. VK_CAPITAL      0x14        Caps Lock鍵 
  18. VK_NUMLOCK      0x90        Num Lock鍵 
  19. VK_SCROLL       0x91        Scroll Lock鍵 
  20. VK_ESCAPE       0x1B        Esc鍵 
  21. VK_SPACE        0x20        空格鍵 
  22. VK_PRIOR        0x21        Page Up鍵 
  23. VK_NEXT         0x22        Page Down鍵 
  24. VK_END          0x23        End鍵 
  25. VK_HOME         0x24        Home鍵 
  26. VK_LEFT         0x25        左方向鍵 
  27. VK_UP           0x26        上方向鍵 
  28. VK_RIGHT        0x27        右方向鍵 
  29. VK_DOWN         0x28        下方向鍵 
  30. VK_DELETE       0x2E        Delete鍵 
  31. VK_INSERT       0x2D        Insert鍵 
  32. '0'             0x30        0鍵(非小鍵盤) 
  33. '1'             0x31        1鍵(非小鍵盤) 
  34. '2'             0x32        2鍵(非小鍵盤) 
  35. ...             ...         ... 
  36. '9'             0x39        9鍵(非小鍵盤) 
  37. 'A'             0x41        A鍵 
  38. 'B'             0x42        B鍵 
  39. ...             ...         ... 
  40. 'Z'             0x5A        Z鍵 
  41. VK_SLEEP        0x5F        Sleep鍵 
  42. VK_NUMPAD0      0x60        小鍵盤0鍵 
  43. VK_NUMPAD1      0x61        小鍵盤1鍵 
  44. VK_NUMPAD2      0x62        小鍵盤2鍵 
  45. ...             ...         ... 
  46. VK_NUMPAD9      0x69        小鍵盤9鍵 
  47. VK_MULTIPLY     0x6A        小鍵盤乘鍵* 
  48. VK_ADD          0x6B        小鍵盤加鍵+ 
  49. VK_SUBTRACT     0x6D        小鍵盤減鍵- 
  50. VK_DIVIDE       0x6F        小鍵盤除鍵/ 
  51. VK_DECIMAL      0x6E        小鍵盤點鍵. 
  52. VK_F1           0x70        F1鍵 
  53. VK_F2           0x71        F2鍵 
  54. ...             ...         ... 
  55. VK_F12          0x7B        F12鍵 
  56. VK_F13          0x7C        F13鍵      注:別問我,我也不知道什么電腦有這么多鍵 
  57. ...             ...         ... 
  58. VK_F24          0x87        F24鍵 
  59. VK_OEM_1        0xBA        ;:鍵 
  60. VK_OEM_2        0xBF        /?鍵 
  61. VK_OEM_3        0xC0        ·~鍵 
  62. VK_OEM_4        0xDB        [{鍵 
  63. VK_OEM_5        0xDC        \|鍵 
  64. VK_OEM_6        0xDD        ]}鍵 
  65. VK_OEM_7        0xDE        '"鍵 
  66. VK_OEM_PLUS     0xBB        =+鍵 
  67. VK_OEM_MINUS    0xBD        -_鍵 
  68. VK_OEM_COMMA    0xBC        ,<鍵 
  69. VK_OEM_PERIOD   0xBE        .>鍵  
  70. */  

 

 

       以上是部分常用的微軟虛擬鍵盤碼表,想要知道更詳細的,請參見MSDN。其中各個虛擬鍵的具體使用情況根據各人編譯器或IDE等的不同而有所差異。下面是一個實現按Esc鍵就輸出Esc的樣例程序:


  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <windows.h>  
  4. #include <conio.h>  
  5. #define true 1  
  6. #define false 0  
  7.   
  8. int main()  
  9. {  
  10.     HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);      //獲得標准輸入設備句柄  
  11.     INPUT_RECORD keyrec;        //定義輸入事件結構體  
  12.     DWORD res;      //定義返回記錄  
  13.     for (;;)  
  14.     {  
  15.         ReadConsoleInput(handle_in, &keyrec, 1, &res);      //讀取輸入事件  
  16.         if (keyrec.EventType == KEY_EVENT)      //如果當前事件是鍵盤事件  
  17.         {  
  18.             if (keyrec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) //當前事件的虛擬鍵為Esc鍵  
  19.             {  
  20.                 printf("Esc ");  
  21.             }  
  22.         }  
  23.     }  
  24.     return 0;  
  25. }  

 

 

       在上面的樣例程序中,當你按下Esc鍵后又馬上釋放,程序會輸出兩次Esc,因為有兩次事件的虛擬鍵代碼都是Esc鍵的代碼,一次是按下,一次是釋放。如果要實現按下鍵后出現反應,釋放不出現反應,那么將上例程序中第18行代碼的條件改成


  1. if (keyrec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE  
  2.     && keyrec.Event.KeyEvent.bKeyDown == true)     //表示當前為鍵按下而不是鍵釋放  

就行了。

 

 

       根據控制鍵的狀態我們可以實現不同的狀態輸出不同的值以及組合鍵的實現,下面的樣例程序在大寫鎖定打開時輸入A鍵則輸出大寫字母A,否則輸出小寫字母a。而在Shift鍵被按下的狀態是則輸出Shift+A以及Shift+a。樣例程序如下


  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <windows.h>  
  4. #include <conio.h>  
  5. #define true 1  
  6. #define false 0  
  7.   
  8. int main()  
  9. {  
  10.     HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);      //獲得標准輸入設備句柄  
  11.     INPUT_RECORD keyrec;        //定義輸入事件結構體  
  12.     DWORD res;      //定義返回記錄  
  13.     for (;;)  
  14.     {  
  15.         ReadConsoleInput(handle_in, &keyrec, 1, &res);      //讀取輸入事件  
  16.         if (keyrec.EventType == KEY_EVENT)      //如果當前事件是鍵盤事件  
  17.         {  
  18.             if (keyrec.Event.KeyEvent.wVirtualKeyCode == 'A'  
  19.                 && keyrec.Event.KeyEvent.bKeyDown == true)   //當按下字母A鍵時  
  20.             {  
  21.                 if (keyrec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)    //Shift鍵為按下狀態  
  22.                 {  
  23.                     printf("Shift+");  
  24.                 }  
  25.                 if (keyrec.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON)  //大寫鎖定為打開狀態  
  26.                 {  
  27.                     printf("A ");  
  28.                 }  
  29.                 else        //大寫鎖定關閉狀態  
  30.                 {  
  31.                     printf("a ");  
  32.                 }  
  33.             }  
  34.         }  
  35.     }  
  36.     return 0;  
  37. }  

 

 

       由上例需要了解到的是,各個控制鍵狀態的的確定並不是使用等於符號==而是按位與&運算符,因為在同一時刻可能有多種控制鍵狀態值,比如各種鎖定都被打開且各種控制鍵也被同時按下。使用&運算符則顯得尤其高明,方便查詢各個控制鍵的狀態而不使之出現沖突。呵呵,不服不行啊,感慨一下,還是要多學習一下別人高明的地方,比如靈活運用位運算符實現各種功能等等······


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM