原文連接: http://blog.sina.com.cn/s/blog_5f8817250100taab.htmlhtml
本文大部分來自MSDN和網友的博客,我在實踐的基礎上再做了一些總結。函數
1,虛擬鍵(VK_*)spa
鍵盤上每個鍵對應一個掃描碼,掃描碼是OEM廠商制定的,不一樣的廠商生產的鍵盤一樣一個按鍵的掃描碼都有可能出現不一致的狀況,爲了擺脫因爲系統設備不一致的狀況,經過鍵盤驅動程序將掃描碼映射爲統一的虛擬鍵碼錶示,從而達到全部的設備都有一個統一的虛擬鍵,好比回車鍵的虛擬鍵是VK_RETURN。翻譯
Windows定義的虛擬鍵都定義在WinUser.h這個頭文件裏面,都是以VK_做爲前綴。設計
2,激活/關閉窗口對鍵盤的消息code
激活/關閉消息:WM_SETFOCUS/WM_KILLFOCUShtm
建立光標:CreateCaret(...)blog
設置光標位置:SetCaretPos(…)隊列
在窗口中顯示光標:ShowCaret(…)ci
銷燬光標:DestroyCaret()
3,鍵盤消息
1)字符消息
系統字符消息
WM_SYSCHAR:系統字符
WM_SYSDEADCHAR:系統死字符
非系統按鍵消息
WM_CHAR:非系統字符
WM_DEADCHAR:非系統死字符
2)按鍵消息
系統按鍵消息:與ALT鍵相組合的組合鍵(不管用戶處理否,都須要最後調用DefWindowProc(hWnd,iMessage,wParam,lParam))
WM_SYSKEYDOWN
WM_SYSKEYUP
非系統按鍵消息:
WM_KEYDOWN
WM_KEYUP
注意:
a) 除Print鍵以外都有「按下」消息。
b) 全部鍵都存在「彈起」消息。
c) 根據MSDN說明,只有下面這些鍵纔會產生字符消息:
咱們是怎麼收到WM_CHAR的呢?就是由於咱們在消息循環時調用了TranslateMessage對鍵盤消息進行翻譯,
若是消息爲WM_KEYDOWN或者WM_SYSKEYDOWN,而且按鍵與位移狀態相組合產生一個字符,則TranslateMessage把字符消息放入消息隊列中。此字符消息將是GetMessage從消息隊列中獲得的按鍵消息以後的下一個消息。
在咱們處理這個消息時,對應的wParam不是虛擬鍵,而是ANSI或Unicode字符代碼,通常狀況下咱們能夠這樣用: (TCHAR)wParam;
4,消息順序
由於TranslateMessage函數從WM_KEYDOWN和WM_SYSKEYDOWN消息產生了字符消息,因此字符消息是夾在按鍵消息之間傳遞給窗口消息處理程序的。例如,若是Caps Lock未打開,而使用者按下再釋放A鍵,則窗口消息處理程序將接收到如表6-10所示的三個消息:
表6-10
消息 |
按鍵或者代碼 |
WM_KEYDOWN |
「A」的虛擬鍵碼(0x41) |
WM_CHAR |
「a」的字符代碼(0x61) |
WM_KEYUP |
「A」的虛擬鍵碼(0x41) |
若是您按下Shift鍵,再按下A鍵,而後釋放A鍵,再釋放Shift鍵,就會輸入大寫的A,而窗口消息處理程序會接收到五個消息,如表6-11所示:
表6-11
消息 |
按鍵或者代碼 |
WM_KEYDOWN |
虛擬鍵碼VK_SHIFT (0x10) |
WM_KEYDOWN |
「A」的虛擬鍵碼(0x41) |
WM_CHAR |
「A」的字符代碼(0x41) |
WM_KEYUP |
「A」的虛擬鍵碼(0x41) |
WM_KEYUP |
虛擬鍵碼VK_SHIFT(0x10) |
Shift鍵自己不產生字符消息。
若是使用者按住A鍵,以使自動重複產生一系列的按鍵,那麼對每條WM_KEYDOWN消息,都會獲得一條字符消息,如表6-12所示:
表6-12
消息 |
按鍵或者代碼 |
WM_KEYDOWN |
「A」的虛擬鍵碼(0x41) |
WM_CHAR |
「a」的字符代碼(0x61) |
WM_KEYDOWN |
「A」的虛擬鍵碼(0x41) |
WM_CHAR |
「a」的字符代碼(0x61) |
WM_KEYDOWN |
「A」的虛擬鍵碼(0x41) |
WM_CHAR |
「a」的字符代碼(0x61) |
WM_KEYDOWN |
「A」的虛擬鍵碼(0x41) |
WM_CHAR |
「a」的字符代碼(0x61) |
WM_KEYUP |
「A」的虛擬鍵碼(0x41) |
若是某些WM_KEYDOWN消息的重複計數大於1,那麼相應的WM_CHAR消息將具備一樣的重複計數。
組合使用Ctrl鍵與字母鍵會產生從0x01(Ctrl-A)到0x1A(Ctrl-Z)的ASCII控制代碼,其中的某些控制代碼也能夠由表6-13列出的鍵產生:
表6-13
按鍵 |
字符代碼 |
產生方法 |
ANSI C控制字符 |
Backspace |
0x08 |
Ctrl-H |
\b |
Tab |
0x09 |
Ctrl-I |
\t |
Ctrl-Enter |
0x0A |
Ctrl-J |
\n |
Enter |
0x0D |
Ctrl-M |
\r |
Esc |
0x1B |
Ctrl-[ |
|
最右列給出了在ANSI C中定義的控制字符,它們用於描述這些鍵的字符代碼。
咱們通常能夠這樣處理WM_CARH消息:
case WM_CHAR:
{
switch (wParam)
{
case 0x08:
// Process a backspace.
break;
case 0x0A:
// Process a linefeed.
break;
case 0x1B:
// Process an escape.
break;
case 0x09:
// Process a tab.
break;
case 0x0D:
// Process a carriage return.
break;
default:
// Process displayable characters.
break;
}
}
咱們能夠在WM_CHAR裏面判斷當前是否有指定的鍵被按下:
BOOL bIsCtrl = (::GetAsyncKeyState(VK_CONTROL) & 0x8000); (MFC源碼 afxcolordialog.cpp 460行)
或
BOOL bIsCtrl = (::GetKeyState(VK_CONTROL) & 0x8000);
下面我解釋一下鍵盤消息的lParam參數,這個參數在MSDN上面均可以查到,只是英文,我這裏做一些簡單的說明:(以WM_KEYDOWN爲例)
WPARAM:虛擬鍵值,VT_*等值。
LPARAM:根據其不一樣的位數表示的含義不一樣能夠分如下幾部分:
(1) 重複計數位(0 - 15 位):表示消息按鍵數據。通常狀況下爲1,當鍵一直按下,窗口過程就會連續收到W_KEYDOWN消息,但有可能窗口過程來不及處理這些按鍵消息,那麼Windows就會把幾個按鍵消息組合成一個,並增長重複計數。好比你處理WM_KEYDOWN時Sleep(200),那麼獲得的這個數字就可能大於1,通常能夠這樣來獲得這個計數:
DWORD count = (((DWORD)lParam) & 0x0000FFFF);
(2) OEM掃描碼(16~23位):OEM掃描碼是鍵盤發送的碼值,因爲此域是設備相關的,於是此值每每被忽略。
(3) 擴展鍵標誌(24位):擴展鍵標誌在有Alt鍵(或Ctrl鍵)按下時爲1,不然爲0。
(4) 保留位(25~28位):保留位是系統缺省保留的,通常不用。
(5) 關聯碼(29位):關聯碼用來記錄某鍵與Alt鍵的組合狀態,若按下Alt,當WM_SYSKEYDOWN消息送到某個激活的窗口時,其值爲1,不然爲0。
(6) 鍵的先前狀態(位30):鍵的先前狀態用於記錄先前某鍵的狀態,對於WM_SYSKEYUP消息,其值始終爲1。
(7) 轉換狀態(31位):轉換狀態的消息是始終按着某鍵所產生的消息,若某鍵原來是按下的,則其先前狀態爲0。轉換狀態指示鍵被按下仍是被鬆開。當鍵被按下時,對應於者WM_SYSKEYDOWN消息,其值始終爲0,當鍵被鬆開時,其轉換狀態爲1,對應於WM_SYSKEYUP消息,其值始終爲1。
5,死字符消息
Windows程序常常忽略WM_DEADCHAR和WM_SYSDEADCHAR消息,但您應該明確地知道死字符是什麼,以及它們工做的方式。
在某些非U.S.英語鍵盤上,有些鍵用於給字母加上音調。由於它們自己不產生字符,因此稱之爲「死鍵」。例如,使用德語鍵盤時,對於U.S.鍵盤上的+/=鍵,德語鍵盤的對應位置就是一個死鍵,未按下Shift鍵時它用於標識銳音,按下Shift鍵時則用於標識抑音。
當使用者按下這個死鍵時,窗口消息處理程序接收到一個wParam等於音調自己的ASCII或者Unicode代碼的WM_DEADCHAR消息。當使用者再按下能夠帶有此音調的字母鍵(例如A鍵)時,窗口消息處理程序會接收到WM_CHAR消息,其中wParam等於帶有音調的字母「a」的ANSI代碼。
所以,使用者程序不須要處理WM_DEADCHAR消息,緣由是WM_CHAR消息已含有程序所須要的全部信息。Windows的作法甚至還設計了內部錯誤處理。若是在死鍵以後跟有不能帶此音調符號的字母(例如「s」),那麼窗口消息處理程序將在一行接收到兩條WM_CHAR消息-前一個消息的wParam等於音調符號自己的ASCII代碼(與傳遞到WM_DEADCHAR消息的wParam值相同),第二個消息的wParam等於字母s的ASCII代碼。
固然,要感覺這種作法的運做方式,最好的方法就是實際操做。您必須加載使用死鍵的外語鍵盤,例如前面講過的德語鍵盤。您能夠這樣設定:在「控制檯」中選擇「鍵盤」,而後選擇「語系」頁面標籤。而後您須要一個應用程序,該程序能夠顯示它接收的每個鍵盤消息的詳細信息。下面的KEYVIEW1就是這樣的程序。