键盘输入概述

应用程序应接受键盘和鼠标中的用户输入。 应用程序以发布到窗口的消息的形式接收键盘输入。

键盘输入模型

系统通过安装适用于当前键盘的键盘设备驱动程序,为应用程序提供独立于设备的键盘支持。 系统通过使用用户或应用程序当前选定的特定于语言的键盘布局提供与语言无关的键盘支持。 键盘设备驱动程序从键盘接收扫描代码,这些代码将发送到键盘布局,这些代码将转换为消息,并发布到应用程序中的相应窗口。

分配给键盘上每个键的唯一值称为 扫描代码,即键盘上键的设备依赖标识符。 当用户键入键时,键盘会生成两个扫描代码,一个是当用户按下键时,另一个是用户释放键时。

键盘设备驱动程序解释扫描代码,并将 (映射) 映射到 虚拟键代码,这是由系统定义的设备无关的值,用于标识键的用途。 翻译扫描代码后,键盘布局将创建一条消息,其中包括扫描代码、虚拟键代码以及有关击键的其他信息,然后将消息置于系统消息队列中。 系统从系统消息队列中删除消息,并将其发布到相应线程的消息队列。 最终,线程的消息循环会删除该消息,并将其传递给相应的窗口过程进行处理。 下图演示了键盘输入模型。

键盘输入处理模型

键盘焦点和激活

系统将键盘消息发布到创建具有键盘焦点的窗口的前景线程的消息队列。 键盘焦点是窗口的临时属性。 系统通过将键盘焦点从一个窗口移动到另一个窗口,将键盘焦点从一个窗口移动到另一个窗口,从而在显示器上共享键盘。 具有键盘焦点的窗口从创建它的线程的消息队列接收 (,这些线程) 所有键盘消息,直到焦点更改为其他窗口。

线程可以调用 GetFocus 函数来确定其窗口 ((如果有) 当前具有键盘焦点)。 线程可以通过调用 SetFocus 函数将键盘焦点赋予其窗口之一。 当键盘焦点从一个窗口更改为另一个窗口时,系统将 WM_KILLFOCUS 消息发送到失去焦点的窗口,然后将 WM_SETFOCUS 消息发送到已获得焦点的窗口。

