【发布时间】:2019-08-09 03:06:57
【问题描述】:
对于自动化测试应用程序,我必须在旧的 X11 应用程序(我没有任何源代码访问权限)中模拟大量 unicode 键盘输入。 我的程序通过标准输入从 UCS-2 LE 编码的输入流中获取输入,基本操作如下:
- 保存当前键盘布局和锁定修饰符(
XDisplayKeycodes、XGetKeyboardMapping、XkbGetState) - 解锁活动修饰符 (
XkbLockModifiers) - 通过 Xinput2 扩展禁用所有 X11 从键盘设备
- 将输入读入按键队列,直到遇到
n唯一符号,其中n是XDisplayKeycodes返回的可能键码数。 - 通过
XChangeKeyboardMapping在n可用的KeyCodes 上映射这些n唯一的X11 KeySyms - 通过
XTestFakeKeyEvent为所有排队的 KeySyms 键入正确的 KeyCodes - 清空队列并在 4 处继续。)直到没有可用输入
- 重新激活键盘并恢复初始修饰符和映射
基本上,这个系统比我目前见过的任何虚拟 X11 键输入工具都更好,性能也更高。
但是,我目前只能使用丑陋的延迟来解决一个问题:
与任何其他 X11 应用程序一样,在我的应用程序成功更改键盘映射表后,目标应用程序会从 X 服务器接收MappingNotify (request==Keyboard) 事件。
X11 客户端的通常响应是调用XRefreshKeyboardMapping 来更新Xlib 对新键盘布局的了解。
现在,如果客户端在处理其 X11 事件队列时存在一些延迟,XRefreshKeyboardMapping 调用可能会返回一个太近的映射,而该映射已经在未来的几代中太远了。
例如。当目标应用程序刚刚到达在其 XEvent 队列处理程序中处理第二个 MappingNotify 事件时,我的输入生成器已经完成了第四个 XChangeKeyboardMapping。
实际上它应该得到第二代地图,当时X服务器上已经没有了。
不幸的是,键盘 MappingNotify 事件中没有任何类型的地图 ID 或版本,因此 XRefreshKeyboardMapping 可以引用特定地图......而且 X 服务器似乎也没有保留历史记录。
结果是 X11 应用程序的 KeyCode 到 KeySym 转换以无效布局运行并生成错误的 KeySyms。
所以基本上我必须等到所有客户端(或至少具有输入焦点的客户端)都请求并收到我的最后一个 XChangeKeyboardMapping 映射,然后才能允许我执行下一个 XChangeKeyboardMapping。
我可以在XChangeKeyboardMapping 之前使用延迟来修复 99.9% 的错误,并且延迟是通过一些丑陋的巫术(击键次数等)计算出来的,如果必须达到 100% 的准确度,那么延迟就很高了。
所以我的问题是,是否有任何方法可以以编程方式通知或检查 X11 客户端是否已完成 XRefreshKeyboardMapping 或其地图是否与服务器地图同步?
如果没有,有没有办法通过 xlib 获取另一个 X11 客户端的当前映射(检查映射是否是当前的)?
感谢任何提示!
【问题讨论】:
-
你可能想看看 libfakekey 所做的骇客:git.yoctoproject.org/cgit/cgit.cgi/libfakekey/tree/src/…
标签: c linux automation keyboard x11