8

I have 3 input sources (languages) configured in Text Input Settings. Let us call them E (as in English) and A and B for two other languages. Mainly I switching between English and A or English and B and almost never between A and B. However switching keyboard shortcuts always cycle them in E->A->B or E<-A<-B direction. This is very inconvenient.

I am looking for a way to do this as it is implemented under MacOS, where switcher cycles between the 2 last languages by default, but you can force it to advance to 3rd one using a separate shortcut or via toolbar menu, as shown in the screenshot below:

enter image description here

Is it possible to configure something like this on Ubuntu?

EDIT: Jacob's solution below allows to create a custom shortcut to switch between two languages. I've modified his script to replicate MacOS switching scheme, where last 2 languages are cycles automatically. You can see it here. Blog post explaining details here.

krokodil
  • 253

3 Answers3

6

1. Toggle between two (fixed) languages

What you describe is basically a keyboard shortcut to toggle between two input languages. The script below will offer the option.

#!/usr/bin/env python3
import subprocess
import sys

args = sys.argv[1:]
k = ["org.gnome.desktop.input-sources", "current"]

def get(command):  return subprocess.check_output(command).decode("utf-8")

currlang = get(["gsettings", "get", k[0], k[1]]).strip().split()[-1]
newlang = args[1] if currlang == args[0] else args[0]
subprocess.Popen(["gsettings", "set", k[0], k[1], newlang])

How to use

  1. Copy the script into an empty file, save it as set_lang.py
  2. In a terminal window, run the command:

    gsettings get org.gnome.desktop.input-sources sources
    

    This will output like:

    [('xkb', 'us+intl'), ('xkb', 'us'), ('xkb', 'nl')]
    

    This list represents your input languages. The index of the languages is equal to the position in the list, starting with 0, e.g. ('xkb', 'us') has index 1 (in my case).

  3. Now test-run the script to toggle between two indexes. To toggle between ('xkb', 'us+intl') and ('xkb', 'nl') (index 0 and 2):

    python3 /path/to/set_lang.py 1 3
    

    where bot languages are represented by the arguments

    1 3
    
  4. If all works fine, add it to a shortut key: choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:

    python3 /path/to/set_lang.py 1 3
    

    to a shortcut of your choice.

You can then use the existing shortcut to browse all languages, or (of course) the menu.

Short explanation

  • The available languages can be retrieved by the command:

    gsettings get org.gnome.desktop.input-sources sources
    
  • The currently set language can be retrieved by the command:

    gsettings get org.gnome.desktop.input-sources current
    

    which will output (a.o.) the index of the currently set language.

  • We can set the language by (e.g.) the command:

    gsettings set org.gnome.desktop.input-sources current 0
    

    to set the language to the first in the list (index 0)

In short: if we run the script we two languages (indices) as arguments, the script will look what is the current index, will switch to the other one.




2. Toggle between the two last used languages

The version of the script below will switch between the two last used languages, which turned out to be similar to the behaviour of MacOs.

#!/usr/bin/env python3
import subprocess
import os

k = ["org.gnome.desktop.input-sources", "current"]
stored = os.path.join(os.environ["HOME"], ".lastlang")

def get(command):  return subprocess.check_output(command).decode("utf-8")

currlang = get(["gsettings", "get", k[0], k[1]]).strip().split()[-1]
try:
    newlang = open(stored).read().strip()
except FileNotFoundError:
    newlang = currlang

open(stored, "wt").write(currlang)
subprocess.Popen(["gsettings", "set", k[0], k[1], newlang])

I added this version as an additional option. The two last used languages will persist (be remembered) after reboot.

How to use

  1. Copy the script into an empty file, save it as switchlang.py
  2. Test- run the script by the command:

    python3/ path/to/switchlang.py
    

    After first run, switch language from the menu, now run

    python3/ path/to/switchlang.py
    

    again. From then on, the script will always toggle between the last two used languages.

