Skip to content

Instantly share code, notes, and snippets.

@fikovnik
Created February 7, 2018 09:43
Show Gist options
  • Save fikovnik/ef428e82a26774280c4fdf8f96ce8eeb to your computer and use it in GitHub Desktop.
Save fikovnik/ef428e82a26774280c4fdf8f96ce8eeb to your computer and use it in GitHub Desktop.
Get keyboard layout using X11
// compile with `gcc -I/usr/include getxkblayout.c -lX11 -lxkbfile`
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>
int main(int argc, char **argv) {
Display *dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
fprintf(stderr, "Cannot open display\n");
exit(1);
}
XkbStateRec state;
XkbGetState(dpy, XkbUseCoreKbd, &state);
XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
char *group = XGetAtomName(dpy, desc->names->groups[state.group]);
printf("Full name: %s\n", group);
XkbRF_VarDefsRec vd;
XkbRF_GetNamesProp(dpy, NULL, &vd);
char *tok = strtok(vd.layout, ",");
for (int i = 0; i < state.group; i++) {
tok = strtok(NULL, ",");
if (tok == NULL) {
return 1;
}
}
printf("Layout name: %s\n", tok);
return 0;
}
@su8
Copy link

su8 commented Apr 1, 2018

Thanks for sharing it to stackoverflow.

@su8
Copy link

su8 commented Apr 1, 2018

You are missing XFree(group); and XCloseDisplay(dpy); at the end, just before return 0;.

@kulak
Copy link

kulak commented Jan 1, 2021

it works well (returns Russian and US layouts in XFCE). works great.

@rderooy
Copy link

rderooy commented Mar 15, 2022

Fails here with a segfault on XWayland on this line:

char *group = XGetAtomName(dpy, desc->names->groups[state.group]);

Which is caused by "desc" in the line before containing (null).

Here is a slightly cleaned-up version that at least does not segfault, although it fails to return the data.

// compile with `gcc -I/usr/include getxkblayout.c -lX11 -lxkbfile`
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>

int main(int argc, char **argv) {
  Display *dpy = XOpenDisplay(NULL);

  if (dpy == NULL) {
    fprintf(stderr, "Cannot open display\n");
    exit(1);
  }

  XkbStateRec state;
  XkbGetState(dpy, XkbUseCoreKbd, &state);

  XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
  if (desc == NULL) {
    fprintf(stderr, "Failed to get keyboard\n");
    exit(1);
  }
  char *group = XGetAtomName(dpy, desc->names->groups[state.group]);
  printf("Full name: %s\n", group);

  XkbRF_VarDefsRec vd;
  XkbRF_GetNamesProp(dpy, NULL, &vd);

  char *tok = strtok(vd.layout, ",");

  for (int i = 0; i < state.group; i++) {
    tok = strtok(NULL, ",");
    if (tok == NULL) {
      return 1;
    }
  }

  printf("Layout name: %s\n", tok);

  XFree(group);
  XCloseDisplay(dpy);

  return 0;
}

@brs-brs
Copy link

brs-brs commented Jul 30, 2024

Hi! I have packaged slightly modified version of this gist: https://github.com/brs-brs/getxkblayout

@jysr0
Copy link

jysr0 commented Jul 27, 2025

Looks like it works on terminal, but not the status bar like dwmblocks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment