97

I'm wondering if there is any command line tool that returns the current keyboard layout.

I have XkbLayout set to us, ru.

Update: setxkbmap returns layout settings, not selected layout. E.g.:

$ setxkbmap -print | grep xkb_symbols
xkb_symbols   { include "pc+us+ru:2+inet(evdev)+capslock(grouplock)+terminate(ctrl_alt_bksp)"   };

It will return the same result no matter what the current layout is.

2

15 Answers 15

46

Maybe this is version dependent, but on my machine that uses setxkbmap 1.3.0 the following command works:

setxkbmap -query | grep layout

Note that depending on your need it may be useless to know only the layout : for instance the Dvorak variant of the US layout is quite different than the default QWERTY. The -query option of setxkbmap gives both the layout and the variant, as different fields :

$ setxkbmap -query
rules:      evdev
model:      default
layout:     fr
variant:    bepo
options:    grp:alt_shift_toggle
4
  • 4
    -query was added in setxkbmap 1.2.0
    – alanc
    Apr 6, 2013 at 1:49
  • You get the current layouts and variants and many additional info with setxkbmap -print -verbose 10
    – erik
    May 13, 2016 at 20:22
  • To set it, for example both layouts cz and us, the latter with variant dvorak (for a 104 key keyboard), use setxkbmap -model pc104 -layout cz,us -variant ,dvorak
    – erik
    May 13, 2016 at 20:27
  • 30
    doesn't let you know the active one for multiple layouts, which is what the OP asked. Bummer this got to the top.
    – xeruf
    Jun 16, 2020 at 13:06
27

Yes THERE IS a command line tool that does what you want! I just discovered it 10min ago :)

Look at here: https://github.com/nonpop/xkblayout-state

xkblayout-state print "%s"

does exactly what you want (it doesn't output an end of line, so add ; echo if you need). run the tool without parameters for the help.

0
24

There is xkb-switch which is described thus:

xkb-switch is a C++ program that allows to query and change the XKB layout state.

https://github.com/ierton/xkb-switch

Or, following nozimica's suggestion, you could use:

setxkbmap -print | awk -F"+" '/xkb_symbols/ {print $2}'

From this thread on the Arch Linux boards: https://bbs.archlinux.org/viewtopic.php?pid=539406

3
  • 1
    Thanks, xkb-switch works fine, but I hope that there was more portable solution
    – Andrew
    Apr 28, 2011 at 16:34
  • 1
    @Andrew: yes it's kind of odd there is no simple way to get the current layout. Dec 26, 2011 at 17:38
  • 21
    Your setxkbmap doesn't show the currently active layout when more than one layout is defined.
    – terdon
    Oct 22, 2015 at 12:51
19

Use this to get the code for the current layout:

$(xset -q|grep LED| awk '{ print $10 }')

This might needs to be converted to a form you want, like:

case "$(xset -q|grep LED| awk '{ print $10 }')" in
  "00000002") KBD="English" ;;
  "00001002") KBD="Thai" ;;
  *) KBD="unknown" ;;
esac
4
  • 4
    I get 00000002 even though my layout is "USA Dvorak international". Language is not enough...
    – l0b0
    Jan 5, 2012 at 11:42
  • 6
    It doesn't help if there are three or more layouts. The second and the third layouts give the same value 00001004 on my machine.
    – sastanin
    Dec 19, 2012 at 8:37
  • problem: toggle your numlock and start this command again ;)
    – andras.tim
    Jul 6, 2016 at 16:19
  • This will not work reliably - you need to use a mask since the LED indicates the status of the keyboard led buttons as well.
    – fikovnik
    Feb 7, 2018 at 9:26
17

The answers so far did not work for me. I use setkbmap with two layouts english and czech so any -print or -query will always return the two. Grepping the LED status for xset -q does not work either since that one shows the status of all keyboard leds.

The best so far was to quickly write this small utility: https://gist.github.com/fikovnik/ef428e82a26774280c4fdf8f96ce8eeb

#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;
}

and compile using

gcc -I/usr/include getxkblayout.c -lX11 -lxkbfile

3
  • In which package is XKBrules.h contained? x11proto-dev does not contain it.
    – nephewtom
    Feb 5, 2020 at 21:58
  • @nephewtom libxkbfile
    – fikovnik
    Feb 6, 2020 at 15:15
  • Works like a charm (y) May 30, 2023 at 11:24
13

You can use xkbprint to print the current layout.

For example to print the current layout as PDF use

xkbprint -color "${DISPLAY}" - |\
    ps2pdf - > current_keyboard_layout.pdf

which produces:

xkbprint result

1
  • 1
    This is one of the reasons I don't recommend using xmodmap, use setxkbmap and xkbcomp instead.
    – Flow
    Jan 21, 2021 at 20:50
9

Another simpler approach, because of fixed positions of the output of the xset -q command, is this:

xset -q | grep -A 0 'LED' | cut -c59-67

It prints 00000002 or 00001002 depending on your current keyboard layout.

