键盘输入概述
应用程序应接受来自键盘和鼠标的用户输入。 应用程序以发布到其窗口的消息的形式接收键盘输入。
键盘输入模型
系统通过安装适用于当前键盘的键盘设备驱动程序,为应用程序提供与设备无关的键盘支持。 系统通过使用用户或应用程序当前选择的特定于语言的键盘布局,提供与语言无关的键盘支持。 键盘设备驱动程序从键盘接收扫描代码,这些代码将发送到键盘布局,在键盘布局中,扫描代码将转换为消息并发布到应用程序中的相应窗口。
分配给键盘上每个键的唯一值称为扫描代码,是键盘上键的设备相关标识符。 当用户键入某个键时,键盘会生成两个扫描代码,一个在用户按下该键时生成,另一个在用户松开该键时生成。
键盘设备驱动程序解释扫描代码并将其转换(映射)为虚拟键代码,这是一个由系统定义的独立于设备的值,用于标识键的用途。 转换扫描代码后,键盘布局会创建一条消息,其中包含扫描代码、虚拟键代码和有关击键的其他信息,然后将该消息置于系统消息队列中。 系统将该消息从系统消息队列中删除,并将其发布到相应线程的消息队列。 最终,线程的消息循环会删除该消息,并将其传递给相应的窗口过程进行处理。 下图演示了键盘输入模型。
键盘焦点和激活
系统将键盘消息发布到创建具有键盘焦点的窗口的前台线程的消息队列。 键盘焦点是窗口的临时属性。 系统将键盘焦点从一个窗口移动到另一个窗口,从而在显示器上的所有窗口之间共享键盘。 具有键盘焦点的窗口(从创建它的线程的消息队列)接收所有键盘消息,直到焦点更改为其他窗口。
线程可以调用 GetFocus 函数来确定哪个窗口(如果有)当前具有键盘焦点。 线程可以通过调用 SetFocus 函数将键盘焦点赋予其中一个窗口。 将键盘焦点从一个窗口更改为另一个窗口时,系统会向失去焦点的窗口发送 WM_KILLFOCUS 消息,然后向获得焦点的窗口发送 WM_SETFOCUS 消息。
键盘焦点的概念与活动窗口的概念相关。 活动窗口是用户当前正在使用的顶级窗口。 具有键盘焦点的窗口要么是活动窗口,要么是活动窗口的子窗口。 为了帮助用户识别活动窗口,系统会将其置于 Z 顺序的顶部并突出显示其标题栏(如果有)和边框。
用户可以通过单击顶级窗口、使用 ALT+TAB 或 Alt+ESC 组合键选择它或从“任务列表”中选择它来激活该窗口。 线程可以使用 SetActiveWindow 函数激活顶级窗口。 它可以使用 GetActiveWindow 函数确定所创建的顶级窗口是否处于活动状态。
当一个窗口停用而另一个窗口被激活时,系统会发送 WM_ACTIVATE 消息。 如果正在停用窗口,则 wParam 参数的低序字为零,如果正在激活窗口,则为非零。 默认窗口过程收到 WM_ACTIVATE 消息后,便会将键盘焦点设置到活动窗口。
若要阻止键盘和鼠标输入事件到达应用程序,请使用 BlockInput。 请注意,BlockInput 函数不会干扰异步键盘输入状态表。 这意味着在输入被阻止时调用 SendInput 函数将更改异步键盘输入状态表。
击键消息
按下键会使 WM_KEYDOWN 或 WM_SYSKEYDOWN 消息被放入附加到具有键盘焦点的窗口的线程消息队列中。 松开键会使 WM_KEYUP 或 WM_SYSKEYUP 消息被放入队列中。
按下键和松开键消息通常是相伴发生的,但如果用户长按一个键,以致键盘的自动重复功能启动,则系统会连续生成许多 WM_KEYDOWN 或 WM_SYSKEYDOWN 消息。 然后,当用户松开键时,它会生成一条 WM_KEYUP 或 WM_SYSKEYUP 消息。
本部分涵盖了以下主题:
系统和非系统击键
系统区分系统击键和非系统击键。 系统击键会生成系统击键消息 WM_SYSKEYDOWN 和 WM_SYSKEYUP。 非系统击键会生成非系统击键消息 WM_KEYDOWN 和 WM_KEYUP。
如果窗口过程必须处理系统击键消息,请确保在处理消息后,过程将其传递给 DefWindowProc 函数。 否则,只要窗口具有键盘焦点,所有涉及 ALT 键的系统操作都将被禁用。 也就是说,用户将无法访问窗口的菜单或系统菜单,或使用 Alt+ESC 或 ALT+TAB 组合键激活其他窗口。
系统击键消息主要供系统而不是应用程序使用。 系统使用它们向菜单提供其内置键盘界面,并允许用户控制哪个窗口处于活动状态。 当用户键入一个键并同时键入 ALT 键时,或者当用户键入且没有窗口具有键盘焦点时(例如,活动应用程序最小化时),将生成系统击键消息。 在这种情况下,消息将发布到附加到活动窗口的消息队列。
非系统击键消息供应用程序窗口使用;DefWindowProc 函数不对其执行任何操作。 窗口过程可以丢弃它不需要的任何非系统击键消息。
描述的虚拟键代码
击键消息的 wParam 参数包含按下或松开的键的虚拟键代码。 窗口过程根据虚拟键代码的值处理或忽略击键消息。
典型的窗口过程仅处理它接收到的击键消息的一小部分,而忽略其余部分。 例如,窗口过程可能仅处理 WM_KEYDOWN 击键消息,并且仅处理那些包含光标移动键、Shift 键(也称为控制键)和功能键的虚拟键代码的消息。 典型的窗口过程不处理来自字符键的击键消息。 相反,它使用 TranslateMessage 函数将消息转换为字符消息。 有关 TranslateMessage 和字符消息的详细信息,请参阅字符消息。
击键消息标志
击键消息的 lParam 参数包含有关生成该消息的击键的附加信息。 此信息包括重复计数、扫描代码、扩展键标志、上下文代码、上一个键状态标志和转换状态标志。 下图显示了这些标志和值在 lParam 参数中的位置。
应用程序可以使用以下值从 lParam 的高位字中获取击键标志。
值 | 说明 |
---|---|
KF_EXTENDED 0x0100 |
操作扩展键标志。 |
KF_DLGMODE 0x0800 |
操作对话框模式标志,该标志指示对话框是否处于活动状态。 |
KF_MENUMODE 0x1000 |
操作菜单模式标志,该标志指示菜单是否处于活动状态。 |
KF_ALTDOWN 0x2000 |
操作上下文代码标志。 |
KF_REPEAT 0x4000 |
操作上一个键状态标志。 |
KF_UP 0x8000 |
操作转换状态标志。 |
示例代码:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
WORD vkCode = LOWORD(wParam); // virtual-key code
WORD keyFlags = HIWORD(lParam);
WORD scanCode = LOBYTE(keyFlags); // scan code
BOOL isExtendedKey = (keyFlags & KF_EXTENDED) == KF_EXTENDED; // extended-key flag, 1 if scancode has 0xE0 prefix
if (isExtendedKey)
scanCode = MAKEWORD(scanCode, 0xE0);
BOOL wasKeyDown = (keyFlags & KF_REPEAT) == KF_REPEAT; // previous key-state flag, 1 on autorepeat
WORD repeatCount = LOWORD(lParam); // repeat count, > 0 if several keydown messages was combined into one message
BOOL isKeyReleased = (keyFlags & KF_UP) == KF_UP; // transition-state flag, 1 on keyup
// if we want to distinguish these keys:
switch (vkCode)
{
case VK_SHIFT: // converts to VK_LSHIFT or VK_RSHIFT
case VK_CONTROL: // converts to VK_LCONTROL or VK_RCONTROL
case VK_MENU: // converts to VK_LMENU or VK_RMENU
vkCode = LOWORD(MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK_EX));
break;
}
// ...
}
break;
重复计数
可以检查重复计数,以确定一个击键消息是否表示多个击键。 当键盘生成 WM_KEYDOWN 或 WM_SYSKEYDOWN 消息的速度快于应用程序处理它们的速度时,系统会增加计数。 当用户长按某个键,以致键盘的自动重复功能启动时,通常会发生这种情况。 系统不会将生成的按键消息填充到系统消息队列中,而是将消息组合成单个按键消息并增加重复计数。 松开键无法启动自动重复功能,因此 WM_KEYUP 和 WM_SYSKEYUP 消息的重复计数始终设置为 1。
扫描代码
扫描代码是系统在用户按下某个键时生成的值。 它是一个值,该值标识按下的键(不考虑活动键盘布局),而不是由键表示的字符。 应用程序通常忽略扫描代码。 它使用虚拟键代码来解释击键消息。
新式键盘使用人机接口设备 (HID) 规范与计算机通信。 键盘驱动程序会将从键盘发送的已报告 HID 使用值转换为扫描代码并将其传递到应用程序。
注意
虽然虚拟键代码通常对桌面应用程序更有用,但在需要知道按下哪个键(不考虑当前的键盘布局)的特殊情况下,可能需要使用扫描代码。 例如,用于游戏的 WASD(W 向上、A 向左、S 向下和 D 向右)键绑定,这可确保跨 US QWERTY 或 French AZERTY 键盘布局的一致键结构。
下表列出了 Windows 目前识别的扫描代码集。 HID 使用页面/HID 使用 ID/HID 使用名称值引用 HID 使用表文档。 键位置值引用前面的键盘图像。
Scan 1 Make 代码在 WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP 和 WM_INPUT 消息中传递。
HID 使用页面名称 | HID 用法名称 | HID 使用页面 | HID 用法 ID | Scan 1 Make | 键位置 |
---|---|---|---|---|---|
通用桌面 | 系统断电 | 0x0001 | 0x0081 | 0xE05E | |
通用桌面 | 系统睡眠 | 0x0001 | 0x0082 | 0xE05F | |
通用桌面 | 系统唤醒 | 0x0001 | 0x0083 | 0xE063 | |
键盘/小键盘 | ErrorRollOver | 0x0007 | 0x0001 | 0x00FF | |
键盘/小键盘 | 键盘 A | 0x0007 | 0x0004 | 0x001E | 31 |
键盘/小键盘 | 键盘 B | 0x0007 | 0x0005 | 0x0030 | 50 |
键盘/小键盘 | 键盘 C | 0x0007 | 0x0006 | 0x002E | 48 |
键盘/小键盘 | 键盘 D | 0x0007 | 0x0007 | 0x0020 | 33 |
键盘/小键盘 | 键盘 E | 0x0007 | 0x0008 | 0x0012 | 19 |
键盘/小键盘 | 键盘 F | 0x0007 | 0x0009 | 0x0021 | 34 |
键盘/小键盘 | 键盘 G | 0x0007 | 0x000A | 0x0022 | 35 |
键盘/小键盘 | 键盘 H | 0x0007 | 0x000B | 0x0023 | 36 |
键盘/小键盘 | 键盘 I | 0x0007 | 0x000C | 0x0017 | 24 |
键盘/小键盘 | 键盘 J | 0x0007 | 0x000D | 0x0024 | 37 |
键盘/小键盘 | 键盘 K | 0x0007 | 0x000E | 0x0025 | 38 |
键盘/小键盘 | 键盘 L | 0x0007 | 0x000F | 0x0026 | 39 |
键盘/小键盘 | 键盘 M | 0x0007 | 0x0010 | 0x0032 | 52 |
键盘/小键盘 | 键盘 N | 0x0007 | 0x0011 | 0x0031 | 51 |
键盘/小键盘 | 键盘 O | 0x0007 | 0x0012 | 0x0018 | 25 |
键盘/小键盘 | 键盘 P | 0x0007 | 0x0013 | 0x0019 | 26 |
键盘/小键盘 | 键盘 Q | 0x0007 | 0x0014 | 0x0010 | 17 |
键盘/小键盘 | 键盘 R | 0x0007 | 0x0015 | 0x0013 | 20 |
键盘/小键盘 | 键盘 S | 0x0007 | 0x0016 | 0x001F | 32 |
键盘/小键盘 | 键盘 T | 0x0007 | 0x0017 | 0x0014 | 21 |
键盘/小键盘 | 键盘 U | 0x0007 | 0x0018 | 0x0016 | 23 |
键盘/小键盘 | 键盘 V | 0x0007 | 0x0019 | 0x002F | 49 |
键盘/小键盘 | 键盘 W | 0x0007 | 0x001A | 0x0011 | 18 |
键盘/小键盘 | 键盘 X | 0x0007 | 0x001B | 0x002D | 47 |
键盘/小键盘 | 键盘 Y | 0x0007 | 0x001C | 0x0015 | 22 |
键盘/小键盘 | 键盘 Z | 0x0007 | 0x001D | 0x002C | 46 |
键盘/小键盘 | 键盘 1 和 ! | 0x0007 | 0x001E | 0x0002 | 2 |
键盘/小键盘 | 键盘 2 和 @ | 0x0007 | 0x001F | 0x0003 | 3 |
键盘/小键盘 | 键盘 3 和 # | 0x0007 | 0x0020 | 0x0004 | 4 |
键盘/小键盘 | 键盘 4 和 $ | 0x0007 | 0x0021 | 0x0005 | 5 |
键盘/小键盘 | 键盘 5 和 % | 0x0007 | 0x0022 | 0x0006 | 6 |
键盘/小键盘 | 键盘 6 和 ^ | 0x0007 | 0x0023 | 0x0007 | 7 |
键盘/小键盘 | 键盘 7 和 & | 0x0007 | 0x0024 | 0x0008 | 8 |
键盘/小键盘 | 键盘 8 和 * | 0x0007 | 0x0025 | 0x0009 | 9 |
键盘/小键盘 | 键盘 9 和 ( | 0x0007 | 0x0026 | 0x000A | 10 |
键盘/小键盘 | 键盘 0 和 ) | 0x0007 | 0x0027 | 0x000B | 11 |
键盘/小键盘 | 键盘回车 Enter 键 | 0x0007 | 0x0028 | 0x001C | 43 |
键盘/小键盘 | 键盘 Escape 键 | 0x0007 | 0x0029 | 0x0001 | 110 |
键盘/小键盘 | 键盘 Delete 键 | 0x0007 | 0x002A | 0x000E | 15 |
键盘/小键盘 | 键盘 Tab 键 | 0x0007 | 0x002B | 0x000F | 16 |
键盘/小键盘 | 键盘空格键 | 0x0007 | 0x002C | 0x0039 | 61 |
键盘/小键盘 | 键盘 - 和 _ | 0x0007 | 0x002D | 0x000C | 12 |
键盘/小键盘 | 键盘 = 和 + | 0x0007 | 0x002E | 0x000D | 13 |
键盘/小键盘 | 键盘 { | 0x0007 | 0x002F | 0x001A | 27 |
键盘/小键盘 | 键盘 } | 0x0007 | 0x0030 | 0x001B | 28 |
键盘/小键盘 | 键盘 | 和 \ | 0x0007 | 0x0031 | 0x002B | 29 |
键盘/小键盘 | 键盘非美国 | 0x0007 | 0x0032 | 0x002B | 42 |
键盘/小键盘 | 键盘 ; 和 : | 0x0007 | 0x0033 | 0x0027 | 40 |
键盘/小键盘 | 键盘 ‘ 和 “ | 0x0007 | 0x0034 | 0x0028 | 41 |
键盘/小键盘 | 键盘 ` 和 ~ | 0x0007 | 0x0035 | 0x0029 | 1 |
键盘/小键盘 | 键盘 , | 0x0007 | 0x0036 | 0x0033 | 53 |
键盘/小键盘 | 键盘 . | 0x0007 | 0x0037 | 0x0034 | 54 |
键盘/小键盘 | 键盘 ? | 0x0007 | 0x0038 | 0x0035 | 55 |
键盘/小键盘 | 键盘 Caps Lock | 0x0007 | 0x0039 | 0x003A | 30 |
键盘/小键盘 | 键盘 F1 | 0x0007 | 0x003A | 0x003B | 112 |
键盘/小键盘 | 键盘 F2 | 0x0007 | 0x003B | 0x003C | 113 |
键盘/小键盘 | 键盘 F3 | 0x0007 | 0x003C | 0x003D | 114 |
键盘/小键盘 | 键盘 F4 | 0x0007 | 0x003D | 0x003E | 115 |
键盘/小键盘 | 键盘 F5 | 0x0007 | 0x003E | 0x003F | 116 |
键盘/小键盘 | 键盘 F6 | 0x0007 | 0x003F | 0x0040 | 117 |
键盘/小键盘 | 键盘 F7 | 0x0007 | 0x0040 | 0x0041 | 118 |
键盘/小键盘 | 键盘 F8 | 0x0007 | 0x0041 | 0x0042 | 119 |
键盘/小键盘 | 键盘 F9 | 0x0007 | 0x0042 | 0x0043 | 120 |
键盘/小键盘 | 键盘 F10 | 0x0007 | 0x0043 | 0x0044 | 121 |
键盘/小键盘 | 键盘 F11 | 0x0007 | 0x0044 | 0x0057 | 122 |
键盘/小键盘 | 键盘 F12 | 0x0007 | 0x0045 | 0x0058 | 123 |
键盘/小键盘 | 键盘 PrintScreen 键 | 0x0007 | 0x0046 | 0xE037 0x0054 *注意 1 |
124 |
键盘/小键盘 | 键盘 Scroll Lock 键 | 0x0007 | 0x0047 | 0x0046 | 125 |
键盘/小键盘 | 键盘 Pause 键 | 0x0007 | 0x0048 | 0xE11D45 0xE046 *注意 2 0x0045 *注意 3 |
126 |
键盘/小键盘 | 键盘 Insert 键 | 0x0007 | 0x0049 | 0xE052 | 75 |
键盘/小键盘 | 键盘 Home 键 | 0x0007 | 0x004A | 0xE047 | 80 |
键盘/小键盘 | 键盘 PageUp 键 | 0x0007 | 0x004B | 0xE049 | 85 |
键盘/小键盘 | 键盘 Delete Forward 键 | 0x0007 | 0x004C | 0xE053 | 76 |
键盘/小键盘 | 键盘 End 键 | 0x0007 | 0x004D | 0xE04F | 81 |
键盘/小键盘 | 键盘 PageDown 键 | 0x0007 | 0x004E | 0xE051 | 86 |
键盘/小键盘 | 键盘向右键 | 0x0007 | 0x004F | 0xE04D | 89 |
键盘/小键盘 | 键盘向左键 | 0x0007 | 0x0050 | 0xE04B | 79 |
键盘/小键盘 | 键盘向下键 | 0x0007 | 0x0051 | 0xE050 | 84 |
键盘/小键盘 | 键盘向上键 | 0x0007 | 0x0052 | 0xE048 | 83 |
键盘/小键盘 | 小键盘 Num Lock 和清除键 | 0x0007 | 0x0053 | 0x0045 0xE045 *注意 3 |
90 |
键盘/小键盘 | 小键盘 / | 0x0007 | 0x0054 | 0xE035 | 95 |
键盘/小键盘 | 小键盘 * | 0x0007 | 0x0055 | 0x0037 | 100 |
键盘/小键盘 | 小键盘 - | 0x0007 | 0x0056 | 0x004A | 105 |
键盘/小键盘 | 小键盘 + | 0x0007 | 0x0057 | 0x004E | 106 |
键盘/小键盘 | 小键盘 ENTER | 0x0007 | 0x0058 | 0xE01C | 108 |
键盘/小键盘 | 小键盘 1 和 End | 0x0007 | 0x0059 | 0x004F | 93 |
键盘/小键盘 | 小键盘 2 和向下键 | 0x0007 | 0x005A | 0x0050 | 98 |
键盘/小键盘 | 小键盘 3 和 PageDn | 0x0007 | 0x005B | 0x0051 | 103 |
键盘/小键盘 | 小键盘 4 和向左键 | 0x0007 | 0x005C | 0x004B | 92 |
键盘/小键盘 | 小键盘 5 | 0x0007 | 0x005D | 0x004C | 97 |
键盘/小键盘 | 小键盘 6 和向左键 | 0x0007 | 0x005E | 0x004D | 102 |
键盘/小键盘 | 小键盘 7 和 Home | 0x0007 | 0x005F | 0x0047 | 91 |
键盘/小键盘 | 小键盘 8 和向上键 | 0x0007 | 0x0060 | 0x0048 | 96 |
键盘/小键盘 | 小键盘 9 和 PageUp | 0x0007 | 0x0061 | 0x0049 | 101 |
键盘/小键盘 | 小键盘 0 和 Insert | 0x0007 | 0x0062 | 0x0052 | 99 |
键盘/小键盘 | 小键盘 . | 0x0007 | 0x0063 | 0x0053 | 104 |
键盘/小键盘 | 键盘非美国斜杠 | 0x0007 | 0x0064 | 0x0056 | 45 |
键盘/小键盘 | 键盘应用程序键 | 0x0007 | 0x0065 | 0xE05D | 129 |
键盘/小键盘 | 键盘电源键 | 0x0007 | 0x0066 | 0xE05E | |
键盘/小键盘 | 小键盘 = | 0x0007 | 0x0067 | 0x0059 | |
键盘/小键盘 | 键盘 F13 | 0x0007 | 0x0068 | 0x0064 | |
键盘/小键盘 | 键盘 F14 | 0x0007 | 0x0069 | 0x0065 | |
键盘/小键盘 | 键盘 F15 | 0x0007 | 0x006A | 0x0066 | |
键盘/小键盘 | 键盘 F16 | 0x0007 | 0x006B | 0x0067 | |
键盘/小键盘 | 键盘 F17 | 0x0007 | 0x006C | 0x0068 | |
键盘/小键盘 | 键盘 F18 | 0x0007 | 0x006D | 0x0069 | |
键盘/小键盘 | 键盘 F19 | 0x0007 | 0x006E | 0x006A | |
键盘/小键盘 | 键盘 F20 | 0x0007 | 0x006F | 0x006B | |
键盘/小键盘 | 键盘 F21 | 0x0007 | 0x0070 | 0x006C | |
键盘/小键盘 | 键盘 F22 | 0x0007 | 0x0071 | 0x006D | |
键盘/小键盘 | 键盘 F23 | 0x0007 | 0x0072 | 0x006E | |
键盘/小键盘 | 键盘 F24 | 0x0007 | 0x0073 | 0x0076 | |
键盘/小键盘 | 小键盘 , | 0x0007 | 0x0085 | 0x007E | 107 *注意 4 |
键盘/小键盘 | 键盘 International1 | 0x0007 | 0x0087 | 0x0073 | 56 *注意 4、5 |
键盘/小键盘 | 键盘 International2 | 0x0007 | 0x0088 | 0x0070 | 133 *注意 5 |
键盘/小键盘 | 键盘 International3 | 0x0007 | 0x0089 | 0x007D | 14 *注意 5 |
键盘/小键盘 | 键盘 International4 | 0x0007 | 0x008A | 0x0079 | 132 *注意 5 |
键盘/小键盘 | 键盘 International5 | 0x0007 | 0x008B | 0x007B | 131 *注意 5 |
键盘/小键盘 | 键盘 International6 | 0x0007 | 0x008C | 0x005C | |
键盘/小键盘 | 键盘 LANG1 | 0x0007 | 0x0090 | 0x0072 *注意 6 0x00F2 *注意 3、6 |
|
键盘/小键盘 | 键盘 LANG2 | 0x0007 | 0x0091 | 0x0071 *注意 6 0x00F1 *注意 3、6 |
|
键盘/小键盘 | 键盘 LANG3 | 0x0007 | 0x0092 | 0x0078 | |
键盘/小键盘 | 键盘 LANG4 | 0x0007 | 0x0093 | 0x0077 | |
键盘/小键盘 | 键盘 LANG5 | 0x0007 | 0x0094 | 0x0076 | |
键盘/小键盘 | 键盘 LeftControl | 0x0007 | 0x00E0 | 0x001D | 58 |
键盘/小键盘 | 键盘 LeftShift | 0x0007 | 0x00E1 | 0x002A | 44 |
键盘/小键盘 | 键盘 LeftAlt | 0x0007 | 0x00E2 | 0x0038 | 60 |
键盘/小键盘 | 键盘 Left GUI | 0x0007 | 0x00E3 | 0xE05B | 127 |
键盘/小键盘 | 键盘 RightControl | 0x0007 | 0x00E4 | 0xE01D | 64 |
键盘/小键盘 | 键盘 RightShift | 0x0007 | 0x00E5 | 0x0036 | 57 |
键盘/小键盘 | 键盘 RightAlt | 0x0007 | 0x00E6 | 0xE038 | 62 |
键盘/小键盘 | 键盘 Right GUI | 0x0007 | 0x00E7 | 0xE05C | 128 |
消费者 | 扫描下一个曲目 | 0x000C | 0x00B5 | 0xE019 | |
消费者 | 扫描上一个曲目 | 0x000C | 0x00B6 | 0xE010 | |
消费者 | 停止 | 0x000C | 0x00B7 | 0xE024 | |
消费者 | 播放/暂停 | 0x000C | 0x00CD | 0xE022 | |
消费者 | 静音 | 0x000C | 0x00E2 | 0xE020 | |
消费者 | 音量增大 | 0x000C | 0x00E9 | 0xE030 | |
消费者 | 音量减小 | 0x000C | 0x00EA | 0xE02E | |
消费者 | AL 使用者控制配置 | 0x000C | 0x0183 | 0xE06D | |
消费者 | AL 电子邮件阅读器 | 0x000C | 0x018A | 0xE06C | |
消费者 | AL 计算器 | 0x000C | 0x0192 | 0xE021 | |
消费者 | AL 本地计算机浏览器 | 0x000C | 0x0194 | 0xE06B | |
消费者 | AC 搜索 | 0x000C | 0x0221 | 0xE065 | |
消费者 | AC 开始 | 0x000C | 0x0223 | 0xE032 | |
消费者 | AC 返回 | 0x000C | 0x0224 | 0xE06A | |
消费者 | AC 向前 | 0x000C | 0x0225 | 0xE069 | |
消费者 | AC 停止 | 0x000C | 0x0226 | 0xE068 | |
消费者 | AC 刷新 | 0x000C | 0x0227 | 0xE067 | |
消费者 | AC 书签 | 0x000C | 0x022A | 0xE066 |
注意:
- “Alt+Print screen”击键时发出“SysRq”键扫描代码
- “Control+Pause”击键时发出“Break”键扫描代码
- 如旧版键盘消息所示
- 键存在于巴西键盘上
- 键存在于日本键盘上
- 此扫描代码仅在键松开事件中发出
扩展键标志
扩展键标志指示击键消息是否源自增强型 101/102 键键盘上的一个附加键。 扩展键包括键盘右侧的 ALT 和 CTRL 键;INS、DEL、HOME、END、PAGE UP、PAGE DOWN 和数字键盘左侧键群中的方向键;NUM LOCK 键;BREAK (CTRL+PAUSE) 键;PRINT SCRN 键;以及数字键盘中的斜杠 (/) 和 ENTER 键。 右侧 SHIFT 键不被视为扩展键,它有一个单独的扫描代码。
如果指定,则扫描代码由两个字节的序列组成,其中第一个字节的值为 0xE0。
上下文代码
上下文代码指示生成击键消息时是否按下 ALT 键。 如果按下 ALT 键则代码为 1,如果不按则为 0。
上一个键状态标志
上一个键状态标志指示生成击键消息的键先前是否被按下。 如果键之前被按下,则为 1;如果键之前未按下,则为 0。 可以使用此标志来标识键盘的自动重复功能生成的击键消息。 对于自动重复功能生成的 WM_KEYDOWN 和 WM_SYSKEYDOWN 击键消息,此标志设置为 1。 对于 WM_KEYUP 和 WM_SYSKEYUP 消息,它始终设置为 1。
转换状态标志
转换状态标志指示是按下键还是松开键生成击键消息。 对于 WM_KEYDOWN 和 WM_SYSKEYDOWN 消息,此标志始终设置为 0;对于 WM_KEYUP 和 WM_SYSKEYUP 消息,它始终设置为 1。
字符消息
击键消息提供有关击键的大量信息,但它们不提供字符击键的字符代码。 若要检索字符代码,应用程序必须在其线程消息循环中包含 TranslateMessage 函数。 TranslateMessage 将 WM_KEYDOWN 或 WM_SYSKEYDOWN 消息传递到键盘布局。 布局检查消息的虚拟键代码,如果它对应于字符键,则提供等效的字符代码(考虑到 SHIFT 和 CAPS LOCK 键的状态)。 然后,它会生成包含字符代码的字符消息,并将消息置于消息队列的顶部。 消息循环的下一次迭代会从队列中删除字符消息,并将消息调度到相应的窗口过程。
本部分涵盖了以下主题:
非系统字符消息
窗口过程可以接收以下字符消息:WM_CHAR、WM_DEADCHAR、WM_SYSCHAR、WM_SYSDEADCHAR 和 WM_UNICHAR。 TranslateMessage 函数在处理 WM_KEYDOWN 消息时会生成 WM_CHAR 或 WM_DEADCHAR 消息。 同样,它在处理 WM_SYSKEYDOWN 消息时会生成 WM_SYSCHAR 或 WM_SYSDEADCHAR 消息。
处理键盘输入的应用程序通常会忽略除 WM_CHAR 和 WM_UNICHAR 消息之外的所有消息,将任何其他消息传递给 DefWindowProc 函数。 请注意,WM_CHAR 使用 UTF-16(16 位 Unicode 转换格式)或 ANSI 字符集,而 WM_UNICHAR 始终使用 UTF-32(32 位 Unicode 转换格式)。 系统使用 WM_SYSCHAR 和 WM_SYSDEADCHAR 消息来实现菜单助记键。
所有字符消息的 wParam 参数包含按下的字符键的字符代码。 字符代码的值取决于接收消息的窗口的窗口类。 如果使用 RegisterClass 函数的 Unicode 版本注册窗口类,系统会为该类的所有窗口提供 Unicode 字符。 否则,系统会提供 ANSI 字符代码。 有关详细信息,请参阅注册窗口类和在 Windows 应用中使用 UTF-8 代码页。
字符消息的 lParam 参数的内容与被转换为生成字符消息的按键消息的 lParam 参数的内容相同。 有关信息,请参阅击键消息标志。
死字符消息
某些非英语键盘包含不应自行生成字符的字符键。 相反,它们用于向后续击键生成的字符添加变音符。 这些键称为死键。 德语键盘上的长音符键是死键的一个示例。 若要输入包含带长音符的“o”的字符,德国用户会键入长音符键,然后键入“o”键。 具有键盘焦点的窗口将收到以下消息序列:
TranslateMessage 在处理来自死键的 WM_KEYDOWN 消息时生成 WM_DEADCHAR 消息。 尽管 WM_DEADCHAR 消息的 wParam 参数包含死键变音符的字符代码,但应用程序通常会忽略该消息。 相反,它会处理后续击键生成的 WM_CHAR 消息。 WM_CHAR 消息的 wParam 参数包含带有变音符的字母的字符代码。 如果后续击键生成的字符不能与变音符组合,系统会生成两条 WM_CHAR 消息。 第一个 wParam 参数包含变音符的字符代码;第二个 wParam 参数包含后续字符键的字符代码。
TranslateMessage 函数在处理来自系统死键(与 ALT 键一起按下的死键)的 WM_SYSKEYDOWN 消息时生成 WM_SYSDEADCHAR 消息。 应用程序通常会忽略 WM_SYSDEADCHAR 消息。
密钥状态
在处理键盘消息时,应用程序可能需要确定除生成当前消息的那个键之外的另一个键的状态。 例如,允许用户按 SHIFT+END 选择文本块的文字处理应用程序必须在收到来自 END 键的击键消息时检查 SHIFT 键的状态。 应用程序可以使用 GetKeyState 函数来确定生成当前消息时虚拟键的状态;它可以使用 GetAsyncKeyState 函数来检索虚拟键的当前状态。
键盘布局保留名称列表。 生成单个字符的键的名称与键生成的字符的名称相同。 非字符键(如 TAB 和 ENTER)的名称存储为字符串。 应用程序可以通过调用 GetKeyNameText 函数从设备驱动程序检索任何键的名称。
击键和字符转换
该系统包括几个特殊用途函数,用于转换各种击键消息提供的扫描代码、字符代码和虚拟键代码。 这些函数包括 MapVirtualKey、ToAscii、ToUnicode 和 VkKeyScan。
此外,Microsoft Rich Edit 3.0 还支持 HexToUnicode IME,它允许用户使用热键在十六进制字符和 Unicode 字符之间进行转换。 这意味着,当 Microsoft Rich Edit 3.0 合并到应用程序中时,应用程序将继承 HexToUnicode IME 的功能。
热键支持
热键是一种组合键,用于生成 WM_HOTKEY 消息,即系统放置在线程消息队列顶部的消息,绕过队列中的任何现有消息。 应用程序使用热键从用户处获取高优先级键盘输入。 例如,通过定义由 CTRL+C 组合键组成的热键,应用程序可以允许用户取消冗长的操作。
为了定义热键,应用程序调用 RegisterHotKey 函数,指定生成 WM_HOTKEY 消息的键的组合、用于接收消息的窗口句柄以及热键的标识符。 当用户按下热键时,WM_HOTKEY 消息将放入创建窗口的线程的消息队列中。 消息的 wParam 参数包含热键的标识符。 应用程序可以为一个线程定义多个热键,但线程中的每个热键必须具有唯一标识符。 在应用程序终止之前,它应使用 UnregisterHotKey 函数销毁热键。
应用程序可以使用热键控件,便于用户轻松选择热键。 热键控件通常用于定义激活窗口的热键;它们不使用 RegisterHotKey 和 UnregisterHotKey 函数。 相反,使用热键控件的应用程序通常会发送 WM_SETHOTKEY 消息来设置热键。 每当用户按下热键时,系统都会发送一条指定 SC_HOTKEY 的 WM_SYSCOMMAND 消息。 有关热键控件的详细信息,请参阅热键控件中的“使用热键控件”。
用于浏览和其他功能的键盘键
Windows 支持带有特殊键的键盘,用于浏览器功能、媒体功能、应用程序启动和电源管理。 WM_APPCOMMAND 支持额外的键盘键。 此外,还修改了 ShellProc 函数以支持额外的键盘键。
组件应用程序中的子窗口不太可能能够直接实现这些额外键盘键的命令。 因此,按下其中一个键时,DefWindowProc 会向窗口发送 WM_APPCOMMAND 消息。 DefWindowProc 还会将 WM_APPCOMMAND 消息发送到其父窗口(以气泡形式)。 这类似于使用鼠标右键调用上下文菜单的方式,即 DefWindowProc 在右键单击时发送 WM_CONTEXTMENU 消息,并将其发送到其父项(以气泡形式)。 此外,如果 DefWindowProc 收到顶级窗口的 WM_APPCOMMAND 消息,它将调用代码为 HSHELL_APPCOMMAND 的 shell 挂钩。
Windows 还支持 Microsoft IntelliMouse Explorer,它是一个有五个按钮的鼠标。 两个额外的按钮支持向前和向后浏览器导航。 有关详细信息,请参阅XBUTTON。
模拟输入
若要模拟一系列不间断的用户输入事件,请使用 SendInput 函数。 函数接受三个参数。 第一个参数 cInputs 指示将模拟的输入事件数。 第二个参数 rgInputs 是一个 INPUT 结构数组,每个结构都描述一种输入事件类型和有关该事件的附加信息。 最后一个参数 cbSize 接受 INPUT 结构的大小(以字节为单位)。
SendInput 函数的工作原理是将一系列模拟输入事件注入设备的输入流。 效果类似于重复调用 keybd_event 或 mouse_event 函数,只是系统会确保没有其他输入事件与模拟事件混为一体。 调用完成后,返回值指示成功播放的输入事件数。 如果此值为零,则表示输入被阻止。
SendInput 函数不会重置键盘的当前状态。 因此,如果用户在调用此函数时按下了任何键,它们可能会干扰此函数生成的事件。 如果担心可能存在干扰,请使用 GetAsyncKeyState 函数检查键盘的状态,并根据需要进行更正。
语言、区域设置和键盘布局
语言是一种自然语言,例如英语、法语和日语。 子语言是在特定地理区域使用的自然语言的变体,例如英式英语和美式英语。 应用程序使用称为语言标识符的值来唯一标识语言和子语言。
应用程序通常使用区域设置来设置处理输入和输出所使用的语言。 例如,设置键盘的区域设置会影响键盘生成的字符值。 设置显示器或打印机的区域设置会影响显示或打印的字形。 应用程序通过加载和使用键盘布局来设置键盘的区域设置。 它们通过选择支持指定区域设置的字体来设置显示器或打印机的区域设置。
键盘布局不仅指定键在键盘上的物理位置,还确定通过按下这些键会生成的字符值。 每个布局标识当前输入语言,并确定由哪些键和键组合生成哪些字符值。
每个键盘布局都有一个相应的句柄,用于标识布局和语言。 句柄的低位字是语言标识符。 高位字是设备句柄,用于指定物理布局;或者为零,表示默认物理布局。 用户可以将任何输入语言与物理布局相关联。 例如,偶尔使用法语的英语用户可以将键盘的输入语言设置为法语,而无需更改键盘的物理布局。 这意味着用户可以使用熟悉的英语布局输入法语文本。
应用程序通常不会直接操作输入语言。 相反,用户设置语言和布局组合,然后在它们之间切换。 当用户单击使用其他语言标记的文本时,应用程序会调用 ActivateKeyboardLayout 函数来激活用户对该语言的默认布局。 如果用户使用不在活动列表中的语言编辑文本,应用程序可以使用该语言调用 LoadKeyboardLayout 函数以获得基于该语言的布局。
ActivateKeyboardLayout 函数设置当前任务的输入语言。 hkl 参数可以是键盘布局的句柄或零扩展语言标识符。 可以通过 LoadKeyboardLayout 或 GetKeyboardLayoutList 函数获取键盘布局句柄。 也可使用 HKL_NEXT 和 HKL_PREV 值选择下一个或上一个键盘。
GetKeyboardLayoutName 函数检索调用线程的活动键盘布局的名称。 如果应用程序使用 LoadKeyboardLayout 函数创建活动布局,GetKeyboardLayoutName 会检索用于创建布局的相同字符串。 否则,该字符串是对应于活动布局的区域设置的主要语言标识符。 这意味着函数不一定能区分具有相同主要语言的不同布局,因此无法返回有关输入语言的特定信息。 但是,GetKeyboardLayout 函数可用于确定输入语言。
LoadKeyboardLayout 函数加载键盘布局并使该布局可供用户使用。 应用程序可以使用 KLF_ACTIVATE 值使当前线程的布局立即处于活动状态。 应用程序可以使用 KLF_REORDER 值对布局重新排序,而无需同时指定 KLF_ACTIVATE 值。 加载键盘布局时,应用程序应始终使用 KLF_SUBSTITUTE_OK 值,以确保选择用户的首选项(如果有)。
对于多语言支持,LoadKeyboardLayout 函数提供了 KLF_REPLACELANG 和 KLF_NOTELLSHELL 标志。 KLF_REPLACELANG 标志指示函数在不更改语言的情况下替换现有的键盘布局。 尝试使用相同的语言标识符替换现有布局但不指定 KLF_REPLACELANG 是错误的。 KLF_NOTELLSHELL 标志可阻止函数在添加或替换键盘布局时通知 shell。 这对于在一系列连续调用中添加多个布局的应用程序很有用。 除最后一次调用外,所有调用都应使用此标志。
UnloadKeyboardLayout 函数受限,无法卸载系统默认输入语言。 这可确保用户始终有一种布局可用于输入文本,所用字符集与 shell 和文件系统使用的字符集相同。