X11/Xlib:虚拟键盘输入和键盘映射同步问题

3
对于一个自动化测试应用程序,我必须模拟大量的Unicode键盘输入到一个旧的X11应用程序中(我没有任何源代码访问权限)。 我的程序通过stdin从一个UCS-2 LE编码的输入流中获取输入,基本操作如下:
1. 保存当前键盘布局并锁定修饰符(`XDisplayKeycodes`,`XGetKeyboardMapping`,`XkbGetState`)。 2. 解锁活动修饰符(`XkbLockModifiers`)。 3. 通过Xinput2扩展禁用所有X11从设备。 4. 将输入读入按键队列,直到遇到n个唯一的符号,其中n是由`XDisplayKeycodes`返回的可能按键数。 5. 通过`XChangeKeyboardMapping`将这些n个唯一的X11 KeySyms映射到n个可用的KeyCodes上。 6. 通过`XTestFakeKeyEvent`键入所有排队的KeySyms的正确KeyCodes。 7. 清除队列并在4处继续,直到没有输入可用。 8. 激活键盘并恢复初始修饰符和映射。
基本上,这个系统比我目前看到的任何虚拟X11键盘输入工具都要好得多,性能也更好。
然而,目前我只能使用丑陋的延迟来解决一个问题:
与任何其他X11应用程序一样,目标应用程序从X服务器接收到一个MappingNotify(request==Keyboard)事件,表示我的应用程序成功更改了键盘映射表。 X11客户端的通常响应是调用`XRefreshKeyboardMapping`以更新Xlib对新键盘布局的知识。
现在,如果客户端在处理其X11事件队列时有一些延迟,那么`XRefreshKeyboardMapping`调用可能会返回一个太新的映射,这个映射已经超前了若干代。 例如,当目标应用程序刚刚处理第二个MappingNotify事件时,我的输入生成器已经完成了第四个XChangeKeyboardMapping。 实际上,它应该得到地图的第二代,但此时X服务器不再提供该代。
不幸的是,在键盘MappingNotify事件中没有任何地图ID或版本,因此`XRefreshKeyboardMapping`无法引用特定地图......而且X服务器似乎也没有保留历史记录。
结果是X11应用程序的KeyCode到KeySym转换使用无效布局并生成错误的KeySyms。
因此,基本上我必须等待所有客户端(或至少具有输入焦点的客户端)请求并接收我的最后一个XChangeKeyboardMapping映射,然后才能执行下一个XChangeKeyboardMapping。
我可以通过在XChangeKeyboardMapping之前使用延迟来修复99.9%的错误,这个延迟是通过一些丑陋的巫术(按键数等)计算出来的,如果需要达到100%的准确性,那么这个延迟就太高了。
所以我的问题是,是否有任何编程方式可以通知或检查X11客户端是否已完成XRefreshKeyboardMapping或其映射是否与服务器映射同步?
如果没有,是否有一种通过xlib获取另一个X11客户端当前映射的方法(以检查映射是否当前)?
谢谢任何提示!

你可能想看一下hackery libfakekey的内容:http://git.yoctoproject.org/cgit/cgit.cgi/libfakekey/tree/src/libfakekey.c#n333 - andy.holmes
1个回答

1
我过去在Windows上做过类似的事情。我有幸能够使用SendInput函数,该函数接受带有KEYEVENTF_UNICODE标志的KEYBDINPUT结构。不幸的是,X11不支持直接合成Unicode字符的按键。
由于我现在无法发表评论,所以我被迫提供一个建议作为答案:
您是否考虑过使用剪贴板将您的“unicode输入”传输到此X11应用程序的输入字段中?
您还可以考虑使用直接的Unicode输入,如果该应用程序使用支持此功能的工具包:
例如,基于GTK +的程序(包括所有GNOME应用程序)支持Unicode输入。 按住Ctrl+Shift,然后键入u,后跟Unicode十六进制数字,然后再次释放CtrlShift
我想使用Xtest扩展很容易合成这些序列。

好的想法。不幸的是,剪贴板并不是一个选项,至少在我所有的使用情况下都不是。然而,你提到的输入方法在这个应用程序中不起作用,我会检查是否支持其他输入方法。然而,我的实际目标仍然是解决所描述的延迟问题。 - gollum

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