[Win32]Win32 SDK编程系列文章——键盘输入消息
理论
因为大多数的PC只有一个键盘,所以所有运行中的WINDOWS程序必须共用它。WINDOWS 将负责把击键消息送到具有输入焦点的那个应用程序中去。尽管屏幕上可能同时有几个应用程序窗口,但一个时刻仅有一个窗口有输入焦点。有输入焦点的那个应用程序的标题条总是高亮度显示的。 实际上您可以从两个角度来看键盘消息:一是您可以把它看成是一大堆的按键消息的集合,在这种情况下,当您按下一个键时,WINDOWS就会发送一个WM_KEYDOWN给有输入焦点的那个应用程序,提醒它有一个键被按下。当您释放键时,WINDOWS又会发送一个WM_KYEUP消息,告诉有一个键被释放。您把每一个键当成是一个按钮;另一种情况是:您可以把键盘看成是字符输入设备。当您按下“a”键时,WINDOWS发送一个WM_CHAR消息给有输入焦点的应用程序,告诉它“a”键被按下。实际上WINDOWS 内部发送WM_KEYDOWN和WWM_KEYUP消息给有输入焦点的应用程序,而这些消息将通过调用TranslateMessage翻译成WM_CHAR消息。WINDOWS窗口过程函数将决定是否处理所收到的消息,一般说来您不大会去处理WM_KEYDOWN、WM_KEYUP消息,在消息循环中TranslateMessage函数会把上述消息转换成WM_CHAR消息
实例
关键代码
TCHAR FontName[]=_T("script"); WPARAM keyChar =0x20;//0x20(十六进制)是空格的ascii码,亳州没有按键的时候程序正常显示 TCHAR keyDownUp[50]; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; HFONT hFont,hOldFont; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... hFont=CreateFont(24,16,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_SCRIPT,FontName); hOldFont =(HFONT)SelectObject(hdc,hFont); SetTextColor(hdc,RGB(200,200,50)); SetBkColor(hdc,RGB(0,0,255)); TextOut(hdc,40,40,(TCHAR*)&keyChar,1);//在设备环境的坐标(40,40)处,化长度为1的keyChar字符串 EndPaint(hWnd, &ps); break; case WM_CHAR://按下某键, 并已发出WM_KEYDOWN, WM_KEYUP消息 keyChar=wParam;//接收到的字符放入变量keyChar中,接着调用InvalidateRect,而InvalidateRect使得窗口的客户区无效,这样它会发出WM_PAINT消息,而WM_PAINT消息迫使Windows重新绘制它的客户区。 InvalidateRect(hWnd,NULL,TRUE); //我们将保存所有有关重绘客户区的数据,然后发送WM_PAINT消息,处理该消息的程序段然后根据相关数据重新绘制客户区。尽管这么做事有点像走了弯路,但WINDOWS要处理那么庞大的消息群,没有一定的规矩可不行。 实际上我们完全可以通过调用GetDC 获得设备上下文句柄,然后绘制字符,然后再调用ReleaseDC释放设备上下文句柄,毫无疑问这样也能在客户区绘制出正确的字符。但是如果这之后接收到WM_PAINT消息要处理时,客户区会重新刷新,而我们这稍前所绘制的字符就会消失掉。所以为了让字符一直正确地显示,就必须把它们放到WM_PAINT的处理过程中处理。而在本消息处理中发送WM_PAINT消息即可。 break; case WM_KEYDOWN://按下一个键,当一个非系统键被按下时该消息发送给具有键盘焦点的窗口。非系统键即不与ALT联用的情况。 wsprintf(keyDownUp,L"keyDown:%c",wParam); SetWindowText(hWnd,keyDownUp); break; case WM_SYSKEYUP://释放一个系统键,系统键alt+x wsprintf(keyDownUp,L"SysKeyUp:%c",wParam); SetWindowText(hWnd,keyDownUp); break; case WM_KEYUP: if (GetAsyncKeyState(VK_CONTROL))//GetAsyncKeyState()实时检查键盘硬件状态返回结果。GetKeyState函数并非实时检查键盘状态,它只是检查当前正在处理的消息发生之前和发生之时的键盘状态,它是通过读取消息队列中该键的按键消息来实现的。 { if (wParam == VK_NUMPAD1) { wsprintf(keyDownUp,L"Control+%c",wParam);//组合键消息 SetWindowText(hWnd,keyDownUp); } } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } /* 1. BOOL InvalidateRect( __in_opt HWND hWnd, __in_opt CONST RECT *lpRect,//是指向客户区我们想要其无效的一个正方形结构体的指针。如果为NULL,则整个客户区都无效 __in BOOL bErase);//是否擦除背景 */效果图: