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:
1 parent
15e04aa8f8
commit
22f6df6af9
23 files changed
+454
-58
No files matched your search
+62
-17
@@ -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));
|
||||
|
||||
Reference in new issue
Block a user