85 lines
3.6 KiB
C
85 lines
3.6 KiB
C
// Deterministic native queue boundary: a key was captured before suspension,
|
|
// but remains in Xlib's queue when the Go owner gives the keyboard back.
|
|
#include "commands_native.h"
|
|
#include <X11/keysym.h>
|
|
#include <X11/XKBlib.h>
|
|
#include <X11/extensions/XTest.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
int main(int argc, char **argv) {
|
|
int error = 0, failed = 0;
|
|
int capsHandoff = argc == 2 && strcmp(argv[1], "caps-handoff") == 0;
|
|
CommandDevice *device = open_commands(1, 0, capsHandoff, &error);
|
|
if (!device) { fprintf(stderr, "open: %d\n", error); return 1; }
|
|
if (capsHandoff) {
|
|
set_command_keys(device, 0);
|
|
// A terminal reader changes the real lock while Cthulhu is suspended.
|
|
XkbLockModifiers(device->display, XkbUseCoreKbd, LockMask, LockMask);
|
|
XSync(device->display, False);
|
|
if (!(command_lock_state(device) & 1)) {
|
|
fprintf(stderr, "suspended lock read used stale reader state\n");
|
|
failed = 1;
|
|
}
|
|
set_command_keys(device, 1);
|
|
if (!device->capsLocked) {
|
|
fprintf(stderr, "resumed reader did not adopt external Caps Lock state\n");
|
|
failed = 1;
|
|
}
|
|
XkbLockModifiers(device->display, XkbUseCoreKbd, LockMask, 0);
|
|
XSync(device->display, False);
|
|
} else if (argc == 2 && strcmp(argv[1], "queued") == 0) {
|
|
if (XGrabKeyboard(device->display, device->root, False,
|
|
GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) return 1;
|
|
device->active = 1;
|
|
XEvent event = {0};
|
|
event.xkey.type = KeyPress;
|
|
event.xkey.display = device->display;
|
|
event.xkey.window = device->root;
|
|
event.xkey.keycode = XKeysymToKeycode(device->display, XK_q);
|
|
XPutBackEvent(device->display, &event);
|
|
release_command_keyboard(device);
|
|
set_command_keys(device, 0);
|
|
CommandKey key = {0};
|
|
int result = next_command_key(device, &key);
|
|
if (result != 0 || device->active) {
|
|
fprintf(stderr, "suspended queued key: result=%d active=%d\n", result, device->active);
|
|
failed = 1;
|
|
}
|
|
} else if (argc == 2 && strcmp(argv[1], "passive") == 0) {
|
|
Display *sender = XOpenDisplay(NULL);
|
|
int code = XKeysymToKeycode(sender, XK_Insert);
|
|
XTestFakeKeyEvent(sender, code, True, CurrentTime);
|
|
XSync(sender, False); // The synchronous passive grab is now active.
|
|
set_command_keys(device, 0);
|
|
CommandKey key = {0};
|
|
next_command_key(device, &key);
|
|
int status = XGrabKeyboard(sender, DefaultRootWindow(sender), False,
|
|
GrabModeAsync, GrabModeAsync, CurrentTime);
|
|
if (status != GrabSuccess) {
|
|
fprintf(stderr, "suspension left activated passive grab: %d\n", status);
|
|
failed = 1;
|
|
}
|
|
XUngrabKeyboard(sender, CurrentTime);
|
|
close_commands(device);
|
|
device = NULL;
|
|
XTestFakeKeyEvent(sender, code, False, CurrentTime);
|
|
XSync(sender, False);
|
|
XCloseDisplay(sender);
|
|
} else {
|
|
set_command_keys(device, 0);
|
|
CommandKey keys[2] = {{.pressed = 1}, {.pressed = 0}};
|
|
keys[0].code = keys[1].code = XKeysymToKeycode(device->display, XK_q);
|
|
if (replay_command_keys(device, keys, 2) != 0) return 1;
|
|
CommandDevice *competitor = open_commands(1, 0, 0, &error);
|
|
if (!competitor) {
|
|
fprintf(stderr, "replay restored disabled passive grabs: %d\n", error);
|
|
failed = 1;
|
|
} else {
|
|
close_commands(competitor);
|
|
}
|
|
}
|
|
if (device) close_commands(device);
|
|
return failed;
|
|
}
|