Назначить язык клавиатуры по умолчанию для каждого приложения

11

Можно ли назначить язык клавиатуры по умолчанию для конкретных приложений? Я знаю, что есть возможность всегда запускать приложение с языком клавиатуры по умолчанию, но это не то, что я хочу.

Я ищу что-то похожее на «фиксированные рабочие пространства», которые вы можете установить с помощью CompizConfig (вы устанавливаете Chrome всегда открывающимся в X1Y1, терминалом в X2Y1 и т. Д.). Что-то, где я бы установил Chrome: чешский, терминал: английский, Spotify: английский, ...

grongor
источник
В «Ввод текста» есть опция «Разрешить разные источники для каждого окна». Возможно, шаг в правильном направлении для вас.
Гуннар Хьялмарссон
Да, спасибо, я знаю об этом. Это необходимый шаг, я бы сказал, но, к сожалению, это не то, чего я хочу достичь. Спасибо, в любом случае.
Гронгор
Есть сценарий. Вам нужны только эти 3 приложения или есть другие? В зависимости от того, насколько гибким вы хотите, чтобы сценарий был, мне может потребоваться больше или меньше времени, чтобы написать его
Сергей Колодяжный
@JacobVlijm Похоже, еще одна хорошая работа для питона;)
Сергей Колодяжный,
Написал ответ. Дайте мне знать, что вы думаете
Сергей Колодяжный

Ответы:

6

Вступление

Сценарий ниже устанавливает язык для каждой пользовательской программы в соответствии с положением этого языка в языковом меню. Например, если мой порядок: английский (1), китайский (2) и русский (3), я могу установить для Firefox язык 2, для терминала язык 1, а для LibreOffice язык 3.

Сценарий состоит из двух частей: первая часть представляет собой фактический сценарий, выполняющий эту работу, а второй сценарий выполняет роль управляющего элемента. Идея состоит в том, чтобы запустить сценарий языковых настроек в качестве запускаемого приложения, и всякий раз, когда вам нужно вручную изменить язык - дважды щелкните ярлык на сценарии контроллера.

Предпосылки

  1. Установите wmctrlпрограмму с помощью sudo apt-get install wmctrl.

скрипт

#!/bin/sh
# Author: Serg Kolo
# Date: August 4, 2015
# Description: This script forces assigned input languages
#              for specific windows
# Version:2

# Use this part to set programs and their respective languages
# PROG_CLASS or a running window can be found with the
# wmctrl -lx command
# If you want to add another program to the list, 
# follow the template PROG_CLASS_num=window.Class
# and bellow that $LANGnum=num


PROG_CLASS_1=gedit.Gedit
LANG1=2

PROG_CLASS_2=gnome-terminal-server.Gnome-terminal
LANG2=0

PROG_CLASS_3=Navigator.Firefox
LANG3=1


# While loop below gets the job done. 
# If you need to send languages for more programs -  copy  
# the first entry and replace  $PROG_CLASS_1 with $PROG_CLASS_num
# where num is respective number of a program
# Replace $LANGnum with the respective language number. After the "="
# post positional number of the language you want to use. 
# Remember the count starts from 0

while [ 1 ];do
  WM_CLASS=$(wmctrl -lx | awk -v search=$(printf %x $(xdotool getactivewindow)) '{ if($1~search) print $3 }' )
  CURRENT=$(gsettings get org.gnome.desktop.input-sources current| awk '{print $2}')
    case  $WM_CLASS in

      $PROG_CLASS_1)  
        if [ $CURRENT -ne  $LANG1 ];then
          gsettings set org.gnome.desktop.input-sources current $LANG1
        fi
      ;;

      $PROG_CLASS_2) 
        if [ $CURRENT -ne  $LANG2 ];then
          gsettings set org.gnome.desktop.input-sources current $LANG2
        fi  
      ;;

       $PROG_CLASS_3) 
         if [ $CURRENT -ne  $LANG3 ];then
           gsettings set org.gnome.desktop.input-sources current $LANG3
         fi  
        ;;
    esac

    sleep 0.250

