为每个应用程序分配默认键盘语言


11

是否可以为特定应用程序指定默认键盘语言?我知道有一个选项可以始终使用默认键盘语言启动应用程序,但这不是我想要的。

我正在寻找类似于“固定工作区”的东西,可以使用CompizConfig进行设置(将Chrome设置为始终在X1Y1处打开,在X2Y1处打开终端等)。我要设置Chrome的地方:捷克语,终端:英语,Spotify:英语,...


在“文本输入”中,有“为每个窗口允许不同的源”选项。可能是朝着正确方向迈出的一步。
2015年

是的,谢谢,我知道这一点。这是我要说的必要步骤,但是不幸的是,这并不是我想要实现的。不管怎么说,还是要谢谢你。
grongor

有一种脚本编写方式。您仅需要这3个应用程序,还是其他?根据您希望脚本的灵活程度,可能会花费我更多或更少的时间来编写脚本
Sergiy Kolodyazhnyy 2015年

@JacobVlijm听起来像是python的另一项好工作;)
Sergiy Kolodyazhnyy 2015年

发表答案。让我知道您的想法
Sergiy Kolodyazhnyy 2015年

Answers:


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 

set-lang.sh脚本的启动器(.desktop)文件

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

set-lang-controller.sh的启动器(.desktop)文件

[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.shset-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循环中运行,并检查当前活动窗口。如果当前活动窗口与案例结构中的选项之一匹配,我们将切换到适当的语言。为了避免不断进行设置,案例结构的每个部分都有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添加两个条目。接下来,在案例结构中添加适当的条目。

例如,如果要添加LibreOffice Writer,则打开LibreOffice Writer窗口,转到终端并运行wmctrl -lx。它会告诉我Writer窗口具有class libreoffice.libreoffice-writer。接下来,我将转到脚本,在适当的区域中添加PROG_CLASS_4=libreoffice.libreoffice-writerLANG4=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结构中位于单个圆括号之前的内容)是使用this xpropawkoneliner:xprop | awk '/WM_CLASS/ {gsub(/"/," "); print $3"."$5}


谢谢,这是一个很好的开始。唯一(但很主要)的问题是我将无法在那些应用程序中切换语言。该脚本将始终覆盖我的设置。我也希望能够在这些窗口中切换语言。因此,也许只在第一次时添加一些对应用程序pid的检查并强制使用语言?
grongor

我还希望该脚本是事件驱动的,而不是基于循环的。没什么大不了的,但是如果您能提供一个小方法来使它与dbus或其他东西一起工作(如果可能),我将不胜感激。
grongor

@GRoNGoR,所以我已经考虑了一下,到目前为止,我没有看到一种方法来暂停脚本,除非kill -STOP $(pgrep set-lang.sh)再用来恢复脚本kill -CONT $(pgrep set-lang.sh)。这样,您可以暂停它,正常切换语言,然后继续。
Sergiy Kolodyazhnyy

我很快想到,也许对这两个命令使用键盘快捷键可能是实现此目的的方法,但是到目前为止,我还没有测试过它,只是一种理论。明天我将有足够的睡眠
后再

1
+1为伟大而彻底的工作!我想提两件事:可执行文件~/bin不需要路径(也不需要扩展名,因为它是$PATH重新登录后进入的,请参见:lintian.debian.org/tags/script-with-language-extension .html),则可以将停止/启动合并到一个.desktop文件中;在快速列表或切换功能中。对我来说看起来很完美。
Jacob Vlijm

1

您可以gxneur通过运行安装

sudo apt-get install gxneur

该软件可以自动切换布局,但并不完美。

但是它有很好的工具来设置手动布局开关。

您可以完全按照自己的意愿做。为特定的应用程序设置特定的布局。


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. 该脚本同时使用xdotoolwmctrl

    sudo apt-get install wmctrl xdotool
    
  2. 将上面的脚本复制到一个空文件中,另存为 set_language.py

  3. 通过以下命令进行测试:

    python3 /path/to/set_language.py
    
  4. 如果所有功能均按预期工作,则将其添加到“启动应用程序”:添加到“启动应用程序”:Dash>“启动应用程序”>“添加”。添加命令:

    python3 /path/to/set_language.py
    

一种尺寸适合所有人!+1
Fabby 2015年

嘿,非常感谢您,我会尽快调查一下,让您知道我的想法:)
grongor 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.