在物理键盘上触发按键

Trigger Keypress on Physical Keyboard

我想触发键盘上的按键。在物理键盘上 - 因此它必须以该特定键盘作为其源通过所有内核过滤器。这样的事情甚至可能吗?

我查看了 DeviceIOCtrl 和 IOCTL_KEYBOARD_INSERT_DATA,但找不到文档。有人说,是not implemented in the driver. Another Source tries to use IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER, but also say, it might not be usable for that kind of stuff.

是否有其他选项可以在键盘通过内核过滤器之前触发键盘按键?

我为什么要这样做? 是的,这可能是一个 X-Y 问题,但这是我目前能想到的唯一解决方案。我只想拦截来自特定键盘的键。有RawInput,它告诉我击键的Keyboard,但无法拦截它,还有一个LowLevel Keyboard hook可以拦截,但无法识别键盘。更糟糕的是,RawInput 在 LowLevel-Hook 触发 之后 触发,因此不可能在拦截击键之前获取键盘。有一些 magic unicorn way 使用在 RawInput 之后触发的全局 Hook,但处理所有边缘情况看起来很痛苦。

有一个 API out there 可以拦截键盘敲击,这是我选择的。它基本上安装了一个驱动程序,允许拦截击键 获取键盘 ID。但是:该 ID 有点随意,不遵循我可以用来将整数值与特定键盘设备相关联的任何规则。例如。它在重新插入设备时会发生变化,与 \Device\KeyboardClassX 无关,等等。因此,每次重新连接键盘/启动应用程序时,用户都必须主动按下一个键,这样我才能确定 ID 是哪个物理键盘实际上代表。我想避免这种情况并自动获取特定设备的 ID。我的想法是触发键盘中的按键(-控制器?)并使用驱动程序捕获它,从而将任意 ID 与设备相关联。

所以如果我的Y有不同的X,欢迎提出。我想避免 Magic Unicorn Way of RawInput and GlobalHook 无法可靠工作的所有边缘情况。任何主要语言的例子都很好。也许没有办法解决在应用程序启动时手动按下按钮以识别键盘的 UX-Inconvenience...

我想我找到了适合我的 solution/hack。我正在避开问题中描述的魔法独角兽并坚持我已经拥有的 driver。

当我意识到我已经能够将键盘输入注入 Kernel-Land 时,第一个想法出现了。只是不是特定的键盘,而是随机的键盘。我最初计划使用 RawInput 查询所有可用的 HID-Keyboards,然后将这些项目中的每一个与 driver 中的 ID 相关联。但为什么不反过来呢?通过击键注入随机设备 ID,等待 RawInput 触发相应的键盘。

我就是这么做的。我告诉 driver 为特定设备注入按键并等待击键到达 RawInput。只出现两个问题:

  1. 有些击键不会到达 RawInput-API 且 Keyboard-Handle。所以我无法关联那些
  2. 一旦他们过了driver,我就不能再拦截他们了。 (不能使用 LowLevelHooks,因为它们 运行 在 RawInput 之前,不想使用 Global Hooks 因为它们有很多缺点)

所以我只需要找到一个什么都不做的钥匙。幸运的是 driver 可以使用扫描码。 This document 告诉我,有一系列扫描码 (0x55 - 0x7f) 可以免费获取,每个制造商都在其中做一些定制。所以这就是我开始扫描并通过盲目地将这些 ScanCodes 发射到 driver.

中寻找结果的地方

免责声明:如果你想这样做,你最好至少有两个屏幕,并确保你的焦点 window 不在 VisualStudio 之上,因为只要 window 处于焦点状态,您的焦点 window 就会立即全屏显示并且您的键盘会停止工作...即使您重新获得键盘控制权,您也无法退出全屏显示...

事实上,似乎有很多免费的扫描码可供选择。但其中一些在不同的国家/地区使用或不会在所有键盘 driver 上触发。我选择了 ScanCode 0x7e,它转换为 KeyCode 194,似乎没有在任何语言中使用,但适用于我拥有的所有 (2) 个键盘。

另外,这个“键”总是包含一个合适的键盘句柄,所以没有任何关联的问题。因此,作为最终实现,我使用 RawInput-API 获取连接键盘的数量并循环遍历所有可能的 ID(0-10/20ish 以防止太多 lookups/waiting),直到找到每个键盘的 ID .而且由于扫描代码不用于任何用途,因此用户不会被突然的大写锁定或其他任何事情打断。此外,每次重新插入键盘时都需要重做,因为每个插入的设备都会获得一个新的 ID,即使它之前已经有一个。