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

时间:2019-03-18 17:07:01

标签: c linux automation keyboard x11

对于自动化测试应用程序,我必须模拟大量的Unicode键盘输入到旧的X11应用程序中(我没有任何源访问权限)。 我的程序通过stdin从UCS-2 LE编码的输入流中获取输入,基本操作如下:

  1. 保存当前的键盘布局和锁定修饰符(XDisplayKeycodesXGetKeyboardMappingXkbGetState
  2. 解锁活动修饰符(XkbLockModifiers
  3. 通过Xinput2扩展名禁用所有X11从属键盘设备
  4. 将输入读取到按键队列中,直到遇到n个唯一符号,其中nXDisplayKeycodes返回的可能的键码数量。
  5. 通过n将这些XChangeKeyboardMapping唯一的X11 KeySyms映射到n可用的KeyCodes上
  6. 通过XTestFakeKeyEvent为所有排队的KeySyms输入正确的KeyCodes
  7. 清除队列并继续执行4.),直到没有可用输入为止
  8. 重新激活键盘并恢复初始修饰符和映射

基本上,该系统比到目前为止我所见过的任何虚拟X11按键输入工具都更好,性能更高。

但是,我目前只能使用难看的延迟来解决此问题:

与其他任何X11应用程序一样,在我的应用程序成功更改键盘映射表之后,目标应用程序从X服务器接收到MappingNotify(请求==键盘)事件。 X11客户端的通常响应是调用XRefreshKeyboardMapping以更新Xlib对新键盘布局的了解。

现在,如果客户端在处理其X11事件队列时有一些滞后,则XRefreshKeyboardMapping调用可能会返回太新的映射,而该映射在将来已经太远了。 例如。当目标应用程序刚刚到达其XEvent队列处理程序中处理第二个XChangeKeyboardMapping事件时,我的输入生成器已经完成了第四个MappingNotify。 实际上,它应该获得第二代地图,该地图当时在X服务器上不再可用。

不幸的是,键盘MappingNotify事件中没有映射ID或任何类型的版本,因此XRefreshKeyboardMapping可以引用特定的映射...而且X服务器似乎没有保留历史记录要么。

结果是X11应用程序的KeyCodeKeySym转换在无效布局下运行并生成错误的KeySyms。

因此,基本上,我必须等到所有客户端(或至少一个具有输入焦点的客户端)都已请求并收到我的上一个XChangeKeyboardMapping映射后,才能执行下一个XChangeKeyboardMapping。 / p>

我可以使用XChangeKeyboardMapping之前的延迟来修复99.9%的错误,并且该延迟是由一些丑陋的巫术(如击键次数等)计算得出的,并且如果必须达到100%的精度,这种延迟会很高

所以我的问题是,是否有任何方法可以通过编程方式得到通知或检查X11客户端是否已完成XRefreshKeyboardMapping或它的映射是否与服务器映射同步?

如果没有,是否有办法通过xlib获取另一个X11客户端的当前映射(以检查该映射是否为当前映射)?

感谢任何提示!

1 个答案:

答案 0 :(得分:1)

过去,我在Windows上做过类似的事情。我非常荣幸能够使用SendInput函数,该函数接受带有KEYEVENTF_UNICODE标志的KEYBDINPUT结构。不幸的是,X11不支持Unicode字符的直接按键合成。

由于我无法发表评论,因此我不得不提出建议作为答案:

您是否考虑过使用剪贴板将“ unicode输入”转移到X11应用程序的输入字段中?

如果该应用程序使用支持此功能的工具箱,那么您也可以考虑使用直接Unicode输入:

例如基于GTK +的程序(包括所有GNOME应用程序)都支持Unicode输入。
按住Ctrl + Shift并键入u,然后输入Unicode十六进制数字,然后再次释放CtrlShift

我想使用Xtest扩展名合成这些序列应该很容易。