summaryrefslogtreecommitdiff
path: root/components/keymap.c
diff options
context:
space:
mode:
authorMichael Buch <michaelbuch12@gmail.com>2018-05-23 07:16:30 +0100
committerAaron Marcher <me@drkhsh.at>2018-05-23 10:09:13 +0200
commit943b42de05cc3328ea74b0d9f527f17e1fcf47e7 (patch)
treeb08d4df304c35f503212741161e3298ddd376db1 /components/keymap.c
parent57f69e900bf7e3e7c60a720bf09f2134b724c5cc (diff)
Add keymap component
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.
Diffstat (limited to 'components/keymap.c')
-rw-r--r--components/keymap.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/components/keymap.c b/components/keymap.c
new file mode 100644
index 0000000..358a2ca
--- /dev/null
+++ b/components/keymap.c
@@ -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;
+}