[PATCH] XKB named indicator support for led state query/set

Alan Coopersmith Alan.Coopersmith at Sun.COM
Tue Jun 16 13:26:11 PDT 2009


xset q now lists XKB named indicator states in addition to led bitmask

Sample output:
 Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  0000000a
  XKB indicators:
    00: Caps Lock:   off    01: Num Lock:    on     02: Scroll Lock: off
    03: Compose:     on     04: Shift Lock:  off    05: Group 2:     off
    06: Mouse Keys:  off
 [...]

New options "xset led named <name>" and "xset -led named <name>" allow
turning named leds/virtual indicators on & off.

('named' is keyword necessary to avoid ambiguity if an XKB indicator
 is given a numeric name or a name that matches an existing xkb option
 due to xset's horrible historic command line syntax model.)

Signed-off-by: Alan Coopersmith <alan.coopersmith at sun.com>
---

While debugging a complex application recently failing in XkbSetNamedIndicator,
I wished for a simpler test case - since xset already has get/state for leds by
number, it seemed the most likely place to stick such functionality, even though
xset has too many options already, with a horrible command line syntax for them.

Still, "xset led named 'Scroll Lock'" seems more user friendly than "xset led 2"
and saves the long diatribe on how different X servers may have different led
values for the same led and leaving users to trial & error to find what theirs
are.

 xset.c   |  137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 xset.man |   10 +++-
 2 files changed, 140 insertions(+), 7 deletions(-)

diff --git a/xset.c b/xset.c
index ae1d818..5283b09 100644
--- a/xset.c
+++ b/xset.c
@@ -153,6 +153,7 @@ static void set_bell_dur(Display *dpy, int duration);
 static void set_font_path(Display *dpy, char *path, int special,
 			  int before, int after);
 static void set_led(Display *dpy, int led, int led_mode);
+static void xkbset_led(Display *dpy, const char *led, int led_mode);
 static void set_mouse(Display *dpy, int acc_num, int acc_denom, int threshold);
 static void set_saver(Display *dpy, int mask, int value);
 static void set_repeat(Display *dpy, int key, int auto_repeat_mode);
@@ -439,6 +440,15 @@ main(int argc, char *argv[])
 		break;
 	    }
 	    arg = nextarg(i, argv);
+	    if (strcmp(arg, "named") == 0) {
+		if (++i >= argc) {
+		    usage("missing argument to led named", NULL);
+		} else {
+		    arg = nextarg(i, argv);
+		    xkbset_led(dpy, arg, values.led_mode);
+		}
+		break;
+	    }
 	    if (is_number(arg, 32) && atoi(arg) > 0) {
 		values.led = atoi(arg);
 		i++;
@@ -453,6 +463,15 @@ main(int argc, char *argv[])
 		break;
 	    }
 	    arg = nextarg(i, argv);
+	    if (strcmp(arg, "named") == 0) {
+		if (++i >= argc) {
+		    usage("missing argument to -led named", NULL);
+		} else {
+		    arg = nextarg(i, argv);
+		    xkbset_led(dpy, arg, values.led_mode);
+		}
+		break;
+	    }
 	    if (strcmp(arg, "on") == 0) {
 		i++;
 	    } else if (strcmp(arg, "off") == 0) { /* ...except in this case. */
@@ -1061,6 +1080,36 @@ set_led(Display *dpy, int led, int led_mode)
 }

 static void
+xkbset_led(Display *dpy, const char *led, int led_mode)
+{
+#ifndef XKB
+    error("  xset was not built with XKB Extension support\n");
+#else
+    int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
+    int xkbopcode, xkbevent, xkberror;
+    Atom ledatom;
+
+    if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent, &xkberror,
+			  &xkbmajor, &xkbminor)) {
+	ledatom = XInternAtom(dpy, led, True);
+	if ((ledatom != None) &&
+	    XkbGetNamedIndicator(dpy, ledatom, NULL, NULL, NULL, NULL)) {
+	    if (XkbSetNamedIndicator(dpy, ledatom, True,
+				     led_mode, False, NULL) == False) {
+		printf("Failed to set led named %s %s\n",
+		       led, led_mode ? "on" : "off");
+	    }
+	} else {
+	    fprintf(stderr,"%s: Invalid led name: %s\n", progName, led);
+	}
+    } else {
+	printf("  Server does not have the XKB Extension\n");
+    }
+#endif
+    return;
+}
+
+static void
 set_mouse(Display *dpy, int acc_num, int acc_denom, int threshold)
 {
     int do_accel = True, do_threshold = True;
@@ -1314,10 +1363,86 @@ query(Display *dpy)
 #ifdef XKB
     if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent, &xkberror, &xkbmajor,
 			  &xkbminor)
