94

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.

Matthias Braun
  • 7,797
  • 7
  • 45
  • 54
Andrew
  • 1,392
  • 2
  • 10
  • 14
  • I am not really good at D-Bus, but it should be easy to track the current keyboard layout using it I think. Although it may not be able to do so if there is no active switch. – neydroydrec Dec 26 '11 at 18:16
  • Does this answer your question? [How to get current keyboard layout from the command line?](https://unix.stackexchange.com/questions/402719/how-to-get-current-keyboard-layout-from-the-command-line) – user598527 Mar 27 '23 at 13:32

15 Answers15

42

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
mars
  • 493
  • 4
  • 2
  • 4
    `-query` was added in [setxkbmap 1.2.0](http://lists.x.org/archives/xorg/2010-September/051048.html) – alanc Apr 06 '13 at 01:49
  • You get the current layouts and variants and many additional info with `setxkbmap -print -verbose 10` – erik May 13 '16 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 '16 at 20:27
  • 27
    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 '20 at 13:06
26

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.

Pablo Saratxaga
  • 2,491
  • 26
  • 16
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

jasonwryan
  • 71,734
  • 34
  • 193
  • 226
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
l0b0
  • 50,672
  • 41
  • 197
  • 360
Pepa
  • 199
  • 1
  • 2
  • 4
    I get `00000002` even though my layout is "USA Dvorak international". Language is not enough... – l0b0 Jan 05 '12 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 '12 at 08:37
  • problem: toggle your numlock and start this command again ;) – andras.tim Jul 06 '16 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 07 '18 at 09:26
16

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

fikovnik
  • 261
  • 2
  • 4
12

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

Flow
  • 819
  • 1
  • 11
  • 23
  • This is one of the reasons I don't recommend using `xmodmap`, use `setxkbmap` and `xkbcomp` instead. – Flow Jan 21 '21 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.

Kevin
  • 40,087
  • 16
  • 88
  • 112
nikospag
  • 99
  • 1
  • 2
8

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
oLen
  • 188
  • 1
  • 7
  • 7
    doesn't show the currently active layout when more than one layout is defined, only shows the first – xeruf Jun 16 '20 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.

Qeole
  • 684
  • 8
  • 12
  • 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 '21 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"')
ks1322
  • 1,646
  • 15
  • 26
2

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
ali b
  • 242
  • 1
  • 3
  • 10
  • 3
    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 '21 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 ` 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 '21 at 21:07
1

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).

l0b0
  • 50,672
  • 41
  • 197
  • 360
  • 10
    It prints only the first layout in the list, not the current one. – sastanin Dec 19 '12 at 08: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 06 '16 at 16:29
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.

Matthias Braun
  • 7,797
  • 7
  • 45
  • 54
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
Senderman
  • 1
  • 1
-1

You can use:

setxkbmap -print | grep xkb_symbols
nozimica
  • 874
  • 8
  • 24
  • 7
    it returns overall keyboard settings, not current layout (us _or_ ru) – Andrew Apr 28 '11 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 '11 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 '11 at 16:33