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.

  • So basically, what you need is a shortcut to toggle between two languages? – Jacob Vlijm Jan 13 '17 at 22:49
  • Possible duplicate of Keyboard shortcuts for each input language – Gunnar Hjalmarsson Jan 13 '17 at 23:04
  • @GunnarHjalmarsson close, but not exactly. OP wants one shortcut to toggle, not multiple to control multiple languages. – Jacob Vlijm Jan 13 '17 at 23:27
  • 1
    @JacobVlijm: True. I thought it was close enough, but now I see that you wrote an answer which provides exactly what the OP asked for. – Gunnar Hjalmarsson Jan 13 '17 at 23:44
  • @GunnarHjalmarsson Thanks for mentioning! – Jacob Vlijm Jan 13 '17 at 23:45
up vote 6 down vote accepted

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.

  • 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 0: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: gist.github.com/vzaliva/63cb29b100e9d24f3070c2b78c98d6e4 – krokodil Jan 14 '17 at 0:57
  • Hi @krokodil the only downside of the linked version is that it uses /dev/shm (tmpfs): 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 9: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

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.

  • 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 2 at 8:49

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.