09 Windows编程——键盘消息
焦点窗口:接收到这个键盘事件的窗口称为有输入焦点的窗口。具有输入焦点的窗口要么是活动窗口,要么是活动窗口的子孙窗口。
活动窗口:活动窗口通常是很好鉴别的。它总是最上层的窗口——也就是说,它的父窗口句柄是NULL。
系统消息队列 & 应用程序消息队列
当用户按下和释放键盘上的一个键时,Windows和键盘设备驱动程序将硬件扫描码转换为格式化后的消息。但是,这些消息并不立即被放入应用程序消息队列,而是由Wimdows把这些消息存储在系统消息队列中。系统消息队列是一个单独的消息队列,它被 Windows用来初步存储用户从键盘和鼠标输入的消息。仅当Windows应用程序完成了对前一个用户输入消息的处理后,Windows才从系统消息队列中取出下一条消息,并把它放入应用程序消息队列。
应用程序从Windows接收的关于键盘事件的消息可分为击键消息和字符消息两种。对产生可显示字符的击键组合,Windows在发送击键消息的同时还发送字符消息。有些键不产生字符,如Shift键、功能键、光标移动键和特殊字符键(如Insert键和Delete键)。对于这些键,Windows只产生击键消息。
字符消息
WM_CHAR,WM_SYSCHAR,WM_DEADCHAR,WM_SYSDEADCHAR
wParam就是按键字符,TCHAR(wParam)就可以获得这个字符,不要去区分这个字符是ASCII字符或者UNICODE字符,因为TCHAR数据类型已经帮你区分好了!
一个按键会产生以下4个消息:WM_KEYDOWN,WM_CHAR,WM_KEYUP,WM_DEADCHAR 4个消息。
击键消息
通常键按下消息和键释放消息是成对出现的。但是如果你按下一个键不放时,则被认为发生了一次连续按键(自动重复)行为,Windows将发送给窗口过程一连串的WM KEYDOWN(或WMSYSKEYDOWN)消息。当此键最终被释放时,Windows发送给窗口过程一个WMKEYUP(或WMSYSKEYUP)消息。像所有的队列消息一样,击键消息是可被实时追踪的。你能通过调用GetMessageTime函数,得到键被按下或释放的相对时间。
系统击键
表明该击键对Windows比对Windows应用程序更加重要。当输入键和Alt键组合时通常产生的是WM SYSKEYDOWN和WMSYSKEYUP消息。应用程序通常忽略WMSYSKEYUP和WMSYSKEYDOWN消息,将它们交付给DefWindowProc函数完成默认处理。因为Windows关注所有的Alt键功能逻辑,应用程序就不必处理这些消息。如果你非要处理这些消息,则在处理完毕后,仍然需要发送这些消息给DefWindowProc函数,以便不影响Windows对它的处理。
对所有四类击键消息,wParam是虚拟键代码,用于标识哪个键被按下或被释放,而IParam包含属于本次击键的一些其他数据。大多数虚拟键代码命名是以VK_开头的,它定义在WINUSER日头文件中。lParam消息参数包含了帮助理解击键的其他有用信息。32位的lParam消息被分成了6个字段,如图所示。
1 #include<Windows.h> 2 #include<WinUser.h> 3 #include<tchar.h> 4 #include<stdio.h> 5 6 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 7 8 int WinMain(HINSTANCE hInst, HINSTANCE tmp, LPSTR szCmd, int nShow) 9 { 10 WNDCLASS WndClass; 11 TCHAR* ClassName = TEXT("MyClass"); 12 HWND hwnd; 13 MSG msg; 14 15 WndClass.cbClsExtra = 0; 16 WndClass.cbWndExtra = 0; 17 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 18 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); 19 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 20 WndClass.hInstance = hInst; 21 WndClass.lpfnWndProc = WindProc; 22 WndClass.lpszClassName = ClassName; 23 WndClass.lpszMenuName = NULL; 24 WndClass.style = CS_VREDRAW | CS_HREDRAW; 25 26 RegisterClass(&WndClass); 27 hwnd = CreateWindow(ClassName, TEXT("Hello"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 300, NULL, NULL, hInst, NULL); 28 ShowWindow(hwnd, nShow); 29 UpdateWindow(hwnd); 30 31 while (GetMessage(&msg, NULL, 0, 0)) 32 { 33 TranslateMessage(&msg); 34 DispatchMessage(&msg); 35 } 36 return 0; 37 } 38 39 40 41 LRESULT CALLBACK WindProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 42 { 43 HDC hdc; 44 PAINTSTRUCT pt; 45 static int cx, cy; 46 static int cyChar; 47 static int iLine; 48 static int iMaxLine; 49 static TCHAR cBuf[1024] = { "Please Press Key:" }; 50 TEXTMETRIC tm; 51 RECT rect; 52 switch (message) 53 { 54 case WM_CREATE: 55 hdc = GetDC(hwnd); 56 GetTextMetrics(hdc, &tm); 57 cyChar = tm.tmHeight; 58 ReleaseDC(hwnd, hdc); 59 iLine = 0; 60 iMaxLine = 0; 61 return 0; 62 case WM_SIZE: 63 cx = LOWORD(lParam); 64 cy = HIWORD(lParam); 65 iMaxLine = cy / cyChar-1; 66 iLine = iLine > iMaxLine ? iMaxLine : iLine; 67 return 0; 68 case WM_PAINT: 69 hdc = BeginPaint(hwnd, &pt); 70 TextOut(hdc, pt.rcPaint.left, pt.rcPaint.top, cBuf, _tcslen(cBuf)); 71 EndPaint(hwnd, &pt); 72 iLine++; 73 return 0; 74 case WM_CHAR: 75 iLine = iLine > iMaxLine ? iMaxLine : iLine; 76 _stprintf(cBuf, TEXT("lParam=0x%X wParam=0x%X : %c"), lParam, wParam,wParam); 77 rect.left = 0; 78 rect.top = iLine * cyChar; 79 rect.right = cx; 80 rect.bottom = (iLine + 1)*cyChar; 81 InvalidateRect(hwnd, &rect, TRUE); 82 return 0; 83 case WM_DESTROY: 84 PostQuitMessage(0); 85 return 0; 86 default: 87 break; 88 } 89 90 return DefWindowProc(hwnd, message, wParam, lParam); 91 }