简体   繁体   English

在Linux下删除/重写/生成键盘事件

[英]drop/rewrite/generate keyboard events under Linux

I would like to hook into, intercept, and generate keyboard (make/break) events under Linux before they get delivered to any application. 我想在Linux下交付,拦截并生成键盘(make / break)事件,然后才能将它们传送到任何应用程序。 More precisely, I want to detect patterns in the key event stream and be able to discard/insert events into the stream depending on the detected patterns. 更准确地说,我想检测关键事件流中的模式,并能够根据检测到的模式丢弃/插入事件到流中。

I've seen some related questions on SO, but: 我在SO上看过一些相关的问题,但是:

  • either they only deal with how to get at the key events (key loggers etc.), and not how to manipulate the propagation of them (they only listen, but don't intercept/generate). 或者他们只处理如何获得关键事件(关键记录器等),而不是如何操纵它们的传播(它们只是监听,但不拦截/生成)。
  • or they use passive/active grabs in X (read more on that below). 或者他们在X中使用被动/主动抓取(详见下文)。

A Small DSL 小型DSL

I explain the problem below, but to make it a bit more compact and understandable, first a small DSL definition. 我解释下面的问题,但为了使它更紧凑和易懂,首先是一个小的DSL定义。

  • A_ : for make (press) key A A_ :用于制作(按)键A.
  • A^ : for break (release) key A A^ :用于中断(释放)键A.
  • A^->[C_,C^,U_,U^] : on A^ send a make/break combo for C and then U further down the processing chain (and finally to the application). A^->[C_,C^,U_,U^] :在A^为C发送一个make / break组合,然后在处理链中向下发送U(最后到应用程序)。 If there is no -> then there's nothing sent (but internal state might be modified to detect subsequent events). 如果没有->则没有发送任何内容(但可能会修改内部状态以检测后续事件)。
  • $X : execute an arbitrary action. $X :执行任意操作。 This can be sending some configurable key event sequence (maybe something like Cx Cs for emacs), or execute a function. 这可以发送一些可配置的键事件序列(可能类似于emacs的Cx Cs ),或执行一个函数。 If I can only send key events, that would be enough, as I can then further process these in a window manager depending on which application is active. 如果我只能发送关键事件,那就足够了,因为我可以在窗口管理器中进一步处理这些事件,具体取决于哪个应用程序处于活动状态。

Problem Description 问题描述

Ok, so with this notation, here are the patterns I want to detect and what events I want to pass on down the processing chain. 好吧,所以使用这种表示法,这里是我想要检测的模式以及我想在处理链中传递的事件。

  1. A_, A^->[A_,A^] : expl. A_, A^->[A_,A^] :探索。 see above, note that the send happens on A^ . 见上文,请注意发送在A^上发生。
  2. A_, B_, A^->[A_,A^], B^->[B_,B^] : basically the same as 1. but overlapping events don't change the processing flow. A_, B_, A^->[A_,A^], B^->[B_,B^] :基本上与1.相同但重叠事件不会改变处理流程。
  3. A_, B_, B^->[$X], A^ : if there was a complete make/break of a key (B) while another key was held (A), X is executed (see above), and the break of A is discarded. A_, B_, B^->[$X], A^ :如果有一个完整的键/中断键(B)而另一个键被保持(A),则执行X(见上文),并且中断A被丢弃了。

(it's in principle a simple statemachine implemented over key events, which can generate (multiple) key events as output). (原则上,它是一个简单的状态机,可以在关键事件上实现,可以生成(多个)关键事件作为输出)。

Additional Notes 补充笔记

  • The solution has to work at typing speed. 解决方案必须在打字速度上工作。
  • Consumers of the modified key event stream run under X on Linux (consoles, browsers, editors, etc.). 修改后的密钥事件流的消费者在Linux上运行X(控制台,浏览器,编辑器等)。
  • Only keyboard events influence the processing (no mouse etc.) 只有键盘事件会影响处理(没有鼠标等)
  • Matching can happen on keysyms (a bit easier), or keycodes (a bit harder). 匹配可以发生匹配(更容易)或键码(更难一点)。 With the latter, I will just have to read in the mapping to translate from code to keysym. 对于后者,我将只需要阅读映射以从代码转换为keysym。
  • If possible, I'd prefer a solution that works with both USB keyboards as well as inside a virtual machine (could be a problem if working at the driver layer, other layers should be ok). 如果可能的话,我更喜欢适用于USB键盘以及虚拟机内部的解决方案(如果在驱动程序层工作则可能会出现问题,其他层应该没问题)。
  • I'm pretty open about the implementation language. 我对实现语言非常开放。

Possible Solutions and Questions 可能的解决方案和问题

So the basic question is how to implement this. 所以基本问题是如何实现这一点。

I have implemented a solution in a window manager using passive grabs ( XGrabKey ) and XSendEvent . 我已经使用被动抓取( XGrabKey )和XSendEvent在窗口管理器中实现了一个解决方案。 Unfortunately passive grabs don't work in this case as they don't capture correctly B^ in the second pattern above. 不幸的是,被动抓取在这种情况下不起作用,因为它们在上面的第二种模式中没有正确捕获B^ The reason is that the converted grab ends on A^ and is not continued to B^ . 原因是转换的抓斗在A^上结束并且不继续到B^ A new grab is converted to capture B if still held but only after ~1 sec. 如果仍然保持,则新的抓取转换为捕获B,但仅在约1秒后。 Otherwise a plain B^ is sent to the application. 否则,将普通B^发送到应用程序。 This can be verified with xev . 这可以用xev验证。

I could convert my implementation to use an active grab ( XGrabKeyboard ), but I'm not sure about the effect on other applications if the window manager has an active grab on the keyboard all the time. 我可以将我的实现转换为使用主动抓取( XGrabKeyboard ),但是如果窗口管理器一直在键盘上有活跃的抓取,我不确定对其他应用程序的影响。 X documentation refers to active grabs as being intrusive and designed for short term use. X文档将活动抓取称为侵入式并且是为短期使用而设计的。 If someone has experience with this and there are no major drawbacks with longterm active grabs, then I'd consider this a solution. 如果有人有这方面的经验并且长期积极争夺没有重大缺点,那么我认为这是一个解决方案。

I'm willing to look at other layers of key event processing besides window managers (which operate as X clients). 除了窗口管理器(作为X客户端运行)之外,我愿意查看其他关键事件处理层。 Keyboard drivers or mappings are a possibility as long as I can solve the above problem with them. 键盘驱动程序或映射是可能的,只要我可以用它们解决上述问题。 This also implies that the solution doesn't have to be a separate application. 这也意味着解决方案不必是单独的应用程序。 I'm perfectly fine to have a driver or kernel module do this for me. 我很高兴有一个驱动程序或内核模块为我做这个。 Be aware though that I have never done any kernel or driver programming, so I would appreciate some good resources. 请注意,我从未做过任何内核或驱动程序编程,所以我会很感激一些好的资源。

Thanks for any pointers! 感谢您的任何指示!

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM