For an automated test application I have to simulate large amount of unicode keyboard input into an old X11 application (of which I don't have any source access). My program takes the input from an UCS-2 LE encoded input stream via stdin and the basic operation is as follows:
- Save current keyboard layout and lock modifiers (
XDisplayKeycodes,XGetKeyboardMapping,XkbGetState) - Unlock active modifiers (
XkbLockModifiers) - Disable all X11 slave keyboard devices via Xinput2 extension
- Read input into a key press queue until
nunique symbols are encountered, wherenis the number of possible keycodes as returned byXDisplayKeycodes. - Map these
nunique X11 KeySyms viaXChangeKeyboardMappingon thenavailable KeyCodes - Type the correct KeyCodes for all enqueued KeySyms via
XTestFakeKeyEvent - Clear the queue and continue at 4.) until no input is available
- Reactivate keyboards and restore initial modifiers and mappings
Basically this system works better and much more performant than any virtual X11 key input tool I've seen so far.
However, there is an issue I can currently only fix using ugly delays:
As any other X11 application, the target application receives a MappingNotify (request==Keyboard) event from the X server after my application succeeded in changing the keyboard mapping table.
The usual response of a X11 client is to call XRefreshKeyboardMapping to update Xlib's knowledge of the new keyboard layout.
Now if the the client has some lag processing its X11 event queue, the XRefreshKeyboardMapping call might return a too recent mapping that is already some generations too far in the future.
E.g. my input generator has already done the fourth XChangeKeyboardMapping when the target application just arrived at handling the second MappingNotify event in its XEvent queue handler.
Actually it should get the second generation of the map, which isn't available at the X server anymore at that time.
Unfortunately there is no map id or version of any kind in the keyboard MappingNotify event so that XRefreshKeyboardMapping could refer to a specific map ... and the X server does not seem to keep a history either.
The result is that the X11 application's KeyCode to KeySym conversion operates with an invalid layout and generates wrong KeySyms.
So basically I have to wait until all clients (or at least the one with the input focus) have requested and received my last XChangeKeyboardMapping map before I am allowed to do the next XChangeKeyboardMapping.
I can fix 99.9% of the errors using a delay before XChangeKeyboardMapping and that delay is calculated by some ugly witchcraft (amount of key strokes etc.) and is way to high if 100% accuracy has to be achieved.
So my question is if there is any way to programmatically be notified or to check if a X11 client has completed XRefreshKeyboardMapping or if its map is in sync with the server map?
If not, is there a way to get another X11 client's current mapping via xlib (to check if the map is current)?
Thanks for any hints!