Add keymap component
authorMichael Buch <michaelbuch12@gmail.com>
Wed, 23 May 2018 06:16:30 +0000 (07:16 +0100)
committerAaron Marcher <me@drkhsh.at>
Wed, 23 May 2018 08:09:13 +0000 (10:09 +0200)
Adding a new keymap component that will
indicate the current keyboard layout (language)
and variant if any was set. I use the
standard X11 XKB APIs to retrieve and parse
the xkb_symbols set with setxkbmap.

Makefile
components/keymap.c [new file with mode: 0644]
config.def.h
slstatus.h

index 8e18969358f095991ffd152bd1ad2de0ac33abb7..7ed709985b05ff1c4d25fcaa0e310afcd8e57346 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ COM =\
        components/ip\
        components/kernel_release\
        components/keyboard_indicators\
+       components/keymap\
        components/load_avg\
        components/netspeeds\
        components/num_files\
diff --git a/components/keymap.c b/components/keymap.c
new file mode 100644 (file)
index 0000000..358a2ca
--- /dev/null
@@ -0,0 +1,97 @@
+/* See LICENSE file for copyright and license details. */
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/XKBlib.h>
+#include <X11/Xlib.h>
+
+#include "../util.h"
+
+#define LAYOUT_MAX 256
+
+/* Given a token (sym) from the xkb_symbols string
+ * check whether it is a valid layout/variant. The
+ * EXCLUDES array contains invalid layouts/variants
+ * that are part of the xkb rules config.
+ */
+static int
+IsLayoutOrVariant(char *sym)
+{
+       static const char* EXCLUDES[] = { "evdev", "inet", "pc", "base" };
+
+       size_t i;
+       for (i = 0; i < sizeof(EXCLUDES)/sizeof(EXCLUDES[0]); ++i)
+               if (strstr(sym, EXCLUDES[i])) {
+                       return 0;
+               }
+
+       return 1;
+}
+
+static void
+GetKeyLayout(char *syms, char layout[], int groupNum)
+{
+       char *token, *copy, *delims;
+       int group;
+
+       delims = "+:";
+       group = 0;
+       copy = strdup(syms);
+       token = strtok(copy, delims);
+       while (token != NULL && group <= groupNum) {
+               /* Ignore :2,:3,:4 which represent additional layout
+                * groups
+                */
+               if (IsLayoutOrVariant(token)
+                   && !(strlen(token) == 1 && isdigit(token[0]))) {
+                       strncpy (layout, token, LAYOUT_MAX);
+                       group++;
+               }
+
+               token = strtok(NULL,delims);
+       }
+
+       free(copy);
+}
+
+const char *
+keymap(void)
+{
+       static char layout[LAYOUT_MAX];
+
+       Display *dpy;
+       char *symbols = NULL;
+       XkbDescRec* desc = NULL;
+
+       memset(layout, '\0', LAYOUT_MAX);
+
+       if (!(dpy = XOpenDisplay(NULL))) {
+               warn("XOpenDisplay: Failed to open display");
+               return NULL;
+       }
+
+       ;
+       if (!(desc = XkbAllocKeyboard())) {
+               warn("XkbAllocKeyboard: failed to allocate keyboard");
+               XCloseDisplay(dpy);
+               return NULL;
+       }
+
+       XkbGetNames(dpy, XkbSymbolsNameMask, desc);
+       if (desc->names) {
+               XkbStateRec state;
+               XkbGetState(dpy, XkbUseCoreKbd, &state);
+
+               symbols = XGetAtomName(dpy, desc->names->symbols);
+               GetKeyLayout(symbols, layout, state.group);
+               XFree(symbols);
+       } else {
+               warn("XkbGetNames: failed to retrieve symbols for keys");
+               return NULL;
+       }
+
+       XkbFreeKeyboard(desc, XkbSymbolsNameMask, 1);
+       XCloseDisplay(dpy);
+
+       return layout;
+}
index 45320a30667cef06d365323e85c26b5a07e1ec3c..75debe54a9295a7d6a564f3191e0e76ee0b88b13 100644 (file)
@@ -34,6 +34,8 @@ static const char unknown_str[] = "n/a";
  * ipv6                 IPv6 address                    interface name (eth0)
  * kernel_release       `uname -r`                      NULL
  * keyboard_indicators  caps/num lock indicators        NULL
+ * keymap               layout (variant) of current     NULL
+ *                      keymap
  * load_avg             load average                    NULL
  * netspeed_rx          receive network speed           interface name (wlan0)
  * netspeed_tx          transfer network speed          interface name (wlan0)
index a18b881c4d18b408661407eb1afe27c06449f1e7..6112e7e04e82ce4d40a7b6bd3ea4df8a9836befc 100644 (file)
@@ -37,6 +37,9 @@ const char *kernel_release(void);
 /* keyboard_indicators */
 const char *keyboard_indicators(void);
 
+/* keymap */
+const char *keymap(void);
+
 /* load_avg */
 const char *load_avg(const char *);