/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #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; }