键盘焦点的概念与活动窗口的概念相关。 活动窗口是用户当前正在使用的顶级窗口。 具有键盘焦点的窗口是活动窗口或活动窗口的子窗口。 为了帮助用户识别活动窗口,系统会将其放置在 Z 订单顶部,并在具有一个) 和边框的情况下突出显示其标题栏 (。

用户可以通过单击它、使用 ALT+TAB 或 ALT+ESC 键组合选择它,或从任务列表中选择它来激活顶级窗口。 线程可以使用 SetActiveWindow 函数激活顶级窗口。 它可以使用 GetActiveWindow 函数确定创建的顶级窗口是否处于活动状态。

停用一个窗口并激活另一个窗口时,系统会发送 WM_ACTIVATE 消息。 如果窗口处于停用状态,则 wParam 参数的低序单词为零;如果窗口正在激活,则为非零。 当默认窗口过程收到 WM_ACTIVATE 消息时,它将键盘焦点设置为活动窗口。

若要阻止键盘和鼠标输入事件到达应用程序,请使用 BlockInput。 请注意, BlockInput 函数不会干扰异步键盘输入状态表。 这意味着阻止输入时调用 SendInput 函数将更改异步键盘输入状态表。

击键消息

按键会导致 将WM_KEYDOWNWM_SYSKEYDOWN 消息放置在附加到具有键盘焦点的窗口的线程消息队列中。 释放密钥会导致 将WM_KEYUPWM_SYSKEYUP 消息置于队列中。

键起和向下键消息通常成对发生,但如果用户按住的键足够长的时间才能启动键盘的自动重复功能,则系统会在一行中生成大量 WM_KEYDOWNWM_SYSKEYDOWN 消息。 然后,当用户释放密钥时,它会生成单个 WM_KEYUPWM_SYSKEYUP 消息。

本部分涵盖了以下主题:

系统和非系统击键

系统区分系统击键和非系统击键。 系统击键生成系统击键消息、 WM_SYSKEYDOWNWM_SYSKEYUP。 非系统击键生成非系统击键消息、 WM_KEYDOWNWM_KEYUP

如果窗口过程必须处理系统击键消息,请确保在处理消息后,该过程将其传递给 DefWindowProc 函数。 否则,每当窗口具有键盘焦点时,将禁用涉及 ALT 键的所有系统操作。 也就是说,用户无法访问窗口的菜单或系统菜单,或使用 Alt+ESC 或 ALT+TAB 键组合激活其他窗口。

系统击键消息主要供系统使用,而不是由应用程序使用。 系统使用它们向菜单提供其内置键盘界面,并允许用户控制哪个窗口处于活动状态。 当用户将键与 ALT 键组合键入键或用户类型且没有窗口的键盘焦点 ((例如,当活动应用程序最小化) 时)时,系统击键消息将生成。 在这种情况下,消息将发布到附加到活动窗口的消息队列。

非系统击键消息供应用程序窗口使用; DefWindowProc 函数不对其执行任何作用。 窗口过程可以放弃它不需要的任何非系统击键消息。

描述的Virtual-Key代码

击键消息的 wParam 参数包含按下或释放的 键的虚拟键代码 。 窗口过程根据虚拟键代码的值处理或忽略击键消息。

典型的窗口过程只处理它接收和忽略其余部分的击键消息。 例如,窗口过程可能只处理 WM_KEYDOWN 击键消息,并且仅包含光标移动键的虚拟键代码、移动键 (也称为控制键) 和函数键。 典型的窗口过程不会处理字符键中的击键消息。 相反,它使用 TranslateMessage 函数将消息转换为字符消息。 有关 TranslateMessage 和字符消息的详细信息,请参阅 字符消息

击键消息标志

击键消息的 lParam 参数包含有关生成消息的击键的其他信息。 此信息包括 重复计数扫描代码扩展键标志上下文代码以前的键状态标志转换状态标志。 下图显示了 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 repeatFlag = (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 upFlag = (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_KEYDOWNWM_SYSKEYDOWN 消息比应用程序可以处理的消息快时,系统递增计数。 当用户按住足够长的时间以启动键盘的自动重复功能时,通常会发生这种情况。 系统不会使用生成的向下键消息填充系统消息队列,而是将消息合并为单个向下键消息,并递增重复计数。 释放密钥无法启动自动重复功能,因此WM_KEYUP和WM_SYSKEYUP消息的重复计数始终设置为 1。

扫描代码

包含每个键的“扫描代码”规范的键盘示意图。

扫描代码是当用户按下键时键盘硬件生成的值。 它是一个设备依赖的值,用于标识按下的键,而不是由键表示的字符。 应用程序通常忽略扫描代码。 相反,它使用独立于设备的虚拟密钥代码来解释击键消息。

注意

虽然虚拟密钥代码通常更有用,但在特定情况下可能需要扫描代码。 例如,WASD (W 向上,A 为左,S 为向下,D 为游戏的右键绑定) 键绑定,这可确保在键盘布局之间形成一致的键。

下表列出了 Windows 目前识别的完整扫描代码集。 美国键分配用于引用类型 101/102 增强型键盘,如类型 4 键盘布局支持。 如果 101/102 增强型键盘列中没有条目,则操作系统当前无法识别此扫描代码。 键位置值引用前面的键盘图像。

“扫描 1 生成”代码在WM_KEYDOWN/WM_SYSKEYDOWN消息中传递,而“扫描 1 中断”代码在WM_KEYUP/WM_SYSKEYUP消息中传递。

密钥位置 101/102 增强型键盘 扫描 1 生成 扫描 1 中断
请勿使用 00 80
请勿使用 E0_00 E0_80
1 ~ ` 29 A9
E0_29 E0_A9
2 ! 1 02 82
E0_02 E0_82
3 @ 2 03 83
E0_03 E0_83
4 # 3 04 84
E0_04 E0_84
5 $ 4 05 85
E0_05 E0_85
6 % 5 06 86
E0_06 E0_86
7 ^ 6 07 87
E0_07 E0_87
8 & 7 08 88
E0_08 E0_88
9 * 8 09 89
E0_09 E0_89
10 ( 9 0A 8A
E0_0A E0_8A
11 ) 0 0B 8B
E0_0B E0_8B
12 _ - 0C 8C
E0_0C E0_8C
13 + = 0D 8D
E0_0D E0_8D
15 退格键 0E 8E
E0_0E E0_8E
16 选项卡 0F 8F
E0_0F E0_8F
17 Q 10 90
E0_10 E0_90
18 W 11 91
E0_11 E0_91
19 E 12 92
E0_12 E0_92
20 R 13 93
E0_13 E0_93
21 T 14 94
E0_14 E0_94
22 Y 15 95
E0_15 E0_95
23 U 16 96
E0_16 E0_96
24 I 17 97
E0_17 E0_97
25 O 18 98
E0_18 E0_98
26 P 19 99
E0_19 E0_99
27 { [ 1A 9A
E0_1A E0_9A
28 } ] 1B 9B
E0_1B E0_9B
29
(在美国可用,而不是国际键盘.)
| \ 2B AB
E0_2B E0_AB
30 大写锁定 3A BA
E0_3A E0_BA
31 A 1E 9E
E0_1E E0_9E
32 S 1F 9F
E0_1F E0_9F
33 D 20 A0
E0_20 E0_A0
34 F 21 A1
E0_21 E0_A1
35 G 22 A2
E0_22 E0_A2
36 H 23 A3
E0_23 E0_A3
37 J 24 A4
E0_24 E0_A4
38 K 25 A5
E0_25 E0_A5
39 L 26 A6
E0_26 E0_A6
40 : ; 27 A7
E0_27 E0_A7
41 “ ‘ 28 A8
E0_28 E0_A8
42
(国际键盘上可用,而不是在美国键盘上。)
2B AB
E0_2B E0_AB
43 Enter 1C 9C
44 L SHIFT 2A AA
E0_2A E0_AA
45
(国际键盘上可用,而不是在美国键盘上。)
56 D6
E0_56 E0_D6
46 Z 2C AC
E0_2C E0_AC
47 X 二维 AD
E0_2D E0_AD
48 C 2E AE
E0_2E E0_AE
49 V 2F AF
E0_2F E0_AF
50 B 30 B0
E0_30 E0_B0
51 N 31 B1
E0_31 E0_B1
52 M 32 B2
E0_32 E0_B2
53 < , 33 B3
E0_33 E0_B3
54 > . 34 B4
E0_34 E0_B4
55 ? / 35 B5
E0_35 E0_B5
56
(巴西和一些远东键盘上使用。美国键盘.) 上不可用
73 F3
E0_73 E0_F3
57 R SHIFT 36 B6
E0_36 E0_B6
58 L CTRL 1D 9D
60 L ALT 38 B8
E0_38 E0_B8
61 空格键 39 B9
E0_39 E0_B9
62 R ALT E0 38 E0 B8
64 R CTRL E0 1D E0 9D
75 插入 注释 1 注释 1
76 删除 注释 1 注释 1
79 L 箭头 注释 1 注释 1
80 主页 注释 1 注释 1
81 结束 注释 1 注释 1
83 向上键 注释 1 注释 1
84 Dn 箭头 注释 1 注释 1
85 Page Up 注释 1 注释 1
86 Page Down 注释 1 注释 1
89 R 箭头 注释 1 注释 1
90 Num Lock 45 C5
E0_45 E0_C5
91 数字 7 47 C7
92 数字 4 4B CB
93 数字 1 4F CF
95 数字/ 注释 3 注释 3
96 数字 8 48 C8
97 数字 5 4C CC
98 数字 2 50 D0
99 数字 0 52 D2
100 数字 * 37 B7
E0_37 E0_B7
101 数字 9 49 C9
102 数字 6 4D CD
103 数字 3 51 D1
104 数字。 53 D3
105 数字 - 4A CA
106 数字 + 4E CE
107
(巴西和一些远东键盘上使用。美国键盘.) 上不可用
7E FE
请勿使用 E0_7E E0_FE
108 数字 Enter E0 1C E0 9C
110 Esc 01 81
E0_01 E0_81
112 F1 3B BB
E0_3B E0_BB
113 F2 3C BC
E0_3C E0_BC
114 F3 三维 BD
E0_3D E0_BD
115 F4 3E BE
E0_3E E0_BE
116 F5 3F BF
E0_3F E0_BF
117 F6 40 C0
E0_40 E0_C0
118 F7 41 C1
E0_41 E0_C1
119 F8 42 C2
E0_42 E0_C2
120 F9 43 C3
E0_43 E0_C3
121 F10 44 C4
E0_44 E0_C4
122 F11 57 D7
123 F12 58 D8
124 Print Screen 注释 4 注释 4
125 滚动锁 46 C6
E0_46 E0_C6
126 暂停 注释 5 注释 5
59 D9
E0_59 E0_D9
5B DB
左赢 E0_5B E0_DB
5C DC
右赢 E0_5C E0_DC
5D DD
应用程序 E0_5D E0_DD
5E DE
ACPI 电源 E0_5E E0_DE
5F DF
ACPI 睡眠 E0_5F E0_DF
请勿使用 60 E0
请勿使用 E0_60 E0_E0
请勿使用 61 E1
请勿使用 E0_61 E0_E1
62 E2
E0_62 E0_E2
63 E3
ACPI 唤醒 E0_63 E0_E3
64 E4
E0_64 E0_E4
65 E5
E0_65 E0_E5
66 E6
E0_66 E0_E6
67 E7
E0_67 E0_E7
68 E8
E0_68 E0_E8
69 E9
E0_69 E0_E9
6A EA
E0_6A E0_EA
6B EB
E0_6B E0_EB
6C EC
E0_6C E0_EC
6D ED
E0_6D E0_ED
6E EE
E0_6E E0_EE
6F EF
E0_6F E0_EF
DBE_KATAKANA
(用于远东键盘.)
70 F0
E0_70 E0_F0
71 F1
E0_71 E0_F1
72 F2
E0_72 E0_F2
74 F4
E0_74 E0_F4
75 F5
E0_75 E0_F5
76 F6
E0_76 E0_F6
DBE_SBCSCHAR
(用于远东键盘.)
77 F7
E0_77 E0_F7
78 F8
E0_78 E0_F8
CONVERT
(用于远东键盘.)
79 F9
E0_79 E0_F9
请勿使用 7A FA
请勿使用 E0_7A E0_FA
NONCONVERT
(用于远东键盘.)
7B FB
请勿使用 E0_7B E0_FB
请勿使用 7C FC
请勿使用 E0_7C E0_FC
请勿使用 7D FD
请勿使用 E0_7D E0_FD
请勿使用 7F FF
请勿使用 E0_7F E0_FF

Extended-Key标志

扩展键标志指示击键消息是否源自增强型 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。

上一个Key-State标志

上一个键状态标志指示生成击键消息的键以前是向上还是关闭。 如果密钥之前已关闭,则为 1;如果密钥之前已启动,则为 0。 可以使用此标志识别键盘自动重复功能生成的击键消息。 对于 自动 重复功能生成的 WM_KEYDOWN和WM_SYSKEYDOWN 击键消息,此标志设置为 1。 对于 WM_KEYUPWM_SYSKEYUP 消息,它始终设置为 1。

Transition-State标志

转换状态标志指示是按键还是释放生成击键消息的键。 对于 WM_KEYDOWNWM_SYSKEYDOWN 消息,此标志始终设置为 0;对于 WM_KEYUPWM_SYSKEYUP 消息,它始终设置为 1。

字符消息

击键消息提供有关击键的大量信息,但它们不提供字符击键的字符代码。 若要检索字符代码,应用程序必须在其线程消息循环中包含 TranslateMessage 函数。 TranslateMessageWM_KEYDOWNWM_SYSKEYDOWN 消息传递到键盘布局。 布局会检查消息的虚拟密钥代码,如果它对应于字符键,则提供等效字符代码 (考虑到 SHIFT 和 CAPS LOCK 密钥的状态) 。 然后,它会生成包含字符代码的字符消息,并将消息放置在消息队列的顶部。 消息循环的下一次迭代将从队列中删除字符消息,并将消息调度到相应的窗口过程。

本部分涵盖了以下主题:

非系统字符消息

窗口过程可以接收以下字符消息: WM_CHARWM_DEADCHARWM_SYSCHARWM_SYSDEADCHARWM_UNICHARTranslateMessage 函数在处理WM_KEYDOWN消息时生成WM_CHARWM_DEADCHAR消息。 同样,它会在处理WM_SYSKEYDOWN消息时生成WM_SYSCHARWM_SYSDEADCHAR消息。

处理键盘输入的应用程序通常忽略 除WM_CHARWM_UNICHAR 消息之外的所有消息,并将任何其他消息传递给 DefWindowProc 函数。 请注意, WM_CHAR 使用 UTF-16 (16 位 Unicode 转换格式) 或 ANSI 字符集,而 WM_UNICHAR 始终使用 UTF-32 (32 位 Unicode 转换格式) 。 系统使用 WM_SYSCHARWM_SYSDEADCHAR 消息来实现菜单助记。

所有字符消息的 wParam 参数包含按下的字符键的字符代码。 字符代码的值取决于接收消息的窗口的窗口类。 如果使用 RegisterClass 函数的 Unicode 版本来注册窗口类,系统将 Unicode 字符提供给该类的所有窗口。 否则,系统提供 ANSI 字符代码。 有关详细信息,请参阅在 Windows 应用中 注册窗口类 和使用 UTF-8 代码页

字符消息的 lParam 参数的内容与转换为生成字符消息的 lParam 参数的内容相同。 有关详细信息,请参阅 击键消息标志

Dead-Character消息

某些非英语键盘包含不应自行生成字符的字符键。 相反,它们用于向后续击键生成的字符添加音调符号。 这些 密钥称为死键。 德语键盘上的圆环键是死键的示例。 若要输入由带有周光反射的“o”组成的字符,德国用户将键入圆环键,后跟“o”键。 具有键盘焦点的窗口将收到以下消息序列:

  1. WM_KEYDOWN
  2. WM_DEADCHAR
  3. WM_KEYUP
  4. WM_KEYDOWN
  5. WM_CHAR
  6. WM_KEYUP

TranslateMessage 在处理死密钥WM_KEYDOWN消息时生成WM_DEADCHAR消息。 尽管 WM_DEADCHAR 消息的 wParam 参数包含死键的音调符号的字符代码,但应用程序通常忽略该消息。 而是处理由后续击键生成的 WM_CHAR 消息。 WM_CHAR消息的 wParam 参数包含带音调符号的字母字符代码。 如果后续击键生成无法与音调组合的字符,系统将生成两 条WM_CHAR 消息。 第一个参数的 wParam 参数包含音调符号的字符代码;第二个参数的 wParam 参数包含后续字符键的字符代码。

TranslateMessage 函数在处理系统死键WM_SYSKEYDOWN消息时生成WM_SYSDEADCHAR消息, (按下的死键与 ALT 键) 。 应用程序通常忽略 WM_SYSDEADCHAR 消息。

密钥状态

处理键盘消息时,应用程序可能需要确定另一个键的状态,除了生成当前消息的键。 例如,允许用户按 Shift+END 选择文本块的字处理应用程序,每当它从 END 键收到击键消息时,都必须检查 SHIFT 键的状态。 应用程序可以使用 GetKeyState 函数确定生成当前消息时虚拟密钥的状态;它可以使用 GetAsyncKeyState 函数检索虚拟密钥的当前状态。

键盘布局维护名称列表。 生成单个字符的键的名称与键生成的字符相同。 非字符键的名称(如 TAB 和 ENTER)存储为字符串。 应用程序可以通过调用 GetKeyNameText 函数从设备驱动程序检索任何密钥的名称。

击键和字符翻译

该系统包括几种特殊用途函数,用于转换各种击键消息提供的扫描代码、字符代码和虚拟密钥代码。 这些函数包括 MapVirtualKeyToAsciiToUnicodeVkKeyScan

此外,Microsoft Rich Edit 3.0 还支持 HexToUnicode IME,允许用户使用热键在十六进制字符和 Unicode 字符之间进行转换。 这意味着,当 Microsoft Rich Edit 3.0 合并到应用程序中时,应用程序将继承 HexToUnicode IME 的功能。

Hot-Key支持

热键是生成WM_HOTKEY消息的键组合,系统在线程的消息队列顶部放置的消息,绕过队列中的任何现有消息。 应用程序使用热键从用户获取高优先级键盘输入。 例如,通过定义由 CTRL+C 键组合组成的热键,应用程序可以允许用户取消长时间的操作。

若要定义热键,应用程序调用 RegisterHotKey 函数,指定生成 WM_HOTKEY 消息的键的组合、接收消息的窗口句柄以及热键的标识符。 当用户按下热键时, 会将WM_HOTKEY 消息放置在创建窗口的线程的消息队列中。 消息的 wParam 参数包含热键的标识符。 应用程序可以为线程定义多个热键,但线程中的每个热键必须具有唯一标识符。 在应用程序终止之前,它应使用 UnregisterHotKey 函数销毁热键。

应用程序可以使用热键控件,使用户能够轻松选择热键。 热键控件通常用于定义激活窗口的热键;它们不使用 RegisterHotKeyUnregisterHotKey 函数。 相反,使用热键控件的应用程序通常会发送 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 指示将模拟的输入事件数。 第二个参数 rgInputsINPUT 结构的数组,每个参数描述一种类型的输入事件以及有关该事件的其他信息。 最后一个参数 cbSize 接受 INPUT 结构的大小(以字节为单位)。

SendInput 函数的工作原理是将一系列模拟输入事件注入设备输入流。 效果类似于重复调用 keybd_eventmouse_event 函数,但系统确保没有其他输入事件与模拟事件交织在一起。 调用完成后,返回值指示已成功播放的输入事件数。 如果此值为零,则阻止输入。

SendInput 函数不会重置键盘的当前状态。 因此,如果用户在调用此函数时按下了任何键,则它们可能会干扰此函数生成的事件。 如果担心可能的干扰,请使用 GetAsyncKeyState 函数检查键盘的状态,并根据需要更正。

语言、区域设置和键盘布局

语言是一种自然语言,如英语、法语和日语。 子语言是一种自然语言的变体,该语言在特定地理区域(如英国和美国中讲的英语子语言)。 应用程序使用称为 语言标识符的值来唯一标识语言和子语言。

应用程序通常使用 区域 设置设置在其中处理输入和输出的语言。 例如,设置键盘的区域设置会影响键盘生成的字符值。 设置显示或打印机的区域设置会影响显示或打印的字形。 应用程序通过加载和使用键盘布局来设置键盘的区域设置。 他们通过选择支持指定区域设置的字体来设置显示或打印机的区域设置。

键盘布局不仅指定键盘上的键的物理位置,还确定通过按这些键生成的字符值。 每个布局标识当前输入语言,并确定由哪些键和键组合生成哪些字符值。

每个键盘布局都有一个相应的句柄,用于标识布局和语言。 句柄的低字是语言标识符。 高字是设备句柄,指定物理布局,或为零,表示默认物理布局。 用户可以将任何输入语言与物理布局相关联。 例如,偶尔在法语中工作的英语用户可以将键盘的输入语言设置为法语,而无需更改键盘的物理布局。 这意味着用户可以使用熟悉的英语布局以法语输入文本。

应用程序通常不需要直接操作输入语言。 相反,用户设置语言和布局组合,然后在其中切换。 当用户单击以其他语言标记的文本时,应用程序会调用 ActivateKeyboardLayout 函数来激活该语言的默认布局。 如果用户编辑非活动列表中的语言中的文本,则应用程序可以使用该语言调用 LoadKeyboardLayout 函数,以获取基于该语言的布局。

ActivateKeyboardLayout 函数设置当前任务的输入语言。 hkl 参数可以是键盘布局的句柄,也可以是零扩展语言标识符。 可以从 LoadKeyboardLayoutGetKeyboardLayoutList 函数获取键盘布局句柄。 HKL_NEXTHKL_PREV值也可用于选择下一个或上一个键盘。

GetKeyboardLayoutName 函数检索调用线程的活动键盘布局的名称。 如果应用程序使用 LoadKeyboardLayout 函数创建活动布局, GetKeyboardLayoutName 将检索用于创建布局的相同字符串。 否则,字符串是对应于活动布局区域设置的主要语言标识符。 这意味着函数不一定区分具有相同主语言的不同布局,因此不能返回有关输入语言的特定信息。 但是, GetKeyboardLayout 函数可用于确定输入语言。

LoadKeyboardLayout 函数加载键盘布局,并使布局可供用户使用。 应用程序可以使用 KLF_ACTIVATE 值立即激活当前线程的布局。 应用程序可以使用 KLF_REORDER 值重新排序布局,而无需指定 KLF_ACTIVATE 值。 加载键盘布局时,应用程序应始终使用 KLF_SUBSTITUTE_OK 值,以确保选择了用户的首选项(如果有)。

对于多语言支持, LoadKeyboardLayout 函数提供 KLF_REPLACELANGKLF_NOTELLSHELL 标志。 KLF_REPLACELANG标志指示函数在不更改语言的情况下替换现有键盘布局。 尝试使用同一语言标识符替换现有布局,但未指定 KLF_REPLACELANG 是错误的。 KLF_NOTELLSHELL标志可防止在添加或替换键盘布局时通知 shell。 这对于在连续一系列调用中添加多个布局的应用程序非常有用。 此标志应在最后一次调用中全部使用。

UnloadKeyboardLayout 函数受限制,因为它无法卸载系统默认输入语言。 这可确保用户始终有一个布局可用于使用 shell 和文件系统使用的相同字符集的输入文本。