Jacob Vlijm
  • 83,767
  • Thanks for the script! I am about to try it. I tried commands from your explanation and last one does not work. You missed 'current' before 0 – krokodil Jan 13 '17 at 23:49
  • @krokodil ah, you are right! Thanks. Luckily the script includes it :) (edited) – Jacob Vlijm Jan 14 '17 at 00:24
  • Thanks for your script. It is almost what I asked. I have to tweak it a bit to reproduce MacOS behaviour I am after. Here is my version: https://gist.github.com/vzaliva/63cb29b100e9d24f3070c2b78c98d6e4 – krokodil Jan 14 '17 at 00:57
  • Hi @krokodil the only downside of the linked version is that it uses /dev/shm (tmpfs): https://www.cyberciti.biz/tips/what-is-devshm-and-its-practical-usage.html, which will not persist after reboot; it uses virtual memory (I tried and indeed it doesn't). I therefore added the version in the edited answer. – Jacob Vlijm Jan 14 '17 at 09:56
  • thanks. I intentionally used shm as I think this setting should not persist during reboot. I also wanted to keep it all in memory to avoid even a chance of spinning disks. It now occured to me that I might as well use ENV to store last state. I am going to test this theory. Also, I think in my script error handling is better. It will still switch language even if it could not write, and it will default to language 0 if it could not read. I – krokodil Jan 14 '17 at 17:19
  • @krokodil I see, but why would you default to 0, and not persist? Anyway, always nice if the next user can pick whatever he or she likes. Now three options. Thanks!. – Jacob Vlijm Jan 14 '17 at 17:24
  • +1 for the idea and the script. Instead of invoking the gsettings program you could also access GSettings through the GIO bindings in Python. See https://askubuntu.com/questions/85162/how-can-i-change-the-wallpaper-using-a-python-script for an example. – David Foerster Jan 17 '17 at 06:55
  • @DavidFoerster Thanks! I know, I believe Serg is using that usually. I prefer simply using subprocess though; it is much shorter and does not require additional imports (apart from subprocess of course :) ) – Jacob Vlijm Jan 17 '17 at 06:57
2

Go: >System Settings > Text Entry

  and add languages to "Input sources to use:"

enter image description here

make sure to check "Show current input source in menu bar" just select input sources from the drop down menu.

Thompson Dawes
  • 695
  • 1
  • 6
  • 20
  • 1
    This is the most simplistic and helpful explanation for solving the issue I've found so far on AskUbuntu, using Ub 16.04. Thanks! – Denialos May 02 '18 at 08:49
0

In recent Ubuntu versions with the default GNOME desktop, it works exactly like that (at least in my case with Ctrl+Space shortcut). But in Unity desktop, it's still a problem...

The workaround for Unity is to use ibus switcher which provides the MRU-switching functionality out of the box. It is used by Unity and installed along with it by default usually. (If not, install it and set it at System Settings -> Language Support -> Keyboard input method system.)

You can configure it with ibus-setup gui (run from terminal):

  1. in the Advanced tab uncheck 'Use system keyboard layout';
  2. add your languages in the 'Input Method' tab;
  3. add your switching shortcut in the 'General' tab.

Now, delete the shortcuts in Unity's config at System Settings -> Text Entry and untick 'Show current input source in the menu bar' (it won't work with ibus switcher anyway).

Now you all set and it should work. If you could not find your language in ibus (like it happened to me with English (UK)) - you can manually add it easily, check the workaround here - https://bugs.launchpad.net/ubuntu/+source/ibus/+bug/1540587.

One more last thing: ibus has its own indicator, but it’s ugly and it does not show up in Unity’s menu bar anyway, so if you want to see the current language indicator – try gxkb. It will show a nice country flag of your current language. (You can add gxkb to Startup Applications to start automatically on login.)

NIMISHAN
  • 1,575
  • 4
  • 19
  • 28
Andriy
  • 59