done

Скрипт контроллера

#!/bin/sh
# set -x
# Author: Serg Kolo
# Date: August 8, 2015
# Description: Controller script for set-lang.sh script
# Allows pausing and resuming execution of set-lang.sh
STATUS=$(ps -o stat -p $(pgrep -o  set-lang.sh) | awk '{getline;print }')

case $STATUS in
    T) kill -CONT $(pgrep set-lang.sh) 
       notify-send 'RESUMED'
    ;;

    S) kill -STOP $(pgrep set-lang.sh)
       notify-send 'STOPED'
    ;;

    *) exit ;;
esac 

Файл запуска (.desktop) для скрипта set-lang.sh

[Desktop Entry]
Name=set-lang.sh
Comment=Script to set languages
Exec=/home/yourusername/bin/set-lang.sh
Type=Application
StartupNotify=true
Terminal=false

Файл запуска (.desktop) для set-lang-controller.sh

[Desktop Entry]
Name=lang-control
Comment=Shortcut to controlling script
Exec=/home/yourusername/bin/set-lang-control.sh
Type=Application
StartupNotify=true
Terminal=false

Заставить скрипт работать

  1. Создайте папку в вашем домашнем каталоге с именем bin. Вы можете сделать это в файловом менеджере или использовать команду mkdir $HOME/binв терминале
  2. В binпапке создайте два файла: set-lang.shи set-lang-control.sh. Сохранить скрипт в set-lang.shи контроллер скрипт в set-lang-control.sh. Сделайте оба скрипта исполняемыми сsudo chmod +x $HOME/bin/set-lang-control.sh $HOME/bin/set-lang.sh
  3. Создайте два .desktopфайла. Один есть set-lang.desktop. Должен быть размещен в скрытом .config/autostartкаталоге. Второй set-lang-controller.desktop, может быть помещен в вашу binпапку. Затем перетащите и запустите set-lang-controller.desktopфайл запуска . Это станет ярлыком для временной остановки и возобновления выполнения скрипта.

Обратите внимание, что строка Exec=должна быть изменена, чтобы фактическое имя пользователя указывалось в пути к скрипту (потому что это фактический домашний каталог). Например, мой будетExec=/home/serg/bin/set-lang.sh

Объяснение и настройка:

Сам скрипт выполняется в бесконечном цикле while и проверяет текущее активное окно. Если текущее активное окно соответствует одному из параметров в структуре дела, мы переключаемся на соответствующий язык. Чтобы избежать установки констант, каждая часть структуры case имеет оператор if, который проверяет, задан ли для языка желаемое значение.

Двойной щелчок на панели запуска для set-lang-controller.shпроверки состоянияset-lang.sh скрипта; если скрипт запущен - он будет приостановлен, а если скрипт приостановлен, он будет возобновлен. Уведомление будет показано с соответствующим сообщением.

Чтобы настроить скрипт, вы можете открыть нужные приложения, запустить wmctrl -lxи отметить третий столбец - класс окна. Пример вывода:

$ wmctrl -lx | awk '$4="***" {print}'                                                                                                            
0x02c00007 0 gnome-terminal-server.Gnome-terminal *** Terminal
0x03a0000a 0 desktop_window.Nautilus *** Desktop
0x04a00002 0 N/A *** XdndCollectionWindowImp
0x04a00005 0 N/A *** unity-launcher
0x04a00008 0 N/A *** unity-panel
0x04a0000b 0 N/A *** unity-dash
0x04a0000c 0 N/A *** Hud
0x012000a6 0 Navigator.Firefox *** unity - Assign default keyboard language per-application - Ask Ubuntu - Mozilla Firefox

Выберите соответствующие классы окна для каждой программы. Затем перейдите к той части скрипта, которая позволяет выполнить настройку, и добавьте две записи для PROG_CLASS и LANG. Затем добавьте соответствующую запись в структуру дела.

