我不太清楚这一切是如何运作的,但这是我的猜测:
当你敲击键盘上的某些键时,信号会通过 USB 线,并由操作系统上的键盘驱动程序进行解释(因为操作系统识别出连接到该 USB 端口的设备是键盘)。然后操作系统“发布”被敲击的键(这是标准输入?) 到当前处于活动状态的任何应用程序(例如 Chrome、Word、记事本)。如果应用程序处于接受输入的状态,则它会以它认为合适的任何方式解释按键。否则,“已发布”的按键将被忽略。
但我认为在传递给活动应用程序之前,操作系统会检查您键入的内容是否是 Windows 范围的键盘快捷键(如 Windows + D)。但是,某些常规快捷键(如 Ctrl+C)可能会被应用程序覆盖,尽管大多数应用程序都试图遵循惯例并将 Ctrl+C 解释为尝试将某些内容复制到剪贴板。
这有多准确?
答案1
键盘输入模型
系统通过安装适合当前键盘的键盘设备驱动程序,为应用程序提供与设备无关的键盘支持。系统通过使用用户或应用程序当前选择的特定于语言的键盘布局,提供与语言无关的键盘支持。键盘设备驱动程序从键盘接收扫描码,这些扫描码被发送到键盘布局,在那里被转换成消息并发布到应用程序中的相应窗口。键盘上的每个键都分配有一个称为扫描码的唯一值,这是键盘上键的设备相关标识符。当用户键入一个键时,键盘会生成两个扫描码 - 一个是在用户按下该键时,另一个是在用户释放该键时。键盘设备驱动程序解释扫描码并将其转换(映射)为虚拟键码,这是系统定义的与设备无关的值,用于标识键的用途。转换扫描码后,键盘布局会创建一条消息,其中包括扫描码、虚拟键码和有关击键的其他信息,然后将该消息放入系统消息队列中。系统从系统消息队列中取出该消息并投递到相应线程的消息队列中,最终由该线程的消息循环取出该消息并传递给相应的窗口过程进行处理。
键盘焦点和激活
系统将键盘消息发送到创建具有键盘焦点的窗口的前台线程的消息队列。键盘焦点是窗口的临时属性。系统通过按照用户的方向将键盘焦点从一个窗口移动到另一个窗口,在显示屏上的所有窗口之间共享键盘。具有键盘焦点的窗口(从创建它的线程的消息队列)接收所有键盘消息,直到焦点更改为另一个窗口。线程可以调用 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 和字符消息的更多信息,请参阅字符消息。
欲了解更多信息,请参阅此处的完整版本:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646267(v=vs.85).aspx
具体回答你的问题,如果应用程序想要拦截系统击键,那么它必须在系统消息队列中捕获它,而这并不是应用程序通常的工作方式。系统将自动为每个应用程序创建一个特殊队列,这对应用程序来说更有效率,因为该队列不包含用于其他应用程序的消息。系统队列包含所有应用程序的所有消息,这意味着任何读取它的应用程序都必须丢弃大量不需要的消息。