Key Sequence Transformation in X11
This article is originally titled Abandoning treatment for X11, for my xkeymacs project.
I think I’ve done all that’s possible to achieve with X11 API in this project, but there still remain a bunch of issues. This document is about what they are and why they may not be resolved as an X11 application.
Before we start with the issues, we need clarify the situation first.
There are three ways to grab key events in X11:
GrabModeAsync. In the meantime, there is only one way to send a key event in X11:
XSendEvents marks events sent as synthesized and a bunch of applications (such as
xterm) ignore events with this flag for some security reasons, according to various sources.
If you want to replay the key event you just grabbed, use
ReplayKeyboard. This requires the key event to come from
XGrabKey or a previous
SyncKeyboard, but not from a
You cannot use
XGrabKeyboard along with
XTestFakeKeyEvent because the former sets an active grab and it will receive the key event faked by yourself. If you want to
XUngrabKeyboard and wait for
XTestFakeKeyEvent to accomplish, sadly there seems to be no way.
XFlush flushes your own request to X server, while
XSync flushes and make X server process all requests and generate events, but not handling them, according to this thread.
XGrabKey is called a passive grab. It is activated and then behaves like
XGrabKeyboard when the registered key and modifier combination is found, and actually ungrabbed after the
KeyRelease event of that combination (see this mail). So if you send a key in
KeyPress event, you will intercept the key you just sent. To workaround this issue, you can do
XUngrabKeyboard before you send the key. This results in garbage
KeyRelease events sent to the focused window, however it is normally ignored. Another workaround would be sending the key in
KeyRelease event, which works, but is not the desired behavior.
Note that if you replay a key event with
KeyPress, It will also result in garbage
KeyRelease events, because according to the documentation the replayed event will ignore any key grabs set by any client.
So here is the first issue.
Grabbed keys sent by
XTestFakeKeyEventcannot be replayed
When testing the application, I was surprised to find that when I sent keys that are also grabbed by myself and deliberately do the replay in
KeyPress, I still receive
KeyReleaseevents for them. That is to say the
XAllowEventreplay failed. I guess this is because
XTestFakeKeyEventis part of the
XTestextension and is aimed for automating testing, so the internal implementation did not take this situation into consideration. So there may be no workaround for this.
An example for this issue can be when I grabbed
Control+Xfor C-x mode and I send
Control+Xinside the handling of
When sending some key combination, one have to know the status of the modifier keys and adjust them, send the key, and then restore them. This is expected to happen in a very short period of time so the user won’t notice. To accomplish this,
XQueryKeymap and multiple
XTestFakeKeyEvent is used.
And the second issue.
Sending keys containing
F8causes user to be switched to
When sending keys containing
F4, sometimes I got switched to
ttyby an unexpected
Control+Alt+F3/4combination. This happens for most of the time when I send
(Control+X) k. You can see that there is nothing about
Alt, but still I was almost always switched to
xevreported the expected key sequence for this situation. The underlying logic is unknown, it may have something to do with
ttyswitching hot key implementation.
And some other issues.
Auto repeat cannot work if we intercept the
X server generates continuous paired
KeyReleaseevent for clients if a key is physically held for a long time. However if we intercept the first
KeyPressevent, and send another key event, then the auto repeat just disappears. There doesn’t seem to be a solution for this issue.
There is a perceptible (annoying but bearable) pause when using the above stated approach to implement keyboard macros. Seems no way to resolve either.
Note that using
GrabModeAsynchelps to improve the performance a little bit, but it results in various problems that I haven’t investigated yet.
So the conclusion is that, while X11 provided some API for keyboard event operations, it is vague in documentation and working mechanism, and clearly not designed, nor suitable for translating key sequences into others. This may be the reason why almost no such project like this is known.
For an alternative API, some people in a mailing list suggested Atspi, which I haven’t tried out myself.
Later I found out that this can be achieved with
For a python implementation, see my pykeymacs.