特殊说明:版权归个人所有,请勿转载,谢谢合作。
键盘消息的处理相对鼠标消息处理来说基本相同,虽然标准键盘有104个键位,但是在Win32下访问键盘消息的方法有两种:
(1)通过WM_KEYDOWN和WM_KEYUP消息;
(2)通过WM_CHAR消息。
这两种消息在工作方式上略有不同。WM_CHAR消息与WM_KEYDOWN消息在按下键盘上的按键或由Windows产生,当在键盘上按下某个键时,将会产生两个不同类型的数据:扫描码与ASCII码。
键盘上每一个按键(标准键盘),都对应着一个唯一的标识值,这个标识值称为扫描码,它与ASCII码无关。在早期IBM的机器上,扫描码根据键盘的实际布局(如:扫描码16是Q键,17是W键,18是E、19是R,20是T,21是Y等等)。它所捕获的是键盘上的大写方式,它不会关心是否按下了Shift键或使用了Caps Lock键来锁定大小写。如果正在实现一个像CS(CS是一种射击类游戏)中移动的方向的功能,那么通过捕获WM_KEYDOWN消息就可以实现所需要的效果。
ASCII码是人为形成的数据,它是区分大小写的。如果按下键盘上的A键时,而未按下Shift且未使用Caps Lock键,将只能看到一个小写的字符“a”,如果按下Shift+A,则可以看到一个大写的字符“A”。通过WM_CHAR消息则可以实现大小写的控制。如果所编写的程序,要求区分字符的大小写,使用WM_CHAR再好不过了。
根据MSDN的描述,Windows系统有14种不同的消息,用来报告与键盘有关的事件,见表4.3所示。
- 表4.3 键盘消息事件
消息 | 事件描述 |
WM_KEYDOWN | 非系统键按下 |
WM_KEYUP | 非系统键抬起 |
WM_CHAR | 非系统字符消息 |
WM_ACTIVATE | 激活窗口 |
WM_DEADCHAR | 死键消息 |
WM_GETHOTKEY | 应用程序发送WM_GETHOTKEY的消息,以确定与一个窗口关联的热键 |
WM_HOTKEY | 当用户按下RegisterHotKey函数注册热键。该消息被放置在注册热键与线程相关的消息队列的顶部 |
WM_KILLFOCUS | 窗口失去输入焦点 |
WM_SETFOCUS | 窗口得到输入焦点 |
WM_SETHOTKEY | 与窗口关联热键。当用户按下热键,系统激活的窗口 |
WM_SYSCHAR | 系统字符消息 |
WM_SYSDEADCHAR | 系统死字符 |
WM_SYSKEYDOWN | 系统键按下消息 |
WM_SYSKEYUP | 系统键抬起消息 |
键盘消息中,较为常用的消息为:WM_KEYDOWN、WM_KEYUP以及WM_CHAR。在捕获WM_CHAR消息时回调函数的参数含义:
参数wparam,包含所按下键的ASCII码;
参数lparam,包含一个按位编码的状态,描述可能被按下的特殊控制键。32位的变量lparam,根据不同位数表示不同的含义,如表4.4所示。
- 表4.4 键盘消息事件
位 | 描述 |
0~15 | 重复计数,持续按住某键,造成该键的重复次数 |
16~23 | 扫描码,由于此项与设备相关,因而此值往往会被忽略 |
24 | 布尔型,扩展键标识符。Alt或Ctrl键按下时为1,否则为0 |
25~28 | 保留位,一般不会使用 |
29 | 布尔型,Alt键是否按下 |
30 | 布尔型,记录前一个键的状态 |
31 | 布尔型,转换状态。如果结果为1,该键正被释放,否则正被按住 |
键盘事件消息WM_KEYDOWN和WM_CHAR基本相似,只是信息未经处理而以。在WM_KEYDOWN中传递的数据是虚拟键值码,而不是ASCII码。虚拟键值码与键盘产生的扫描码相似,它是一种与设备无关的键盘编码,它的值存放在过程中处理函数中的wParam参数中,用于识别哪一个按键被按下或抬起。操作系统在接收到键盘输入后,系统将消息发送给具有输入焦点的窗口。在捕获WM_KEYDOWN消息时回调函数的参数含义:
参数wparam,包含所按下键的虚拟键值码,如表4.5所示;
参数lparam,包含一个按位编码的状态,描述其他可能被按下的特殊控制键,如表4.5所示。
- 表4.5 虚拟键值码
虚拟键值 | 键盘按键 | 十六进制值 |
VK_BACK | Backspace 键 | 0x08 |
VK_TAB | Tab 键 | 0x09 |
VK_RETURN | 回车键 | 0x0D |
VK_SHIFT | Shift 键 | 0x10 |
VK_CONTROL | Ctrl 键 | 0x11 |
VK_MENU | Alt 键 | 0x12 |
VK_PAUSE | Pause 键 | 0x13 |
VK_CAPITAL | Caps Lock 键 | 0x14 |
VK_ESCAPE | Esc 键 | 0x1B |
VK_SPACE | 空格键 | 0x20 |
VK_PRIOR | Page Up 键 | 0x21 |
VK_NEXT | Page Down 键 | 0x22 |
VK_END | End 键 | 0x23 |
VK_HOME | Home 键 | 0x24 |
VK_LEFT | 左箭头键 | 0x25 |
VK_UP | 上箭头键 | 0x26 |
VK_RIGHT | 右箭头键 | 0x27 |
VK_DOWN | 箭头键 | 0x28 |
VK_SNAPSHOT | Print Screen 键 | 0x2C |
VK_INSERT | Insert 键 | 0x2D |
VK_DELETE | Delete 键 | 0x2E |
‘0’ – ‘9’ | 数字 0 – 9 | 0x30 – 0x39 |
‘A’ – ‘Z’ | 字母 A – Z | 0x41 – 0x5A |
VK_LWIN | 左WinKey(104键盘才有) | 0x5B |
VK_RWIN | 右WinKey(104键盘才有) | 0x5C |
VK_APPS | AppsKey(104键盘才有) | 0x5D |
VK_NUMPAD0 | 小键盘 0 键 | 0x60 |
VK_NUMPAD1 | 小键盘 1 键 | 0x61 |
VK_NUMPAD2 | 小键盘 2 键 | 0x62 |
VK_NUMPAD3 | 小键盘 3 键 | 0x63 |
VK_NUMPAD4 | 小键盘 4 键 | 0x64 |
VK_NUMPAD5 | 小键盘 5 键 | 0x65 |
VK_NUMPAD6 | 小键盘 6 键 | 0x66 |
VK_NUMPAD7 | 小键盘 7 键 | 0x67 |
VK_NUMPAD8 | 小键盘 8 键 | 0x68 |
VK_NUMPAD9 | 小键盘 9 键 | 0x69 |
VK_F1 – VK_F24 | 功能键F1 – F24 | 0x70 – 0x87 |
VK_NUMLOCK | Num Lock 键 | 0x90 |
VK_SCROLL | Scroll Lock 键 | 0x91 |
WM_KEYUP消息与WM_KEYDOWN消息参数相同,用法也相同,这里就不过多进行介绍,如果想深入学习,请参照MSDN。
【例4-2】实现键盘的捕获。当在键盘上输入数据时,窗口的标题栏显示输入的内容。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { char szBuffer[64] = { 0 }; // 临时缓冲区 // 消息处理 // switch (message) { // 键盘消息事件 case WM_CHAR: // 获得窗口标题的内容 GetWindowText(hWnd, szBuffer, 64); // 格式化到缓冲区 sprintf(szBuffer, "%s%c", szBuffer, wParam); // 设置窗口标题 SetWindowText(hWnd, szBuffer); break; // 窗口销毁消息,关闭窗口时响应。 case WM_DESTROY: PostQuitMessage(0); break; default: // 调用系统默认消息处理,即交给系统处理。 return DefWindowProc(hWnd, message, wParam, lParam); }//end switch return 0; }
首先,需要捕获WM_CHAR消息,或WM_KEYDOWN消息,它们之前的区别在前面已经提到了,针对输入内容来说,前者区分大小写,而后者不区分,无论输入大写还是小写,都以大写处理;其次,使用GetWindowText函数来获得当前窗口标题的内容,GetWindowText函数的第一个参数是将要获得的窗口的句柄,第二个参数是将窗口标题存放的缓冲变量,第三个参数是缓冲变量最多存放的字符数量;再次,使用sprintf函数将窗口标题格式化到缓冲变量中,并加入新按下的按键字符;最后,使用SetWindowText函数将合成后标题内容设置到窗口标题栏中。至此,操作结束,操作结果如图4.3所示。
- 图4.3 键盘消息捕获