一、键盘消息
键盘动作能够触发的消息主要有WM_KEYDOWN、WM_SYSKEYDOWN、WM_SYSKEYUP、WM_KEYUP、WM_CHAR、WM_SYSCHAR、WM_DEADCHAR、WMSYSDEADCHAR。
键盘消息的两个参数wParam和lParam都用来传递有关击键某些信息。其中wParam消息参数用于传递表示键盘某个被按下键的信息;而lParam消息则用于传递某些诸如连续击键次数、按下键的OEM扫描码等等的附加信息。
二、何时触发消息
对于任何键盘上的键按下和释放都会先后触发WM_KEYDOWN和WM_KEYUP消息。在这两个消息的wParam参数中储存的是按下键的虚拟码,例如Ctrl键储存的是VK_CONTROL虚拟码等等。
当按下的是键盘上的字母或者数值等这些能够表达为一个打印字符的消息时,操作系统将在发送WM_KEYDOWN和WM_KEYUP的中间发送一个WM_CHAR消息,这个消息的wParam参数中是一个按下键所对应的字符在字符集中的代码,通过TCHAR类型转换就可以转换成一个字符供程序使用。当然这里存在一个非ASCII码字符的国际化问题,这将在本文的后面专门讲述。
三、主要键盘消息使用的详解
1.WM_CHAR
毫无疑问这是所有键盘消息中最常用最重要的消息。但是使用这个消息也相对是最简单的,因为操作系统已经为我们做完了所有的一切,我们只需要用TCHAR的转换把字符集代码转换为字符即可使用。当然即使是类似西欧字符中那种有重音符号的字符操作系统也会通过处理死键消息来替我们做完一切事情。
2.WM_KEYDOWN
这个消息是我们获取非打印字符的一个重要消息。这个消息中的wParam参数储存了按键的虚拟代码,之所以是虚拟代码是为了实现真正的与硬件无关化。
那么那些能够用转义字符表示的非打印字符是否也应该用这个消息来获取呢?答案是否定的,比如说enter、spacebar、backspace这些键我们最好还是用WM_CHAR来或取。我们用WM_KEYDOWN来响应的消息应该是VK_KEYUP等等这些根本无法用转义字符表示的按键。
3.WM_DEADKEY
何为死键,死键就是在处理西欧字符中那些有重音符号的字母之前必须按的一个键,只有在按了这个键并且在这之后再按一个字母键才会在相应的字母上显示一个重音符号。
四、WM_CHAR消息的内幕
在触发WM_CHAR消息之前,操作系统处理WM_KEYDOWN消息并确定这个WM_KEYDOWN消息中的wParam参数中储存的是一个打印字符的虚拟码。这样操作系统就把这个虚拟码提取出来并把它转换成一个字符集代码,并把他储存在重新触发的WM_CHAR消息的wParam中。之后就发出WM_CHAR消息。
所有的一切在ASCII码中工作的都是非常完美,但是当遇到非ASCII码字符时就要依赖于字符集了。因为在非UNICODE状况下字符集中只有代表ASCII码之后的位置中放了数量有限的其他字符。这时中文版的windows和法语版的windows中的字符集就不同了。当你在中文版的操作系统中输入使用法语的键盘布局输入一个法语字母时就会出现奇怪的现象,因为两个不同字符集中的不同字符可能拥有相同的字符集代码,这时即使键盘消息标示了一个正确的字符集代码也会出现问题。然而在UNICODE状况下就不同了,因为UNICODE字符集用一个完整的字符集来包括了世界上所有字符的代码,任何字符都有一个确切的代码所以不会有任何的歧异产生。
五、使用光标
在响应键盘事件的同时我们有时候会用到光标,在程序设计里这叫做插入符而不是光标。
创键插入符使用函数CreateCaret(HWND,HBITIMAGE,int Width,int Height);创建插入符之后必须使用ShowCaret(HWND)函数才会显示插入符。同时我们能够获取和设置插入符的位置使用函数GetCaretPos和SetCaretPos。另外在非WM_PAINT消息的消息中绘图时我们必须首先使用HideCaret(HWND)来隐藏插入符。
一个程序中只允许一个窗口拥有插入符,从逻辑上讲也只允许程序中拥有焦点的那个窗口出现插入符。所以我们应该在窗口过程的WM_SETFOCUS消息中创建插入符,而在WM_KILLFOCUS消息中使用DestroyCaret(HWND)函数删除插入符。
附:很全的虚拟键码表
虚拟键码 | 对应值(十进制) | 对应键 |
---|
VK_LBUTTON | 1 | 鼠标左键 | VK_RBUTTON | 2 | 鼠标右键 | VK_CANCEL | 3 | Cancel | VK_MBUTTON | 4 | 鼠标中键 | VK_XBUTTON1 | 5 | | VK_XBUTTON2 | 6 | | VK_BACK | 8 | Backspace | VK_TAB | 9 | Tab | VK_CLEAR | 12 | Clear | VK_RETURN | 13 | Enter | VK_SHIFT | 16 | Shift | VK_CONTROL | 17 | Ctrl | VK_MENU | 18 | Alt | VK_PAUSE | 19 | Pause | VK_CAPITAL | 20 | Caps Lock | VK_KANA | 21 | | VK_HANGUL | 21 | | VK_JUNJA | 23 | | VK_FINAL | 24 | | VK_HANJA | 25 | | VK_KANJI | 25* | | VK_ESCAPE | 27 | Esc | VK_CONVERT | 28 | | VK_NONCONVERT | 29 | | VK_ACCEPT | 30 | | VK_MODECHANGE | 31 | | VK_SPACE | 32 | Space | VK_PRIOR | 33 | Page Up | VK_NEXT | 34 | Page Down | VK_END | 35 | End | VK_HOME | 36 | Home | VK_LEFT | 37 | Left Arrow | VK_UP | 38 | Up Arrow | VK_RIGHT | 39 | Right Arrow | VK_DOWN | 40 | Down Arrow | VK_SELECT | 41 | Select | VK_PRINT | 42 | Print | VK_EXECUTE | 43 | Execute | VK_SNAPSHOT | 44 | Snapshot | VK_INSERT | 45 | Insert | VK_DELETE | 46 | Delete | VK_HELP | 47 | Help | | 48 | 0 | | 49 | 1 | | 50 | 2 | | 51 | 3 | | 52 | 4 | | 53 | 5 | | 54 | 6 | | 55 | 7 | | 56 | 8 | | 57 | 9 | | 65 | A | | 66 | B | | 67 | C | | 68 | D | | 69 | E | | 70 | F | | 71 | G | | 72 | H | | 73 | I | | 74 | J | | 75 | K | | 76 | L | | 77 | M | | 78 | N | | 79 | O | | 80 | P | | 81 | Q | | 82 | R | | 83 | S | | 84 | T | | 85 | U | | 86 | V | | 87 | W | | 88 | X | | 89 | Y | | 90 | Z | VK_LWIN | 91 | | VK_RWIN | 92 | | VK_APPS | 93 | | VK_SLEEP | 95 | | VK_NUMPAD0 | 96 | 小键盘 0 | VK_NUMPAD1 | 97 | 小键盘 1 | VK_NUMPAD2 | 98 | 小键盘 2 | VK_NUMPAD3 | 99 | 小键盘 3 | VK_NUMPAD4 | 100 | 小键盘 4 | VK_NUMPAD5 | 101 | 小键盘 5 | VK_NUMPAD6 | 102 | 小键盘 6 | VK_NUMPAD7 | 103 | 小键盘 7 | VK_NUMPAD8 | 104 | 小键盘 8 | VK_NUMPAD9 | 105 | 小键盘 9 | VK_MULTIPLY | 106 | 小键盘 * | VK_ADD | 107 | 小键盘 + | VK_SEPARATOR | 108 | 小键盘 Enter | VK_SUBTRACT | 109 | 小键盘 - | VK_DECIMAL | 110 | 小键盘 . | VK_DIVIDE | 111 | 小键盘 / | VK_F1 | 112 | F1 | VK_F2 | 113 | F2 | VK_F3 | 114 | F3 | VK_F4 | 115 | F4 | VK_F5 | 116 | F5 | VK_F6 | 117 | F6 | VK_F7 | 118 | F7 | VK_F8 | 119 | F8 | VK_F9 | 120 | F9 | VK_F10 | 121 | F10 | VK_F11 | 122 | F11 | VK_F12 | 123 | F12 | VK_F13 | 124 | | VK_F14 | 125 | | VK_F15 | 126 | | VK_F16 | 127 | | VK_F17 | 128 | | VK_F18 | 129 | | VK_F19 | 130 | | VK_F20 | 131 | | VK_F21 | 132 | | VK_F22 | 133 | | VK_F23 | 134 | | VK_F24 | 135 | | VK_NUMLOCK | 144 | Num Lock | VK_SCROLL | 145 | Scroll | VK_LSHIFT | 160 | | VK_RSHIFT | 161 | | VK_LCONTROL | 162 | | VK_RCONTROL | 163 | | VK_LMENU | 164 | | VK_RMENU | 165 | | VK_BROWSER_BACK | 166 | | VK_BROWSER_FORWARD | 167 | | VK_BROWSER_REFRESH | 168 | | VK_BROWSER_STOP | 169 | | VK_BROWSER_SEARCH | 170 | | VK_BROWSER_FAVORITES | 171 | | VK_BROWSER_HOME | 172 | | VK_VOLUME_MUTE | 173 | VolumeMute | VK_VOLUME_DOWN | 174 | VolumeDown | VK_VOLUME_UP | 175 | VolumeUp | VK_MEDIA_NEXT_TRACK | 176 | | VK_MEDIA_PREV_TRACK | 177 | | VK_MEDIA_STOP | 178 | | VK_MEDIA_PLAY_PAUSE | 179 | | VK_LAUNCH_MAIL | 180 | | VK_LAUNCH_MEDIA_SELECT | 181 | | VK_LAUNCH_APP1 | 182 | | VK_LAUNCH_APP2 | 183 | | VK_OEM_1 | 186 | ; : | VK_OEM_PLUS | 187 | = + | VK_OEM_COMMA | 188 | | VK_OEM_MINUS | 189 | - _ | VK_OEM_PERIOD | 190 | | VK_OEM_2 | 191 | / ? | VK_OEM_3 | 192 | ` ~ | VK_OEM_4 | 219 | [ { | VK_OEM_5 | 220 | / | | VK_OEM_6 | 221 | ] } | VK_OEM_7 | 222 | ' " | VK_OEM_8 | 223 | | VK_OEM_102 | 226 | | VK_PACKET | 231 | | VK_PROCESSKEY | 229 | | VK_ATTN | 246 | | VK_CRSEL | 247 | | VK_EXSEL | 248 | | VK_EREOF | 249 | | VK_PLAY | 250 | | VK_ZOOM | 251 | | VK_NONAME | 252 | | VK_PA1 | 253 | | VK_OEM_CLEAR | 254 | |
|