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

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

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

介绍

下面的脚本根据语言菜单中该语言的位置为每个用户定义的程序设置语言。 例如,如果我的订单是:英语(1),中文(2)和俄语(3),我可以将Firefox设置为语言2,终端设置语言1,LibreOffice设置语言3。

该脚本分为两部分:第一部分是执行作业的实际脚本,第二部分脚本用作控制元素。 我们的想法是将语言设置脚本作为启动应用程序运行,并且只要您需要手动更改语言 – 双击控制器脚本的快捷方式。

先决条件

  1. 使用sudo apt-get install wmctrl安装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使两个脚本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

说明和定制:

脚本本身在无限循环中运行并检查当前活动窗口。 如果当前活动窗口与案例结构中的某个选项匹配,我们将切换到相应的语言。 为了避免常量设置,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添加两个条目。 接下来在案例结构中添加适当的条目。

例如,如果我想添加LibreOffice的Writer,我打开LibreOffice Writer窗口,转到终端并运行wmctrl -lx 。 它会告诉我Writer窗口有类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结构中单个圆括号之前的东西)就是使用这个xpropawk oneliner: xprop | awk '/WM_CLASS/ {gsub(/"/," "); print $3"."$5} xprop | awk '/WM_CLASS/ {gsub(/"/," "); print $3"."$5}

您可以通过运行安装gxneur

 sudo apt-get install gxneur 

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

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

你可以做你想要的。 为特定应用程序设置特定布局。

下面的脚本是这个版本的编辑版本,不久之前作为单个应用程序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. 如果一切正常,请将其添加到“启动应用程序:添加到启动应用程序:虚拟>启动应用程序>添加”。 添加命令:

     python3 /path/to/set_language.py