从按键到应用的字符剖析:
1 - 电脑键盘:
PC 键盘不是唯一的键盘类型,但我会限制自己使用它们。
令人惊讶的是,PC 键盘不理解字符,他们理解键盘按钮。这允许美国键盘使用的相同硬件用于 QEWERTY 或 Dvorak 以及使用美国 101/104 键格式的任何其他语言的英语(某些语言有额外的键。)
键盘使用标准扫描码来识别按键,为了使事情更有趣,可以将键盘配置为使用一组特定的代码:
Set 1 - 用于旧的 XT 键盘
Set 2 - 当前使用,
Set-3 用于今天没有人使用的 PS/2 键盘。
设置 1 和 2 使用通断代码(即按下和释放代码)。Set 3 仅对某些键(如 shift)使用 make 和 break 代码,并且只为字母制作代码,这允许键盘本身在长时间按下键时处理键重复。这对于从 PS/2 8086 或 80286 处理器卸载键重复处理很有好处,但对游戏来说却很不利。
您可以在此处阅读有关这一切的更多信息,我还找到了Microsoft 扫描代码规范,以防您想构建和认证自己的 104 键 Windows 键盘。
在任何情况下,我们都可以假设 PC 键盘使用 set 2,这意味着它会在按下键时向计算机发送一个代码,并在释放一个键时向计算机发送一个代码。
顺便说一下,USB HID 规范没有指定键盘发送的扫描码,它只指定了用于发送这些扫描码的结构。
现在,由于我们谈论的是硬件,所有操作系统都是如此,但是每个操作系统处理这些代码的方式可能会有所不同。我将限制自己在 Windows 中发生的事情,但我认为其他操作系统应该遵循大致相同的路径。
2 - 操作系统
我不知道 Windows 究竟是如何处理键盘的,哪些部分由驱动程序处理,哪些由内核处理,哪些在用户模式下;但足以说定期轮询键盘以更改为键状态,扫描代码被翻译并转换为包含虚拟键代码的 WM_KEYDOWN/WM_KEYUP 消息。准确地说,Windows 也会生成 WM_SYSKEYUP/WM_SYSKEYDOWN 消息,您可以在此处阅读有关它们的更多信息
3 - 应用程序
对于 Windows,应用程序获取原始虚拟键代码,并由它决定按原样使用它们或将它们转换为字符代码。
现在没有人写出好的诚实的 C windows 程序,但曾几何时,程序员曾经推出自己的消息泵处理代码,大多数消息泵将包含类似于以下的代码:
while (GetMessage( &msg, NULL, 0, 0 ) != 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
TranslateMessage 是魔法发生的地方。TranslateMessage 中的代码将跟踪 WM_KEYDOWN(和 WM_SYSKEYDOWN)消息并生成 WM_CHAR 消息(和 WM_DEADCHAR、WM_SYSCHAR、WM_SYSDEADCHAR。)
WM_CHAR 消息包含 UTF-16(实际上是 UCS-2,但不允许拆分头发)代码考虑到当时的活动键盘布局,从 WM_KEYDOWN 消息翻译的字符。
在 unicode 之前编写的应用程序呢?这些应用程序使用 ANSI 版本的 RegisterClassEx(即 RegisterClassExA)来注册它们的窗口。在这种情况下,TranslateMessage 根据键盘布局和活动区域性生成带有 8 位字符代码的 WM_CHAR 消息。
4 - 5 - 调度和显示字符。
在使用 UI 库的现代代码中,完全有可能(尽管不太可能)不使用 TranslateMessage 并自定义翻译 WM_KEYDOWN 事件。标准窗口控件(小部件)理解和处理发送给它们的 WM_CHAR 消息,但在窗口下运行的 UI 库/VM 可以实现它们自己的调度机制,而且许多都可以这样做。
希望这能回答你的问题。