Skip to content

Instantly share code, notes, and snippets.

@torbiak
Created January 5, 2017 05:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save torbiak/3ef0082a1aba63169912913a37896a46 to your computer and use it in GitHub Desktop.
Save torbiak/3ef0082a1aba63169912913a37896a46 to your computer and use it in GitHub Desktop.
Reproduce X11 bug where the second KeyRelease event is missing if two grabbed keys are released in quick succession.
// grabtest tries to reproduce an X11 bug where, when two keys grabbed using
// XGrabKey are held down and then quickly released, the second KeyRelease
// event never makes it to the event queue.
//
// make LDFLAGS=-lX11\ -lXtst grabtest
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
#define LEN(X) (sizeof(X) / sizeof(X[0]))
#define PRESS 1
#define RELEASE 0
Display *dpy;
Window root;
int screen;
void
read_n_key_events(int n)
{
for (int i = 0; i < n; i++) {
XEvent ev;
XMaskEvent(dpy, KeyPressMask|KeyReleaseMask, &ev);
KeySym keysym = XLookupKeysym(&ev.xkey, 0);
int ispress = ev.type == KeyPress;
printf("%s %s\n", ispress ? "press" : "release", XKeysymToString(keysym));
}
}
int
main()
{
dpy = XOpenDisplay(NULL);
assert(dpy);
root = DefaultRootWindow(dpy);
screen = DefaultScreen(dpy);
XSelectInput(dpy, root, KeyPressMask|KeyReleaseMask);
KeySym keysyms[] = {XK_d, XK_f};
// Grab keys.
unsigned modifiers = 0;
for (int i = 0; i < LEN(keysyms); i++) {
KeyCode keycode = XKeysymToKeycode(dpy, keysyms[i]);
int ok = XGrabKey(dpy, keycode, modifiers, root, True, GrabModeAsync, GrabModeAsync);
assert(ok);
XKeyboardControl ctrl = {.key=keycode, .auto_repeat_mode=AutoRepeatModeOff};
XChangeKeyboardControl(dpy, KBKey|KBAutoRepeatMode, &ctrl);
}
// Hold keys d and f, then quickly release them.
KeyCode d = XKeysymToKeycode(dpy, XK_d);
KeyCode f = XKeysymToKeycode(dpy, XK_f);
XTestFakeKeyEvent(dpy, d, PRESS, CurrentTime);
XTestFakeKeyEvent(dpy, f, PRESS, CurrentTime);
XTestFakeKeyEvent(dpy, d, RELEASE, CurrentTime);
XFlush(dpy);
read_n_key_events(3);
XTestFakeKeyEvent(dpy, f, RELEASE, CurrentTime);
XFlush(dpy);
read_n_key_events(1);
// Clean up.
for (int i = 0; i < LEN(keysyms); i++) {
KeyCode keycode = XKeysymToKeycode(dpy, keysyms[i]);
XKeyboardControl ctrl = {.key=keycode, .auto_repeat_mode=AutoRepeatModeDefault};
XChangeKeyboardControl(dpy, KBKey|KBAutoRepeatMode, &ctrl);
XUngrabKey(dpy, keycode, modifiers, root);
}
XFlush(dpy);
}
@Beyley
Copy link

Beyley commented Apr 12, 2022

Did you ever find a solution to this issue? im currently having this with an app im developing, and i cannot find a solution

@torbiak
Copy link
Author

torbiak commented Apr 12, 2022

No, sadly. I think this GNOME mailing list post is also referring to the same issue, and that's the only other reference to it that I've seen. I looked through my notes for torbiak/ptrkeys but don't see much else about it except for this commit message. I guess I didn't file a bug or anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment