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

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