Например, если я хочу добавить Writer LibreOffice, я открываю окно Writer LibreOffice, перехожу в терминал и запускаю wmctrl -lx. Это скажет мне, что у окна Writer есть класс libreoffice.libreoffice-writer. Далее я пойду к сценарию, добавлю PROG_CLASS_4=libreoffice.libreoffice-writerи LANG4=3в соответствующую область. Обратите внимание на совпадение с номером 4. Затем перейдите к структуре дела и добавьте следующую запись между last ;;и esac:

$PROG_CLASS_4) 
  if [ $CURRENT -ne  $LANG4 ];then
    gsettings set org.gnome.desktop.input-sources current $LANG4
  fi  
;;

Опять же, обратите внимание на знак $ и соответствующий номер 4.

Кроме того, если скрипт работает как элемент автозапуска, и вы хотите временно остановить его, чтобы настроить его, используйте pkill set-lang.shи возобновите сnohup set-lang.sh > /dev/null 2&>1 &

Небольшое примечание: еще один способ выяснить класс окна для программы (то, что идет перед одинарной круглой скобкой в ​​структуре case) - использовать это xpropи awkoneliner:xprop | awk '/WM_CLASS/ {gsub(/"/," "); print $3"."$5}

Сергей Колодяжный
источник
Спасибо, это довольно хорошее начало. Единственная (но главная) проблема в том, что я не смогу переключать язык в этих приложениях. Скрипт будет просто переопределять мои настройки все время. Я хотел бы иметь возможность переключать язык в этих окнах тоже. Так что, может быть, добавить проверку pid приложения и форсировать язык только в первый раз или что-то в этом роде?
Гронгор
Я также предпочел бы, чтобы этот сценарий был основан на событиях, а не на циклах. Это не имеет большого значения, но я был бы очень признателен, если бы вы могли предоставить небольшой практический совет, чтобы это работало с dbus или чем-то еще (если это возможно).
Гронгор
@GRoNGoR, поэтому я немного подумал об этом, и до сих пор я не вижу способа приостановить выполнение сценария, кроме как kill -STOP $(pgrep set-lang.sh)затем возобновить выполнение сценария kill -CONT $(pgrep set-lang.sh). Таким образом, вы можете приостановить его, переключить языки в обычном режиме, а затем возобновить.
Сергей Колодяжный
Я быстро подумал, что, возможно, с помощью сочетания клавиш для двух команд это можно сделать, но я еще не проверял, пока только теория. Завтра буду тестировать, как только я высплюсь и доложу об этом :). Дайте мне знать, если это будет приемлемой идеей
Сергей Колодяжный
1
+1 за большую и тщательную работу! Две крошечные вещи, которые я хотел бы упомянуть: исполняемым ~/binфайлам не нужен ни путь (ни расширение), поскольку он находится $PATHпосле повторного входа в систему, см. Lintian.debian.org/tags/script-with-language-extension .html ), и вы можете объединить остановки / запуска в одном .desktopфайле; либо в быстром списке или функции переключения. выглядит довольно идеально для меня.
Джейкоб Влейм
1

Вы можете установить gxneurдля этого, запустив

sudo apt-get install gxneur

Это программное обеспечение может автоматически переключать макеты, но оно не идеально с этим.

Но у него есть очень хорошие инструменты для настройки ручных переключателей макета.

Вы можете делать именно то, что вы хотите. Чтобы установить конкретные макеты для конкретных приложений.

Pilot6
источник
0

Сценарий ниже является отредактированной версией этого , которая была опубликована как похожее решение для одного приложения (gnome-terminal ) некоторое время назад.

Сценарий был частично переписан для этого вопроса, чтобы можно было использовать его для автоматической настройки языков для нескольких приложений.

Как использовать на практике; автоматически запоминать установленный язык для приложения

Если скрипт запускается в первый раз, текущий язык считается языком по умолчанию, который запоминается в скрытом файле: ~/.lang_set .

