So far, a keycode or keysym command always overwrote the entire list of keysyms associated with a keycode. However, users often want to modify only some of the keysyms in the list, e.g. only the keysyms assigned when the Mode_switch key is pressed. With this patch, it is now possible to reassign some symkeys without affecting others on the same key, by listing a "-" where no change is requested.
Example: Previously, if I wanted to have "twosuperior" (²) assigned to the key "2" when Mode_shift is pressed, I had to write xmodmap -e "keysym 2 = 2 quotedbl twosuperior NoSymbol" on a UK keyboard, but xmodmap -e "keysym 2 = 2 at twosuperior NoSymbol" on a US keyboard, which is tedious where multiple layouts are used. After this patch, the simpler command xmodmap -e "keysym 2 = - - twosuperior NoSymbol" will work on both UK and US keyboards alike. --- handle.c | 43 ++++++++++++++++++++++++++++++++----------- man/xmodmap.man | 2 ++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/handle.c b/handle.c index 3f05a46..cc18c33 100644 --- a/handle.c +++ b/handle.c @@ -51,6 +51,8 @@ static XModifierKeymap *map = NULL; struct wq work_queue = {NULL, NULL}; +/* placeholder for a KeySym that should not be changed */ +#define KeepSymbol ((KeySym) -1) /* * common utility routines @@ -304,6 +306,10 @@ parse_keysym(const char *line, int n, char **name, KeySym *keysym) *keysym = NoSymbol; return (True); } + if (!strcmp(*name, "-")) { + *keysym = KeepSymbol; + return (True); + } *keysym = XStringToKeysym (*name); if (*keysym == NoSymbol && '0' <= **name && **name <= '9') return parse_number(*name, keysym); @@ -1213,12 +1219,14 @@ execute_work_queue (void) static int exec_keycode(struct op_keycode *opk) { - if (!opk->target_keycode) { - int i, j; - KeyCode free; + KeyCode keycode = opk->target_keycode; + int i, old_count = 0; + KeySym *old_keysyms = NULL; + + if (!keycode) { + int j; if (!opk->count) return (0); - free = 0; for (i = min_keycode; i <= max_keycode; i++) { for (j = 0; j < opk->count; j++) { if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != opk->keysyms[j]) @@ -1226,29 +1234,42 @@ exec_keycode(struct op_keycode *opk) } if (j >= opk->count) return (0); - if (free) + if (keycode) continue; for (j = 0; j < 8; j++) { if (XKeycodeToKeysym(dpy, (KeyCode) i, j) != None) break; } if (j >= 8) - free = i; + keycode = i; } - if (!free) { + if (!keycode) { fprintf(stderr, "%s: no available keycode for assignment\n", ProgramName); return (-1); } - XChangeKeyboardMapping (dpy, free, opk->count, opk->keysyms, 1); } else if (opk->count == 0) { KeySym dummy = NoSymbol; XChangeKeyboardMapping (dpy, opk->target_keycode, 1, &dummy, 1); - } else { - XChangeKeyboardMapping (dpy, opk->target_keycode, opk->count, - opk->keysyms, 1); + return (0); } + + /* replace any KeepSymbol keysyms with fetched previous value */ + for (i = 0; i < opk->count; i++) { + if (opk->keysyms[i] == KeepSymbol) { + if (!old_keysyms) + old_keysyms = XGetKeyboardMapping (dpy, keycode, 1, &old_count); + if (old_keysyms && i < old_count) + opk->keysyms[i] = old_keysyms[i]; + else + opk->keysyms[i] = NoSymbol; + } + } + if (old_keysyms) XFree(old_keysyms); + + XChangeKeyboardMapping (dpy, keycode, opk->count, opk->keysyms, 1); + return (0); } diff --git a/man/xmodmap.man b/man/xmodmap.man index 1ed1ca1..fcb7773 100644 --- a/man/xmodmap.man +++ b/man/xmodmap.man @@ -153,6 +153,8 @@ are not used in any major X server implementation. The first keysym is used when no modifier key is pressed in conjunction with this key, the second with Shift, the third when the Mode_switch key is used with this key and the fourth when both the Mode_switch and Shift keys are used. +A hyphen instead of a keysym name keeps the keysym currently assigned +at that position. .TP 8 .B keycode any = \fIKEYSYMNAME ...\fP If no existing key has the specified list of keysyms assigned to it, -- 1.7.9.5 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel