Asignar idioma de teclado predeterminado por aplicación

11

¿Es posible asignar el idioma predeterminado del teclado para aplicaciones específicas? Sé que hay una opción para iniciar siempre una aplicación con un idioma de teclado predeterminado, pero esto no es lo que quiero.

Estoy buscando algo similar a los "espacios de trabajo fijos" que puede configurar con CompizConfig (configura Chrome para que siempre se abra en X1Y1, terminal en X2Y1, etc.). Algo donde configuraría Chrome: checo, terminal: inglés, Spotify: inglés, ...

grongor
fuente
En "Entrada de texto" existe la opción "Permitir diferentes fuentes para cada ventana". Posiblemente un paso en la dirección correcta para usted.
Gunnar Hjalmarsson
Sí, gracias, lo sé. Este es el paso necesario, diría, pero desafortunadamente no es lo que quiero lograr. Gracias de cualquier manera.
grongor
Hay una forma de script. ¿Solo necesitas esas 3 aplicaciones o hay otras? Dependiendo de cuán flexible desee que sea el guión, podría llevarme más o menos tiempo escribirlo
Sergiy Kolodyazhnyy
@JacobVlijm Suena como otro buen trabajo para python;)
Sergiy Kolodyazhnyy
Publicado una respuesta. Déjame saber lo que piensas
Sergiy Kolodyazhnyy

Respuestas:

6

Introducción

El siguiente script establece el idioma para cada programa definido por el usuario, de acuerdo con la posición de ese idioma en el menú de idiomas. Por ejemplo, si mi pedido es: inglés (1), chino (2) y ruso (3), puedo configurar Firefox para que tenga el idioma 2, terminal para que tenga el idioma 1 y LibreOffice para que tenga el idioma 3.

El guión viene en dos partes: la primera parte es el guión real que hace el trabajo, el segundo guión sirve como elemento de control. La idea es ejecutar el script de configuración de idioma como una aplicación de inicio y siempre que necesite cambiar el idioma manualmente, haga doble clic en el acceso directo al script del controlador.

Prerrequisitos

  1. Instalar wmctrlprograma con sudo apt-get install wmctrl.

Guión

#!/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

Script de controlador

#!/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 

Archivo del iniciador (.desktop) para el script 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

Archivo del iniciador (.desktop) para 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

Hacer que el guión funcione

  1. Cree una carpeta en su directorio de inicio llamada bin. Puedes hacerlo en el administrador de archivos o usar el comando mkdir $HOME/binen la terminal
  2. En la bincarpeta cree dos archivos: set-lang.shy set-lang-control.sh. Guardar script en set-lang.shy script de controlador en set-lang-control.sh. Hacer que ambos scripts sean ejecutables consudo chmod +x $HOME/bin/set-lang-control.sh $HOME/bin/set-lang.sh
  3. Crea dos .desktoparchivos. Una de ellas es set-lang.desktop. Debe colocarse en el .config/autostartdirectorio oculto . El segundo es set-lang-controller.desktop, se puede colocar en su bincarpeta. A continuación, arrastre y fije al iniciador el set-lang-controller.desktoparchivo. Esto se convertirá en el acceso directo para detener y reanudar temporalmente la ejecución del script.

Tenga en cuenta que la línea Exec=debe modificarse para tener su nombre de usuario real en la ruta al script (porque ese es su directorio de inicio real). Por ejemplo, el mío seríaExec=/home/serg/bin/set-lang.sh

Explicación y personalización:

El script mismo se ejecuta en un ciclo while infinito y verifica la ventana activa actual. Si la ventana activa actual coincide con una de las opciones en la estructura del caso, cambiamos al idioma apropiado. Para evitar la configuración constante, cada parte de la estructura del caso tiene una declaración if que comprueba si el idioma ya se ha establecido en el valor deseado.

El doble clic en el iniciador para set-lang-controller.shverificará el estado del set-lang.shscript; si el script se está ejecutando, se pausará, y si el script está en pausa, se reanudará. Se mostrará una notificación con el mensaje correspondiente.

Para personalizar el script, puede abrir las aplicaciones deseadas, ejecutar wmctrl -lxy anotar la tercera columna: la clase de ventana. Salida de muestra:

$ 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

Seleccione las clases de ventana apropiadas para cada programa. A continuación, vaya a la parte del script que permite la personalización y agregue dos entradas para PROG_CLASS y LANG. A continuación, agregue la entrada apropiada en la estructura del caso.

Por ejemplo, si quiero agregar el Escritor de LibreOffice, abro la ventana del Escritor de LibreOffice, voy a la terminal y ejecuto wmctrl -lx. Me dirá que la ventana del escritor tiene clase libreoffice.libreoffice-writer. A continuación, iré al script, agregar PROG_CLASS_4=libreoffice.libreoffice-writery LANG4=3en el área correspondiente. Observe el número correspondiente 4. A continuación, vaya a la estructura del caso y agregue la siguiente entrada entre last ;;y esac:

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