Тогда использование простое: если вы запускаете, например, geditв самом переднем окне и устанавливаете другой язык, geditс этого момента этот язык автоматически подключается , пока вы не измените язык снова с помощьюgedit впереди.

Количество конкретных языков / приложений в принципе не ограничено; просто запустите приложение и установите язык с окном приложения впереди. Приложение будет автоматически установлено и запомнено без редактирования кода.

Событие управляемое?

Хотя скрипт выполняется в цикле, потребление ресурсов минимально. Событие управляемое будет означать, что событие - это изменение в переднем окне. Я не вижу другого выбора, кроме как «шпионить» за самым передним окном, кроме проверки в цикле.

Сценарий

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

key = [
    "org.gnome.desktop.input-sources",
    "gsettings get ", "gsettings set ",
    " sources", " current",
    ]

prev = os.environ["HOME"]+"/.lang_set"

def get(cmd):
    return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")

def get_front():
    # produce the frontmost application
    try:
        focus = str(hex(int(get("xdotool getwindowfocus").strip())))
        front = focus[:2]+"0"+focus[2:]
        cmd = "wmctrl -lp"
        w_list = subprocess.check_output(["/bin/bash", "-c",cmd]).decode("utf-8")
        w_match = [w for w in w_list.splitlines() if front in w][0].split()[2]
        application = get("ps -p "+w_match+" -o comm=").strip()
        # fix for 15.04, where the process name of gnome-terminal varies
        application = "gnome-terminal" if "gnome-terminal" in application else application
        return application
    except subprocess.CalledProcessError:
        return None

def get_lang():
    # get the currently running language (output = string)
    curr_n = int(get(key[1]+key[0]+key[4]).strip().split()[-1])
    return str(eval(get(key[1]+key[0]+key[3]))[curr_n])

def read_prev(application):
    # reads the possibly set languages for general and specific use (list)
    if not os.path.exists(prev):
        currlang = get_lang()
        open(prev, "wt").write("default "+currlang+"\n"+application+" "+currlang)
        return [currlang, currlang]
    else:
        return [l.strip() for l in open(prev).readlines()]

def write_changed(application, lang):
    changelist = read_prev(front_2)
    try:
        match = changelist.index([l for l in changelist if application in l][0])
        changelist[match] = application+" "+lang+"\n"
    except IndexError:
        changelist.append(application+" "+lang+"\n")
    open(prev, "wt").write(("\n").join(changelist))

def set_lang(lang):
    # set the currently used language (input = string)
    lang_i = eval(get(key[1]+key[0]+key[3])).index(eval(lang))  
    cmd = key[2]+key[0]+key[4]+" "+str(lang_i)
    subprocess.Popen(["/bin/bash", "-c", cmd])

front_1 = get_front(); lang_1 = get_lang()

while True:
    time.sleep(1)
    front_2 = get_front(); lang_2 = get_lang()
    if front_2 != None:
        if front_2 != front_1:
            try:
                setlist = read_prev(front_2)
                match = [l for l in setlist if front_2 in l][0]
            except IndexError:
                match = [l for l in setlist if "default" in l][0]
                set_lang(match[match.find(" ")+1:])            
        elif lang_2 != lang_1:
            write_changed(front_2, lang_2)
    front_1 = front_2; lang_1 = lang_2

Как настроить

  1. Скрипт использует xdotoolи wmctrl:

    sudo apt-get install wmctrl xdotool
    
  2. Скопируйте приведенный выше скрипт в пустой файл, сохраните его как set_language.py

  3. Протестируйте его командой:

    python3 /path/to/set_language.py
    
  4. Если все работает должным образом, добавьте его в «Автозагрузка приложений»: «Добавить в автозагрузку приложений»: «Тире»> «Автозагрузка приложений»> «Добавить». Добавьте команду:

    python3 /path/to/set_language.py
    
Якоб Влейм
источник
Один размер подходит всем! +1
Fabby
Привет большое спасибо за это, я скоро посмотрю на это и
сообщу,