-	&& (xkb = XkbAllocKeyboard()) != NULL
-	&& XkbGetControls(dpy, XkbRepeatKeysMask, xkb) == Success)
-	printf("  auto repeat delay:  %d    repeat rate:  %d\n",
-	       xkb->ctrls->repeat_delay, 1000 / xkb->ctrls->repeat_interval);
+	&& (xkb = XkbAllocKeyboard()) != NULL) {
+	if (XkbGetNames(dpy, XkbIndicatorNamesMask, xkb) == Success) {
+	    Atom iatoms[XkbNumIndicators];
+	    char *iatomnames[XkbNumIndicators];
+	    Bool istates[XkbNumIndicators];
+	    int inds[XkbNumIndicators];
+	    int activecount = 0;
+	    int maxnamelen = 0;
+	    int columnwidth;
+	    int linewidth;
+
+	    printf("  XKB indicators:\n");
+
+	    for (i = 0, j = 0; i < XkbNumIndicators; i++) {
+		if (xkb->names->indicators[i] != None) {
+		    iatoms[j++] =  xkb->names->indicators[i];
+		}
+	    }
+
+	    if (XGetAtomNames(dpy, iatoms, j, iatomnames)) {
+		for (i = 0; i < j; i++) {
+		    Bool state;
+		    int ind;
+
+		    if (XkbGetNamedIndicator(dpy, iatoms[i], &inds[i],
+					     &istates[i], NULL, NULL)) {
+			int namelen = strlen(iatomnames[i]);
+			if (namelen > maxnamelen) {
+			    maxnamelen = namelen;
+			}
+			activecount++;
+		    } else {
+			inds[i] = -1;
+		    }
+		}
+	    }
+
+	    if (activecount == 0) {
+		printf("    None\n");
+	    } else {
+
+#define XKB_IND_FORMAT_CHARS 13 /* size of other chars in '    DD: X: off' */
+#define MAX_LINE_WIDTH	     76
+
+		columnwidth = maxnamelen + XKB_IND_FORMAT_CHARS;
+		if (columnwidth > MAX_LINE_WIDTH) {
+		    columnwidth = MAX_LINE_WIDTH;
+		}
+
+		for (i = 0, linewidth = 0; i < activecount ; i++) {
+		    if (inds[i] != -1) {
+			int spaces = columnwidth - XKB_IND_FORMAT_CHARS
+			    - strlen(iatomnames[i]);
+
+			if (spaces < 0)
+			    spaces = 0;
+
+			linewidth += printf("    %02d: %s: %*s",
+					    inds[i], iatomnames[i],
+					    spaces + 3,
+					    on_or_off(istates[i],
+						      True,  "on ",
+						      False, "off", buf));
+		    }
+		    if (linewidth > (MAX_LINE_WIDTH - columnwidth)) {
+			printf("\n");
+			linewidth = 0;
+		    }
+		}
+		if (linewidth > 0) {
+		    printf("\n");
+		}
+	    }
+	}
+	if (XkbGetControls(dpy, XkbRepeatKeysMask, xkb) == Success) {
+	    printf("  auto repeat delay:  %d    repeat rate:  %d\n",
+		   xkb->ctrls->repeat_delay,
+		   1000 / xkb->ctrls->repeat_interval);
+	}
+    }
 #ifdef XF86MISC
     else
 #endif
@@ -1578,6 +1703,10 @@ usage(char *fmt, ...)
     fprintf(stderr, "    To set LED states off or on:\n");
     fprintf(stderr, "\t-led [1-32]         led off\n");
     fprintf(stderr, "\t led [1-32]         led on\n");
+#ifdef XKB
+    fprintf(stderr, "\t-led named 'name'   led off\n");
+    fprintf(stderr, "\t led named 'name'   led on\n");
+#endif
     fprintf(stderr, "    To set mouse acceleration and threshold:\n");
     fprintf(stderr, "\t m [acc_mult[/acc_div] [thr]]    m default\n");
     fprintf(stderr, "    To set pixel colors:\n");
diff --git a/xset.man b/xset.man
index 02cd87c..7446efc 100644
--- a/xset.man
+++ b/xset.man
@@ -54,7 +54,7 @@ xset - user preference utility for X
 [-led [\fIinteger\fP]]
 [+led [\fIinteger\fP]]
 .br
-[led {on|off}]
+[led {on|off|named \fIindicator\fP}]
 .br
 [mouse [\fIaccel_mult\fP[/\fIaccel_div\fP] [\fIthreshold\fP]]] [mouse default]
 .br
@@ -176,10 +176,14 @@ If no parameter or the 'on' flag is given, all LEDs are
turned on.
 If a preceding dash or the flag 'off' is given, all LEDs are turned off.
 If a value between 1 and 32 is given, that LED will be turned on or off
 depending on the existence of a preceding dash.
-A common LED which can be controlled is the ``Caps Lock'' LED.  ``xset
-led 3'' would turn led #3 on.  ``xset -led 3'' would turn it off.
+``xset led 3'' would turn led #3 on.  ``xset -led 3'' would turn it off.
 The particular LED values may refer to different LEDs on different
 hardware.
+If the X server supports the XKEYBOARD (XKB) extension, leds may be
+referenced by the XKB indicator name by specifying the `named' keyword
+and the indicator name.   For example, to turn on the Scroll Lock LED:
+.IP
+xset led named "Scroll Lock"
 .PP
 .TP 8
 .B mouse
-- 
1.5.6.5


-- 
	-Alan Coopersmith-           alan.coopersmith at sun.com
	 Sun Microsystems, Inc. - X Window System Engineering



More information about the xorg-devel mailing list