[PATCH xmodmap] Add support for hyphen as placeholder for preserving a current keysym

Markus Kuhn Markus.Kuhn at cl.cam.ac.uk
Thu Mar 6 07:11:19 PST 2014


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



More information about the xorg-devel mailing list