Attempt to make modifier key changes take affect when the dialogue closes. This means you don't have to restart Fenrir to apply them.

This commit is contained in:
Storm Dragon committed 2026-10-29 18:27:20 -04:00
1 parent 15e04aa8f8
commit 22f6df6af9
23 files changed
+454 -58

No files matched your search

+62 -17
View File
@@ -175,7 +175,7 @@ int terminal_key(VTerm *vt, const TerminalEvent *event, char *bytes, int size) {
return length;
}
struct TerminalX { Display *display; Window window; unsigned int numlock; int grabbed; XIM im; XIC ic; int scriptKeys[KEY_MAX+1]; int scriptKeyCount; };
struct TerminalX { Display *display; Window window; unsigned int numlock; int grabbed; XIM im; XIC ic; int scriptKeys[KEY_MAX+1]; int scriptKeyCount; unsigned char grabbedKeys[256]; };
static int x_error;
static int trap_error(Display *display, XErrorEvent *event) {
(void)display;
@@ -206,8 +206,7 @@ static void observe_windows(TerminalX *x, Window window, int depth, int *remaini
}
if (children) XFree(children);
}
static void install_grabs(TerminalX *x) {
Window window = x->window;
static void collect_grabs(TerminalX *x, const int *keys, int count, unsigned char wanted[256]) {
x->numlock = 0;
XModifierKeymap *modifiers = XGetModifierMapping(x->display);
KeyCode numlock = XKeysymToKeycode(x->display, XK_Num_Lock);
@@ -218,14 +217,14 @@ static void install_grabs(TerminalX *x) {
x->numlock |= 1u << mask;
XFreeModifiermap(modifiers);
}
KeySym keys[] = {XK_Insert,
KeySym fixedKeys[] = {XK_Insert,
XK_KP_Insert, XK_KP_End, XK_KP_Down, XK_KP_Page_Down, XK_KP_Left,
XK_KP_Begin, XK_KP_Right, XK_KP_Home, XK_KP_Up, XK_KP_Page_Up,
XK_KP_Delete, XK_KP_Enter, XK_KP_Add, XK_KP_Subtract, XK_KP_Divide,
XK_Control_L, XK_Control_R};
for (unsigned int i=0; i<sizeof(keys)/sizeof(keys[0]); i++) {
KeyCode code = XKeysymToKeycode(x->display, keys[i]);
if (code) XGrabKey(x->display, code, AnyModifier, window, False, GrabModeAsync, GrabModeSync);
for (unsigned int i=0; i<sizeof(fixedKeys)/sizeof(fixedKeys[0]); i++) {
KeyCode code = XKeysymToKeycode(x->display, fixedKeys[i]);
if (code) wanted[code] = 1;
}
// Script modifiers may be any Linux key, not just Compose. Resolve through
// the same symbol translation as event routing instead of assuming that
@@ -235,14 +234,63 @@ static void install_grabs(TerminalX *x) {
for (int code=first; code<=last; code++) {
KeySym symbol = XkbKeycodeToKeysym(x->display, code, 0, 0);
int key = terminal_key_code(symbol, code);
for (int i=0; i<x->scriptKeyCount; i++) {
if (key == x->scriptKeys[i]) {
XGrabKey(x->display, code, AnyModifier, window, False, GrabModeAsync, GrabModeSync);
for (int i=0; i<count; i++) {
if (key == keys[i]) {
wanted[code] = 1;
break;
}
}
}
}
static int replace_grabs(TerminalX *x, const int *keys, int count, int idleOnly) {
if (count < 0 || count > KEY_MAX+1) return -EINVAL;
// Freeze other clients only for the bounded grab transaction. This closes
// the gap between the idle check, adding grabs and switching key sets.
XGrabServer(x->display);
XSync(x->display, False);
if (idleOnly) {
char down[32];
XQueryKeymap(x->display, down);
int busy = XPending(x->display) != 0;
for (int i=0; i<32; i++) busy |= down[i] != 0;
if (busy) { XUngrabServer(x->display); XFlush(x->display); return 1; }
}
unsigned char wanted[256] = {0};
XErrorHandler previous = begin_trap(x->display);
collect_grabs(x, keys, count, wanted);
for (int code=0; code<256; code++) {
if (wanted[code] && !x->grabbedKeys[code])
XGrabKey(x->display, code, AnyModifier, x->window, False, GrabModeAsync, GrabModeSync);
}
int error = end_trap(x->display, previous);
if (error) {
previous = begin_trap(x->display);
for (int code=0; code<256; code++) {
if (wanted[code] && !x->grabbedKeys[code])
XUngrabKey(x->display, code, AnyModifier, x->window);
}
end_trap(x->display, previous);
} else {
for (int code=0; code<256; code++) {
if (x->grabbedKeys[code] && !wanted[code])
XUngrabKey(x->display, code, AnyModifier, x->window);
}
memcpy(x->grabbedKeys, wanted, sizeof(wanted));
x->scriptKeyCount = count;
for (int i=0; i<count; i++) x->scriptKeys[i] = keys[i];
}
XUngrabServer(x->display);
XSync(x->display, False);
return error ? -error : 0;
}
static void install_grabs(TerminalX *x) {
unsigned char wanted[256] = {0};
collect_grabs(x, x->scriptKeys, x->scriptKeyCount, wanted);
for (int code=0; code<256; code++) {
if (wanted[code]) XGrabKey(x->display, code, AnyModifier, x->window, False, GrabModeAsync, GrabModeSync);
}
memcpy(x->grabbedKeys, wanted, sizeof(wanted));
}
int terminal_x_caps_lock(TerminalX *x, int enabled) {
if (!XkbLockModifiers(x->display, XkbUseCoreKbd, LockMask, enabled ? LockMask : 0)) return -EIO;
XSync(x->display, False);
@@ -254,13 +302,10 @@ int terminal_x_toggle_caps(TerminalX *x) {
return terminal_x_caps_lock(x, !(state.locked_mods & LockMask));
}
int terminal_x_script_keys(TerminalX *x, const int *keys, int count) {
if (count < 0 || count > KEY_MAX+1) return -EINVAL;
XErrorHandler previous = begin_trap(x->display);
x->scriptKeyCount = count;
for (int i=0; i<count; i++) x->scriptKeys[i] = keys[i];
install_grabs(x);
int error = end_trap(x->display, previous);
return error ? -error : 0;
return replace_grabs(x, keys, count, 0);
}
int terminal_x_update_keys(TerminalX *x, const int *keys, int count) {
return replace_grabs(x, keys, count, 1);
}
TerminalX *terminal_x_open(unsigned long window, int *error) {
TerminalX *x = calloc(1, sizeof(*x));