在Linux下如何模拟/重写/生成键盘事件

9
我希望在Linux下能够钩取、拦截并生成键盘(按下/松开)事件,在这些事件被传递到任何应用程序之前。更准确地说,我想检测键事件流中的模式,并根据检测到的模式丢弃/插入事件到流中。
我在SO上看到了一些相关的问题,但是:
- 要么只涉及如何获取键事件(键记录器等),而不涉及如何操作它们的传播(仅监听,但不拦截/生成)。 - 要么使用X中的被动/主动抓取(下面有更多信息)。
一个小型DSL:
我解释一下问题,为了使其更加紧凑和易懂,先给出一个小型DSL定义。
- A_: 按下键A - A^: 松开键A - A^->[C_,C^,U_,U^]: 在A^上发送C和U的make/break组合到处理链(最终到应用程序)。如果没有->,则不发送任何内容(但内部状态可能会被修改以检测后续事件)。 - $X: 执行任意操作。这可以是发送一些可配置的键事件序列(例如emacs中的C-x C-s),或执行函数。如果我只能发送键事件,那就足够了,因为我可以在窗口管理器中进一步处理这些事件,具体取决于哪个应用程序处于活动状态。
问题描述:
好的,使用这种符号表示法,以下是我想要检测的模式以及我想要传递到处理链中的事件。
- A_, A^->[A_,A^]: 参见上文说明,注意发送发生在A^上。 - A_, B_, A^->[A_,A^], B^->[B_,B^]: 基本上与1相同,但重叠事件不会改变处理流程。 - A_, B_, B^->[$X], A^: 如果在按下一个键(A)时完全按下/松开了另一个键(B),则执行X(参见上文),并且丢弃A的松开。
(它原则上是一个简单的状态机,实现在键事件上,可以生成多个键事件作为输出。)
附加说明:
  • 解决方案必须能够在打字速度下工作。
  • 修改后的按键事件流的消费者在Linux上运行(控制台、浏览器、编辑器等)。
  • 只有键盘事件影响处理(没有鼠标等)。
  • 匹配可以基于键值(比较容易),也可以基于键码(稍微困难一些)。对于后者,我将不得不读取映射以从代码翻译到键值。
  • 如果可能,我希望解决方案既适用于USB键盘,也适用于虚拟机内部(如果在驱动程序层工作可能会有问题,其他层应该没问题)。
  • 我对实现语言很开放。

可能的解决方案和问题

所以基本问题是如何实现这个功能。

我已经在窗口管理器中使用被动抓取(XGrabKey)和 XSendEvent 实现了一个解决方案。不幸的是,在这种情况下,被动抓取无法正确捕捉第二个模式中的 B^。原因是转换后的抓取在 A^ 上结束,并且没有继续到 B^。如果 B 按钮仍然按住,那么一个新的抓取会被转换来捕获 B,但是只有在约1秒后才会发生这种情况。否则,应用程序将收到普通的 B^。可以使用 xev 验证此操作。

我可以将我的实现转换为使用活动抓取(XGrabKeyboard),但是如果窗口管理器始终对键盘进行活动抓取,那么其他应用程序的影响就不确定了。 X 文档将主动抓取描述为具有侵入性并设计用于短期使用。如果有人有长期使用活动抓取的经验,并且没有主要缺点,那么我认为这是一种解决方案。

我愿意查看除窗口管理器(作为X客户端运行)之外的其他键盘事件处理层。键盘驱动程序或映射是可能的,只要我能够解决上述问题。这还意味着解决方案不必是单独的应用程序。我完全可以让驱动程序或内核模块为我完成这项工作。请注意,虽然我从未进行过任何内核或驱动程序编程,但我会感谢一些好的资源。

感谢任何指导!


我可以问一下这个的最终目的吗?这是一个作业吗?一个个人项目?职业工作?还是其他什么? - kazanaki
4
你找到了完成这个任务的方法吗? - retracile
1个回答

3
使用XInput2将设备(键盘)浮动,然后监视设备上的KeyPress和KeyRelease事件,并使用XTest重新生成KeyPress和KeyRelease事件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接