Nuevamente, observe el signo $ y el número coincidente 4.

Además, si el script se ejecuta como un elemento de inicio automático y desea detenerlo temporalmente para personalizarlo, use pkill set-lang.shy reanude connohup set-lang.sh > /dev/null 2&>1 &

Pequeña nota: otra forma de averiguar la clase de ventana para un programa (esas cosas que van antes de un paréntesis redondo en la estructura del caso) es usar esto xpropy awkoneliner:xprop | awk '/WM_CLASS/ {gsub(/"/," "); print $3"."$5}

Sergiy Kolodyazhnyy
fuente
Gracias, este es un muy buen comienzo. El único (pero importante) problema es que no podré cambiar el idioma en esas aplicaciones. El script simplemente anulará mi configuración todo el tiempo. Me gustaría poder cambiar el idioma en esas ventanas también. Entonces, ¿tal vez agregar alguna comprobación para el pid de la aplicación y forzar el lenguaje solo la primera vez o algo así?
grongor
También preferiría que este script esté basado en eventos, no basado en bucles. No es un gran problema, pero realmente agradecería si pudieras proporcionar un pequeño procedimiento para que esto funcione con dbus o algo así (si es posible).
grongor
@GRoNGoR, así que lo he pensado un poco, y hasta ahora no veo una manera de pausar el script, excepto kill -STOP $(pgrep set-lang.sh)y luego reanudar el script con kill -CONT $(pgrep set-lang.sh). De esa manera puede pausarlo, cambiar de idioma normalmente y luego reanudarlo.
Sergiy Kolodyazhnyy
Un pensamiento rápido que tuve es que quizás usar un atajo de teclado para los dos comandos podría ser la forma de hacerlo, pero aún no lo he probado, solo una teoría hasta ahora. Lo probaré mañana una vez que duerma lo suficiente y me informe :) Hágame saber si esta sería una idea aceptable
Sergiy Kolodyazhnyy
1
¡+1 por el excelente y minucioso trabajo! Dos pequeñas cosas que me gustaría mencionar: los ejecutables ~/binno necesitan la ruta (ni la extensión, ya que está $PATHdespués de un reinicio de sesión, consulte: lintian.debian.org/tags/script-with-language-extension .html ), y podría combinar detener / iniciar en un .desktoparchivo; ya sea en una lista rápida o una función de alternar. Se ve bastante perfecto para mí.
Jacob Vlijm el
1

Puede instalar gxneurpara eso ejecutando

sudo apt-get install gxneur

Este software puede cambiar automáticamente los diseños, pero no es perfecto con eso.

Pero tiene herramientas muy buenas para configurar interruptores de diseño manual.

Puedes hacer exactamente lo que quieras. Para establecer diseños específicos para aplicaciones específicas.

Piloto6
fuente
0

La secuencia de comandos a continuación es una versión editada de esta , que se publicó como una solución similar para una sola aplicación ( gnome-terminal) hace un tiempo.

El guión fue reescrito parcialmente para esta pregunta, para poder usarlo para configurar automáticamente los idiomas para múltiples aplicaciones.

Cómo usar en la práctica; recuerda automáticamente establecer idioma por aplicación

Si se inicia el guión por primera vez, el idioma actual se supone que es el idioma por defecto, que se recuerda en un archivo oculto: ~/.lang_set.

Entonces, el uso es simple: si ejecuta, por ejemplo, gediten la ventana más frontal y establece un idioma diferente, ese idioma se conecta automáticamente a geditpartir de ese momento, hasta que cambie el idioma nuevamente gediten frente.

El número de idiomas / aplicaciones específicos es, en principio, ilimitado; simplemente ejecute la aplicación y configure el idioma con la ventana de la aplicación al frente. La aplicación se configurará y recordará automáticamente sin editar el código.

¿Evento conducido?

Aunque el script se ejecuta en un bucle, el consumo de recursos es mínimo. Evento dirigido significaría que el evento es un cambio en la ventana frontal. No veo otra opción que "espiar" para la ventana más frontal que comprobar en un bucle.

La secuencia de comandos

#!/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

Como instalar

  1. El script usa ambos xdotooly wmctrl:

    sudo apt-get install wmctrl xdotool
    
  2. Copie el script anterior en un archivo vacío, guárdelo como set_language.py

  3. Pruébalo con el comando:

    python3 /path/to/set_language.py
    
  4. Si todo funciona como se esperaba, agréguelo a Aplicaciones de inicio: Agregar a Aplicaciones de inicio: Tablero> Aplicaciones de inicio> Agregar. Agrega el comando:

    python3 /path/to/set_language.py
    
Jacob Vlijm
fuente
¡Una talla para todos! +1
Fabby
Hola, muchas gracias por esto, lo investigaré pronto y les haré saber cómo me siento al respecto :)
grongor