Wednesday, February 6, 2019

Switching between 3 languages with i3

I type in 3 languages: English, Ukrainian, and Russian. It turns out, I never have to switch directly between Russian and Ukrainian. However, when typing in either Russian or Ukrainian I often switch to English to type email addresses, URLs, Unix commands, etc. In such scenario using standard X11 keyboard switching mechanism with setxkbmap specifying all 3 languages is impractical. It cycles through them sequentially! For comparison, MacOS handles this situation nicely with cycling only through the last 2 most recently used keyboard layouts. I already posted a solution for standard Ubuntu window manager, but now I wanted to make it work with i3 window manager.

The idea is to have two typing models "us/ru" and "us/ua". You can switch between them using a key combination. Within each mode, you can switch between the languages using Alt+SPACE (or another key).

First, download this script and copy it into your ~/bin/ directory. Then add the following 3 lines to your ~/.config/i3/config:

bindsym Mod1+space exec "xkb-switch -n; pkill -x --signal=SIGUSR1 i3status"

exec_always "setxkbmap -layout us,ru -variant ,mac"

bindsym $mod+z exec "~/bin/ /dev/shm/kbd2.txt 'setxkbmap -layout us,ru -variant ,mac' 'setxkbmap -layout us,ua' ; pkill -x --signal=SIGUSR1 i3status"

This is assuming you are using i3status keyboard indication method described in my previous post. Using it will also get the instant status bar update of the current keyboard languages. If you do not use i3status or do not need keyboard indicator you can use the following 2 lines instead:

exec_always "setxkbmap -layout us,ru -option grp:alt_space_toggle 

bindsym $mod+z exec "~/bin/ /dev/shm/kbd2.txt 'setxkbmap -layout us,ru -variant ,mac -option grp:alt_space_toggle' 'setxkbmap -layout us,ua -option grp:alt_space_toggle'

Now you can use WindowsKey+Z to switch between "us/ua" and "us/ru" modes and Alt+SPACE to switch between en and either ru or ua layouts.

Keyboard layout indicator for i3 with i3status

I am using i3 window manager with i3status bar. This post describes how to set up a responsive keyboard layout indicator if you are using multiple keyboard layouts. It looks like this:

In the screenshot above it shows that I have 2 keyboard layouts: American English (us) and Ukrainian (ua) and currently the first one is active.

Display part is implemented by this script. It depends on xkblayout-state utility. Save this script and compiled version of xkblayout-state to your ~/bin/ directory.

In your ~/.config/i3status/config add "output_format = i3bar" line to general section:

general {
        colors = true
        interval = 5
        output_format = i3bar        

In ~/.config/i3/config add:

bar {
    status_command ~/bin/
    output primary
    tray_output primary


exec_always "setxkbmap -layout us,ua -option 'grp:alt_space_toggle'"

This will allow you to switch keyboard with Alt+SPACE, and the indicator will display the current status.

So far, so good, but the problem is that the status bar is updated every 5 seconds. We would want keyboard layout indicator to update immediately. This could be done. It will require another command line utility: xkb-switch (available via apt on Ubuntu Linux). The idea is to implement switching via i3 hotkey, which will also trigger an instant status bar update. Here is  a section of i3 config:

exec_always "setxkbmap -layout us,ua"

bindsym Mod1+space exec "xkb-switch -n; pkill -x --signal=SIGUSR1 i3status"

We removed ALT+SPACE toggle option from setxkbmap, and implemented it as bindsym. Sending USR1 signal to i3status triggers the immediate update.