虚拟键码保存在WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN和WM_SYSKEYUP讯息的wParam参数中。此代码标识按下或释放的键。
简介虚拟指的是假定存在于思想中而不是现实世界中的一些事物,也只有熟练使用DOS组合语言编写应用程式的程式写作者才有可能指出,为什么对Windows键盘处理如此基本的键码是虚拟的而不是真实的。
对于早期的程式写作者来说,真实的键码由实际键盘硬体产生。在Windows文件中将这些键码称为“扫描码(scan codes)”。在IBM相容机种上,扫描码16是Q键,17是W键,18是E、19是R,20是T,21是Y等等。这时您会发现,扫描码是依据键盘的实际布局的。Windows开发者认为这些代码过于与设备相关了,于是他们试图通过定义所谓的虚拟键码,以便经由与装置无关的方式处理键盘。其中一些虚拟键码不能在IBM相容机种上产生,但可能会在其他制造商生产的键盘中找到,或者在未来的键盘上找到。
您使用的大多数虚拟键码的名称在WINUSER.H头文件中都定义为以VK_开头。表1列出了这些名称和数值(十进位和十六进位),以及与虚拟键相对应的IBM相容机种键盘上的键。下表也标出了Windows执行时是否需要这些键。下表还按数位顺序列出了虚拟键码。
前四个虚拟键码中有三个指的是鼠标键:
表1
十进制
十六进制
winuser.h识别字
IBM相容键盘对应键
1
0x01
VK_LBUTTON
鼠标左键
2
0x02
VK_RBUTTON
鼠标右键
3
0x03
VK_CANCEL
Ctrl-Break
4
0x04
VK_MBUTTON
鼠标中键
您永远都不会从键盘讯息中获得这些鼠标键代码。VK_CANCEL代码是一个虚拟键码,它包括同时按下两个键(Ctrl-Break)。Windows应用程序通常不使用此键。
表2中的键——Backspace、Tab、Enter、Esc和空格——通常用于Windows程序。不过,Windows一般用字元讯息(而不是键盘讯息)来处理这些键。
表2
十进制
十六进制
winuser.h识别字
IBM相容键盘对应键
8
0x08
VK_BACK
Backspace
9
0x09
VK_TAB
Tab
12
0x0C
VK_CLEAR
NumLock关闭时的数字键盘5
13
0x0D
VK_RETURN
Enter
16
0x10
VK_SHIFT
Shift
17
0x11
VK_CONTROL
Ctrl
18
0x12
VK_MENU
Alt
19
0x13
VK_PAUSE
Pause
20
0x14
VK_CAPITAL
Caps Lock
27
0x1B
VK_ESCAPE
Esc
32
0x20
VK_SPACE
空格
另外,Windows程序通常不需要监视Shift、Ctrl或Alt键的状态。
表3列出的前八个码可能是与VK_INSERT和VK_DELETE一起最常用的虚拟键码:
表3
十进制
十六进制
winuser.h识别字
IBM相容键盘对应键
33
0x21
VK_PRIOR
Page Up
34
0x22
VK_NEXT
Page Down
35
0x23
VK_END
End
36
0x24
VK_HOME
Home
37
0x25
VK_LEFT
左箭头
38
0x26
VK_UP
上箭头
39
0x27
VK_RIGHT
右箭头
40
0x28
VK_DOWN
下箭头
41
0x29
VK_SELECT
42
0x2A
VK_PRINT
43
0x2B
VK_EXECUTE
44
0x2C
VK_SNAPSHOT
Print Screen
45
0x2D
VK_INSERT
Insert
46
0x2E
VK_DELETE
Delete
47
0x2F
VK_HELP
注意,许多名称(例如VK_PRIOR)Windows也包括在主键盘上的字母和数位键的虚拟键码(数字键盘将单独处理)。
表4
十进制
十六进制
WINUSER.H识别字
IBM相容键盘
48-57
30-39
无
主键盘上的0到9
65-90
41-5A
无
A到Z
注意,数字和字母的虚拟键码是ASCII码。Windows程序几乎从不使用这些虚拟键码;实际上,程序使用的是ASCII码字元的字元讯息。
表5所示的代码是由Microsoft Natural Keyboard及其相容键盘产生的:
表5
十进制
十六进制
WINUSER.H识别字
IBM相容键盘
91
5B
VK_LWIN
左Windows键
92
5C
VK_RWIN
右Windows键
Windows用VK_LWIN和VK_RWIN键打开“开始”菜单或者(在以前的版本中)启动“工作管理员程序”。这两个都可以用于登录或登出Windows(只在Microsoft Windows NT中有效),或者登录或登出网路(在Windows for Applications中)。应用程序能够通过显示辅助资讯或者当成快捷键看待来处理application键。
表6所示的代码用于小键盘上的键(如果有的话):
表6
十进制
十六进制
WINUSER.H识别字
IBM相容键盘
96-105
60-69
VK_NUMPAD0到VK_
NUMPAD9 NumLock打开时数字键盘上的0到9
106
6A
VK_MULTIPLY
数字键盘上的*
107
6B
VK_ADD
数字键盘上的+
108
6C
VK_SEPARATOR
109
6D
VK_SUBTRACT
数字键盘上的-
110
6E
VK_DECIMAL
数字键盘上的.
111
6F
VK_DIVIDE
数字键盘上的/
最後,虽然多数的键盘都有12个功能键,但Windows只需要10个,而位元旗标却有24个。另外,程式通常用功能键作为键盘加速键,这样,它们通常不处理表7所示的按键:
表7
十进制
十六进制
WINUSER.H识别字
IBM相容键盘
112-121
70-79
VK_F1到VK_F10
功能键F1到F10
122-135
7A-87
VK_F11到VK_F24
功能键F11到F24
144
90
VK_NUMLOCK
Num Lock
145
91
VK_SCROLL
Scroll Lock
另外,还定义了一些其他虚拟键码,但它们只用于非标准键盘上的键,或者通常在大型主机终端机上使用的键。查看/ Platform SDK / User Interface Services / User Input / Virtual-Key Codes,可得到完整的列表。
虚拟键表虚拟键码
对应值
对应键
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
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
左WIN键
VK_RWIN
92
右WIN键
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
左shift
VK_RSHIFT
161
右shift
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
完整的虚拟键码表1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
*VirtualKeys,StandardSet
*/
#defineVK_LBUTTON0x01
#defineVK_RBUTTON0x02
#defineVK_CANCEL0x03
#defineVK_MBUTTON0x04/*NOTcontiguouswithL&RBUTTON*/
#if(_WIN32_WINNT>=0x0500)
#defineVK_XBUTTON10x05/*NOTcontiguouswithL&RBUTTON*/
#defineVK_XBUTTON20x06/*NOTcontiguouswithL&RBUTTON*/
#endif/*_WIN32_WINNT>=0x0500*/
/*
*0x07:unassigned
*/
#defineVK_BACK0x08
#defineVK_TAB0x09
/*
*0x0A-0x0B:reserved
*/
#defineVK_CLEAR0x0C
#defineVK_RETURN0x0D
#defineVK_SHIFT0x10
#defineVK_CONTROL0x11
#defineVK_MENU0x12
#defineVK_PAUSE0x13
#defineVK_CAPITAL0x14
#defineVK_KANA0x15
#defineVK_HANGEUL0x15/*oldname-shouldbehereforcompatibility*/
#defineVK_HANGUL0x15
#defineVK_JUNJA0x17
#defineVK_FINAL0x18
#defineVK_HANJA0x19
#defineVK_KANJI0x19
#defineVK_ESCAPE0x1B
#defineVK_CONVERT0x1C
#defineVK_NONCONVERT0x1D
#defineVK_ACCEPT0x1E
#defineVK_MODECHANGE0x1F
#defineVK_SPACE0x20
#defineVK_PRIOR0x21
#defineVK_NEXT0x22
#defineVK_END0x23
#defineVK_HOME0x24
#defineVK_LEFT0x25
#defineVK_UP0x26
#defineVK_RIGHT0x27
#defineVK_DOWN0x28
#defineVK_SELECT0x29
#defineVK_PRINT0x2A
#defineVK_EXECUTE0x2B
#defineVK_SNAPSHOT0x2C
#defineVK_INSERT0x2D
#defineVK_DELETE0x2E
#defineVK_HELP0x2F
/*
*VK_0-VK_9arethesameasASCII'0'-'9'(0x30-0x39)
*0x40:unassigned
*VK_A-VK_ZarethesameasASCII'A'-'Z'(0x41-0x5A)
*/
#defineVK_LWIN0x5B
#defineVK_RWIN0x5C
#defineVK_APPS0x5D
/*
*0x5E:reserved
*/
#defineVK_SLEEP0x5F
#defineVK_NUMPAD00x60
#defineVK_NUMPAD10x61
#defineVK_NUMPAD20x62
#defineVK_NUMPAD30x63
#defineVK_NUMPAD40x64
#defineVK_NUMPAD50x65
#defineVK_NUMPAD60x66
#defineVK_NUMPAD70x67
#defineVK_NUMPAD80x68
#defineVK_NUMPAD90x69
#defineVK_MULTIPLY0x6A
#defineVK_ADD0x6B
#defineVK_SEPARATOR0x6C
#defineVK_SUBTRACT0x6D
#defineVK_DECIMAL0x6E
#defineVK_DIVIDE0x6F
#defineVK_F10x70
#defineVK_F20x71
#defineVK_F30x72
#defineVK_F40x73
#defineVK_F50x74
#defineVK_F60x75
#defineVK_F70x76
#defineVK_F80x77
#defineVK_F90x78
#defineVK_F100x79
#defineVK_F110x7A
#defineVK_F120x7B
#defineVK_F130x7C
#defineVK_F140x7D
#defineVK_F150x7E
#defineVK_F160x7F
#defineVK_F170x80
#defineVK_F180x81
#defineVK_F190x82
#defineVK_F200x83
#defineVK_F210x84
#defineVK_F220x85
#defineVK_F230x86
#defineVK_F240x87
/*
*0x88-0x8F:unassigned
*/
#defineVK_NUMLOCK0x90
#defineVK_SCROLL0x91
/*
*NECPC-9800kbddefinitions
*/
#defineVK_OEM_NEC_EQUAL0x92//'='keyonnumpad
/*
*Fujitsu/OASYSkbddefinitions
*/
#defineVK_OEM_FJ_JISHO0x92//'Dictionary'key
#defineVK_OEM_FJ_MASSHOU0x93//'Unregisterword'key
#defineVK_OEM_FJ_TOUROKU0x94//'Registerword'key
#defineVK_OEM_FJ_LOYA0x95//'LeftOYAYUBI'key
#defineVK_OEM_FJ_ROYA0x96//'RightOYAYUBI'key
/*
*0x97-0x9F:unassigned
*/
/*
*VK_L*&VK_R*-leftandrightAlt,CtrlandShiftvirtualkeys.
*UsedonlyasparameterstoGetAsyncKeyState()andGetKeyState().
*NootherAPIormessagewilldistinguishleftandrightkeysinthisway.
*/
#defineVK_LSHIFT0xA0
#defineVK_RSHIFT0xA1
#defineVK_LCONTROL0xA2
#defineVK_RCONTROL0xA3
#defineVK_LMENU0xA4
#defineVK_RMENU0xA5
#if(_WIN32_WINNT>=0x0500)
#defineVK_BROWSER_BACK0xA6
#defineVK_BROWSER_FORWARD0xA7
#defineVK_BROWSER_REFRESH0xA8
#defineVK_BROWSER_STOP0xA9
#defineVK_BROWSER_SEARCH0xAA
#defineVK_BROWSER_FAVORITES0xAB
#defineVK_BROWSER_HOME0xAC
#defineVK_VOLUME_MUTE0xAD
#defineVK_VOLUME_DOWN0xAE
#defineVK_VOLUME_UP0xAF
#defineVK_MEDIA_NEXT_TRACK0xB0
#defineVK_MEDIA_PREV_TRACK0xB1
#defineVK_MEDIA_STOP0xB2
#defineVK_MEDIA_PLAY_PAUSE0xB3
#defineVK_LAUNCH_MAIL0xB4
#defineVK_LAUNCH_MEDIA_SELECT0xB5
#defineVK_LAUNCH_APP10xB6
#defineVK_LAUNCH_APP20xB7
#endif/*_WIN32_WINNT>=0x0500*/
/*
*0xB8-0xB9:reserved
*/
#defineVK_OEM_10xBA//';:'forUS
#defineVK_OEM_PLUS0xBB//'+'anycountry
#defineVK_OEM_COMMA0xBC//','anycountry
#defineVK_OEM_MINUS0xBD//'-'anycountry
#defineVK_OEM_PERIOD0xBE//'.'anycountry
#defineVK_OEM_20xBF//'/?'forUS
#defineVK_OEM_30xC0//'`~'forUS
/*
*0xC1-0xD7:reserved
*/
/*
*0xD8-0xDA:unassigned
*/
#defineVK_OEM_40xDB//'[{'forUS
#defineVK_OEM_50xDC//'\|'forUS
#defineVK_OEM_60xDD//']}'forUS
#defineVK_OEM_70xDE//''"'forUS
#defineVK_OEM_80xDF
/*
*0xE0:reserved
*/
/*
*Variousextendedorenhancedkeyboards
*/
#defineVK_OEM_AX0xE1//'AX'keyonJapaneseAXkbd
#defineVK_OEM_1020xE2//""or"\|"onRT102-keykbd.
#defineVK_ICO_HELP0xE3//HelpkeyonICO
#defineVK_ICO_000xE4//00keyonICO
#if(WINVER>=0x0400)
#defineVK_PROCESSKEY0xE5
#endif/*WINVER>=0x0400*/
#defineVK_ICO_CLEAR0xE6
#if(_WIN32_WINNT>=0x0500)
#defineVK_PACKET0xE7
#endif/*_WIN32_WINNT>=0x0500*/
/*
*0xE8:unassigned
*/
/*
*Nokia/Ericssondefinitions
*/
#defineVK_OEM_RESET0xE9
#defineVK_OEM_JUMP0xEA
#defineVK_OEM_PA10xEB
#defineVK_OEM_PA20xEC
#defineVK_OEM_PA30xED
#defineVK_OEM_WSCTRL0xEE
#defineVK_OEM_CUSEL0xEF
#defineVK_OEM_ATTN0xF0
#defineVK_OEM_FINISH0xF1
#defineVK_OEM_COPY0xF2
#defineVK_OEM_AUTO0xF3
#defineVK_OEM_ENLW0xF4
#defineVK_OEM_BACKTAB0xF5
#defineVK_ATTN0xF6
#defineVK_CRSEL0xF7
#defineVK_EXSEL0xF8
#defineVK_EREOF0xF9
#defineVK_PLAY0xFA
#defineVK_ZOOM0xFB
#defineVK_NONAME0xFC
#defineVK_PA10xFD
#defineVK_OEM_CLEAR0xFE
/*
*0xFF:reserved
*/
当用户按下某个键时,
1.键盘会检测到这个动作,并通过键盘控制器把扫描码(scan code)传送到计算机;
键盘扫描码跟具体的硬件有关的,不同厂商对同一个键的扫描码有可能不同。
2.计算机接收到扫描码后,将其交给键盘驱动程序;
3.键盘驱动程序把这个扫描码转换为键盘虚拟码;虚拟码与具体硬件无关,不同厂商的键盘,同一个键的虚拟码总是相同的。
3.然后,键盘驱动程序把该键盘操作的扫描码和虚拟码以及其它信息传递给操作系统;
4.操作系统将获得的信息封装在一个键盘消息中,并把该键盘消息插入到消息列队。
5.通过Windows的消息系统,该键盘消息被送到某个窗口中;
6.窗口所在的应用程序接收到消息后,可以了解到有关键盘操作的信息,然后决定作出一定的响应
键盘消息:WM_KEYDOWN
nVirtKey = (int) wParam; // 虚拟码
lKeyData = lParam; // 键盘操作的相关信息
键盘消息WM_KEYDOWN的第二个参数lParam比较复杂
其作用是指定重复次数、扫描码、扩展键标记、上下文环境码、前键状态标记、转换状态标记等
lParam: 总长4字节,32位
0–15位:用于指定当前消息的重复次数。当用户按下某个键持续一段时间的话,
该值是自动计数的按下某键的次数;若按键时间很长,则会发出多个消息,
且重复次数不会累计
16–23:指定扫描码
24:指定是否该键是一个扩展键(如alt、ctrl),若值为1表示是扩展键,否则其值为0
25–28:保留
29:指定上下文环境码。对于WM_KEYDOWN、WM_KEYUP消息,其值总为0,
对WM_CHAR消息,如果同时alt键被按下,则值为1,否则值为0.
30:指定前键状态。如果消息发送前该键是按下状态,其值为1,否则为0
31:指定转换状态,对于WM_KEYDOWN,其值总为0;
对于WM_CHAR,如果该键被释放,则其值为1,否则为0.