【问题标题】:Trigger Keypress on Physical Keyboard在物理键盘上触发按键
【发布时间】:2020-11-04 07:25:16
【问题描述】:

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

我查看了 DeviceIOCtrl 和 IOCTL_KEYBOARD_INSERT_DATA,但没有找到文档。有人说是not implemented in the driver。另一个 Source 尝试使用 IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER,但也说,it might not be usable for that kind of stuff

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

我为什么要这样做? 是的,这可能是一个 X-Y 问题,但它是我目前能想到的唯一解决方案。我只想截取来自特定键盘的键。有 RawInput,它告诉我击键的键盘,但不能拦截它,还有一个 LowLevel Keyboard 钩子可以拦截,但无法识别键盘。更糟糕的是,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 不便......

【问题讨论】:

  • "更糟糕的是,RawInput 在 LowLevel-Hook 之后触发" - 您链接到的文章通过使用标准键盘挂钩而不是低级键盘挂钩。 WH_KEYBOARD_LL 在 RawInput 事件之前触发,WH_KEYBOARD 在事件之后触发。
  • 另外,如果您阅读文章底部的 cmets,有人建议使用 WH_GETMESSAGE 挂钩而不是 WH_KEYBOARD 挂钩,以便 RawInput 事件和键盘事件可以用一个钩子处理。不过,我没有尝试看看它是否有效。
  • @Remy Lebeau 您的第一条评论的问题是许多边缘情况不能可靠地工作,我想避免这些情况。我会浏览那篇文章中的 cmets,还没有这样做。
  • 缺少编写自定义键盘驱动程序,您真的找不到更好的解决方案。这些是唯一可用于拦截/修改用户模式代码中的键盘输入的 API。
  • @RemyLebeau 我知道这一点。幸运的是,已经存在一个驱动程序,但它有一些限制,我想通过使用我的问题的前半部分来解决。正如我所说,拦截不是问题,关联是一件棘手的事情。如果我在使用它,我不妨尝试将 Windows API 用于非预期目的。

标签: c++ winapi input keyboard deviceiocontrol


【解决方案1】:

我想我找到了适合我的解决方案/hack。我正在避开问题中描述的神奇独角兽并坚持我已经拥有的驱动程序。

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

这就是我所做的。我告诉驱动程序为特定设备注入按键并等待按键到达 RawInput。只会出现两个问题:

  1. 某些击键无法通过键盘句柄到达 RawInput-API。所以我无法将这些关联起来
  2. 一旦他们越过司机,我就不能再拦截他们了。 (不能使用 LowLevelHooks,因为它们在 RawInput 之前运行,不想使用 Global Hooks,因为它们有很多缺点)

所以我只需要找到一个根本不做任何事情的钥匙。幸运的是,驱动程序使用扫描码。 This document 告诉我,有一系列扫描码(0x55 - 0x7f)可供免费获取,每个制造商都在其中做了一些定制的事情。所以这就是我开始扫描并在 RawInput-API 中查找结果的地方,方法是盲目地将这些 ScanCode 发送到驱动程序中。

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

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

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

【讨论】:

  • 需要这个并测试其他两个键盘后注意:这是不可靠的。最好使用未使用的键来注入数据,例如 Print Screen 或 Break。
猜你喜欢
  • 2013-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多