2
  • 1
    I like this one, I think you can narrow it down to 8 chars. c59-66.
    – xlembouras
    Jul 31, 2014 at 13:23
  • It seems to need -c76-84 as of today
    – elig
    Feb 6 at 0:42
7

On newer systems, you can use

localectl status

It will for instance show you the following:

System Locale: LANG=en_US.UTF-8
       VC Keymap: us
      X11 Layout: us
1
  • 10
    doesn't show the currently active layout when more than one layout is defined, only shows the first
    – xeruf
    Jun 16, 2020 at 13:08
3

Partial answer: On KDE, you can apparently get the current keyboard layout through the qdbus command:

$ qdbus org.kde.keyboard /Layouts getCurrentLayout
gb(intl)

I have several layouts configured, but it only shows the one that is currently in use.

Tested on Kubuntu 18.04 (qdbus version 4.8.7). There may be other d-bus based solutions for non-Qt environments, but I do not know about them.

1
  • 1
    I'd wish there would be some generic solution which "just works"(tm) on any X11 desktop you can imagine, like KDE, GNOME and, say, WubbaLubbaDubDub.
    – Tino
    Jan 19, 2021 at 12:14
3

With GNOME D-Bus you can do it like this:

$ gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell --method org.gnome.Shell.Eval  "imports.ui.status.keyboard.getInputSourceManager().currentSource.id"
(true, '"ru"')
1

Below gives me the current keyboard layout,

setxkbmap -query | awk '/layout/ {print $2}'.

Following script toggles the keyboard layout. I personally prefer this to grp:alt_shift_toggle and similar options.

LAYOUT=$(setxkbmap -query | awk '/layout/ {print $2}')

if [[ "$LAYOUT" == "ir" ]]; then
   setxkbmap us
else
   setxkbmap ir
fi
2
  • 4
    At my side setxkbmap -query | awk '/layout/ {print $2}' gives us,de,us. It does not return the current keyboard layout but gives the available keyboard layouts. And after setxkbmap us the Win+SPC no more toggles to German, so this approach has bad sideffects.
    – Tino
    Jan 19, 2021 at 11:43
  • @Tino It print those languages because either you (with command setxkbmap -layout us,de) or the system at the startup set it like so. you can put the command setxkbmap <default language> in the startup scripts like .xinitrc or .xprofile to fix it. Afterwards when you query for current keyboard layout, it'll show you one layout. Win+SPC does not work because SPC in German is different character from that in Eng. So when you switch German the combination won't work.So in this way, the best solution is to use a hotkey with non-printable characters like Alt-Esc or Alt-shift etc.
    – ali b
    Jan 20, 2021 at 21:07
1

When using Sway, the output of setxkbmap was always us, although I had a different layout active.

I solved this using

swaymsg -t get_inputs | jq -r '.[] | select(.name=="AT Translated Set 2 keyboard") | .xkb_active_layout_name'

which accurately produces either English (US) or German on my machine.

The name of your keyboard may differ; get its name using swaymsg -t get_inputs.

The command above uses jq for parsing the JSON output of swaymsg.

0

From Goosfrabaa in the Arch Linux forums:

setxkbmap -v | awk -F "+" '/symbols/ {print $2}'

This works correctly here, and prints us(dvorak-intl) (displayed as "USA Dvorak international" in the GNOME keyboard selection menu).

2
  • 11
    It prints only the first layout in the list, not the current one.
    – sastanin
    Dec 19, 2012 at 8:38
  • How can I detect my keymap, when I use language toggle by setxkbmap? $ setxkbmap -v >> Trying to build keymap using the following components: | keycodes: evdev+aliases(qwerty) | types: complete | compat: complete+ledscroll(group_lock) | symbols: pc+us+hu:2+inet(evdev)+group(alt_shift_toggle)+compose(rwin)+terminate(ctrl_alt_bksp) | geometry: pc(pc105) in this case I got everytime "us"
    – andras.tim
    Jul 6, 2016 at 16:29
0

You can query the LED mask value from xset -q command and then apply 00001000 mask to see if the primary or the seconday layout is in use. Example:

t=$(xset -q | grep LED)
# this will remove all trash in $t before the LED mask:
mask="0b${t##*mask:  }"
not_en_mask="0b00001000"
# Now we just apply bitwise AND to $mask and see if it is equals zero or not
[[ $((mask & not_en_mask)) == 0 ]] && echo EN || echo RU
-1

You can use:

setxkbmap -print | grep xkb_symbols
3
  • 7
    it returns overall keyboard settings, not current layout (us or ru)
    – Andrew
    Apr 28, 2011 at 11:17
  • Execute it well, as @jasonwryan states if you analyze carefully that line, into it resides your layout. In my case it is latam.
    – nozimica
    Apr 28, 2011 at 14:10
  • 5
    jasonwryan version just output a part of string after '+', xkb_symbols value doesn't depend on selected layout, I always get 'us'
    – Andrew
    Apr 28, 2011 at 16:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .