我想知道是否有办法让一个动作根据其所在的工作区产生两种不同的效果。
例如:如果在工作区 1 上,则使用聚焦 Empathy 聊天列表的命令,但如果在工作区 2 上,则使用打开 Chrome 的命令。
它将与鼠标悬停在 Compiz 的屏幕右边缘相联系。
这可能吗?
答案1
看一下xdotool
.get_desktop
将输出视图中的当前桌面。
对于带有 Unity 的 Ubuntu ,工作区被称为viewports
并且以坐标形式呈现,x 和 y 位置位于左上角。
例如,
$ xdotool get_desktop_viewport
4780 0
您可以使用该信息来确定您所在的工作区,并针对每个工作区执行命令。
答案2
笔记:答案已用 Python 重写,以获得更好的性能,但没有 GUI 元素。请参阅部分Python 版本
Shell 脚本版本
介绍
下面的脚本允许根据当前活动的工作区运行特定命令。它旨在绑定到键盘快捷键。脚本运行的演示可在此处找到: https://www.youtube.com/watch?v=oxim3JbeiVM
获取脚本
从此帖子复制脚本源或通过以下步骤安装:
sudo apt-get install git
cd /opt ; sudo git clone https://github.com/SergKolo/sergrep.git
sudo chmod -R +x sergrep
该文件是/opt/sergrep/unity_viewport_commands.sh
使用方法和选项概述
该脚本具有以下标志:
-r
为当前视口运行命令-g
生成新的命令列表-h
打印帮助文本-v
查看当前设置-s
更改单个视口的设置
该脚本旨在与具有特定标志的键盘快捷键绑定。例如, Ctrl++Alt将I 绑定到unity_viewport_commands.sh -r
以调用命令。
要将脚本绑定到快捷方式,请参阅如何将 .sh 文件绑定到键盘组合?
脚本源
#!/usr/bin/env bash
#
###########################################################
# Author: Serg Kolo , contact: [email protected]
# Date: April 18th, 2016
# Purpose: Script that runs a command depending
# on the current viewport
# Written for: https://askubuntu.com/q/56367/295286
# Tested on: Ubuntu 14.04 , Unity 7.2.6
###########################################################
# Copyright: Serg Kolo , 2016
#
# Permission to use, copy, modify, and distribute this software is hereby granted
# without fee, provided that the copyright notice above and this permission statement
# appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
ARGV0="$0"
ARGC=$#
get_screen_geometry()
{
xwininfo -root | awk '/-geometry/{gsub(/+|x/," ");print $2,$3}'
}
gui_dialog()
{
SCHEMA="org.compiz.core:/org/compiz/profiles/unity/plugins/core/"
read swidth sdepth <<< "$(get_screen_geometry)"
vwidth=$(gsettings get $SCHEMA hsize)
vheight=$(gsettings get $SCHEMA vsize)
width=0
for horizontal in $(seq 1 $vwidth); do
height=0
for vertical in $(seq 1 $vheight); do
# array+=( FALSE )
viewport+=( $(echo "$width"x"$height") )
height=$(($height+$sdepth))
done
width=$(($width+$swidth))
done
local fmtstr=""
for i in ${viewport[@]} ; do
fmtstr=$fmtstr"$(printf "%s\"%s\" " "--add-entry=" $i)"
done
STR=$(zenity --forms --title="Set Viewport Commands" \
--text='Please avoid using # character' --separator="#" \
$fmtstr 2>/dev/null)
OLDIFS=$IFS
IFS="#"
commands=( $STR )
IFS=$OLDIFS
# for loop done with while loop
counter=0
while [ $counter -lt ${#viewport[@]} ] ;
do
echo "${viewport[$counter]}":"${commands[$counter]}"
counter=$(($counter+1))
done
}
get_current_viewport()
{
xprop -root -notype _NET_DESKTOP_VIEWPORT | \
awk -F'=' '{gsub(/\,/,"x");gsub(/\ /,"");print $2}'
}
run_viewport_command()
{
[ -r "$HOME"/"$DATAFILE" ] || \
{ printf ">>> ERR: commands file doesn't exit. \
\nCreate new one using -g flag" > /dev/stderr ; exit 1 ;}
local VP=$(get_current_viewport)
cmd=$(awk -v regex="^$VP" -F ':' '$0~regex{ $1="";print }' "$HOME"/"$DATAFILE")
eval $cmd " &> /dev/null &"
}
view_current_settings()
{
if [ -r "$HOME"/"$DATAFILE" ]; then
cat "$HOME"/"$DATAFILE" | \
zenity --list --height=250 --width=250 \
--title="current settings" --column="" 2> /dev/null
else
printf ">>> ERR: commands file doesn't exist
\\nCreate new one using -g flag" > /dev/stderr
exit 1
fi
}
change_single()
{
if [ -r "$HOME"/"$DATAFILE" ] ;then
NEWLINE="$(zenity --forms --separator='#' \
--add-entry="viewport to change(XPOSxYPOS):"\
--add-entry="new command")"
remove_this=$(awk -F '#' '{ print $1 }' <<< "$NEWLINE")
sed -i '/^'$remove_this'/d' "$HOME"/"$DATAFILE"
new_cmd=$(awk -F '#' '{$1="";printf "%s",$0}' <<< "$NEWLINE")
echo "$remove_this":"$new_cmd" >> "$HOME"/"$DATAFILE"
fi
}
print_usage()
{
cat << EOF
Usage: viewport_commands.sh [option]
Copyright Serg Kolo , 2016
-r run a command for current viewport
-g generate new list of commands
-h print this text
-v view current settings
-s change setting for a single viewport
EOF
}
parse_args()
{
[ $# -eq 0 ] && print_usage && exit 0
local option OPTIND
while getopts "grvhs" option ;
do
case ${option} in
g) gui_dialog > "$HOME"/"$DATAFILE"
;;
r) run_viewport_command
;;
v) view_current_settings
;;
s) change_single
;;
h) print_usage && exit 0
;;
\?) echo "Invalid option: -$OPTARG" >&2
;;
esac
done
shift $((OPTIND-1))
}
main()
{
local DATAFILE=".viewport_commands"
parse_args "$@"
exit 0
}
main "$@"
简单shell脚本版本(原答案)
Ubuntu 使用视口而不是工作区。这是一个以正数向下和向右计数的坐标系统,其中0,0
左上角是您的办公空间。
了解了这一点,我们可以编写一个简单的脚本来获取当前坐标、测试坐标并执行适当的命令。下面的脚本就是用来执行此操作的。
#!/bin/bash
get_viewport()
{
xprop -root -notype _NET_DESKTOP_VIEWPORT | \
awk -F '=' '{ gsub(/\ /,"");print $2 }'
}
get_viewport
case "$(get_viewport)" in
"0,0") notify-send 'You are in the top left viewport'
;;
"2732,768") notify-send 'You are in the bottom right viewport'
;;
esac
notify-send
用您想要的任何操作替换命令。用于nohup COMMAND 2>/dev/null &
避免命令挂起脚本(notify-send
是一个例外,因此没有将其添加到那里)。
使用xprop -root -notype _NET_DESKTOP_VIEWPORT
来确定每个视口的坐标。
最后,case 语句选项中不应有空格,例如"0,0"
works 但"0, 0"
will not。
Python 版本
介绍
此版本的脚本执行相同的功能,但为了简单易用,不包含命令行参数或 GUI 元素。该脚本可用作Github要点以及以下内容:
用法:
使用方法非常简单:
python3 /path/to/workspace_command.py
该脚本确定当前工作区并运行 中定义的适当命令~/.workspace_commands.json
。请确保先创建此文件,否则脚本将无法运行。还请注意,必须使用双引号来定义每个工作区,以及命令 + 参数
样本~/workspace_commands.json
:
{
"1":["nautilus"],
"2":["firefox","google.com"],
"3":["virtualbox"]
}
脚本源代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Author: Serg Kolo , contact: [email protected]
Date: August 9th, 2016
Purpose: Spawns a command depending on current
viewport, as defined in ~/.workspace_commands.json
Written for: https://askubuntu.com/q/56367/295286
Tested on: Ubuntu 16.04 LTS , Unity desktop
The MIT License (MIT)
Copyright © 2016 Sergiy Kolodyazhnyy <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
"""
# Just in case the user runs
# the script with python 2, import
# print function
from __future__ import print_function
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gio,Gdk
import json
import subprocess
import os
def gsettings_get(schema,path,key):
"""Get value of gsettings schema"""
if path is None:
gsettings = Gio.Settings.new(schema)
else:
gsettings = Gio.Settings.new_with_path(schema,path)
return gsettings.get_value(key)
def run_cmd(cmdlist):
""" Reusable function for running shell commands"""
try:
stdout = subprocess.check_output(cmdlist)
except subprocess.CalledProcessError:
print(">>> subprocess:",cmdlist)
sys.exit(1)
else:
if stdout:
return stdout
def enumerate_viewports():
""" generates enumerated dictionary of viewports and their
indexes, counting left to right """
schema="org.compiz.core"
path="/org/compiz/profiles/unity/plugins/core/"
keys=['hsize','vsize']
screen = Gdk.Screen.get_default()
screen_size=[ screen.get_width(),screen.get_height()]
grid=[ int(str(gsettings_get(schema,path,key))) for key in keys]
x_vals=[ screen_size[0]*x for x in range(0,grid[0]) ]
y_vals=[screen_size[1]*x for x in range(0,grid[1]) ]
viewports=[(x,y) for y in y_vals for x in x_vals ]
return {vp:ix for ix,vp in enumerate(viewports,1)}
def get_current_viewport():
"""returns tuple representing current viewport,
in format (width,height)"""
vp_string = run_cmd(['xprop', '-root',
'-notype', '_NET_DESKTOP_VIEWPORT'])
vp_list=vp_string.decode().strip().split('=')[1].split(',')
return tuple( int(i) for i in vp_list )
def read_config_file():
""" reads ~/.workspace_commands file """
rcfile = os.path.join( os.path.expanduser('~'),
'.workspace_commands.json')
try:
with open(rcfile) as config_file:
config_data = json.load(config_file)
except IOError as error:
print(error.__repr__())
else:
if config_data:
return config_data
def main():
# get all the info we need first
viewports_dict=enumerate_viewports()
current_viewport = get_current_viewport()
current_vp_number = viewports_dict[current_viewport]
viewport_config = read_config_file()
for vp,command in viewport_config.items():
if int(vp) == current_vp_number:
# spawn the command and let us exit
pid = subprocess.Popen(command).pid
break
if __name__ == '__main__':
main()
鼠标悬停操作:
最初的问题是如何让它与屏幕右侧的鼠标悬停操作配合使用。虽然我建议使用上述脚本作为键盘快捷键,但鼠标悬停操作也是可行的。下面是一个简单的脚本,如果鼠标位于屏幕的右上角,它会启动上面的 Python 版本。您可以随意调整脚本以满足您的需求
#!/usr/bin/env python3
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gio,Gdk
import subprocess
from time import sleep
def main():
screen = Gdk.Screen.get_default()
root_window = screen.get_root_window()
while True:
if root_window.get_pointer()[2] == 0 and \
root_window.get_pointer()[1] >= root_window.get_width()-2:
proc = subprocess.Popen(['python3','/home/user/bin/python/workspace_command.py']).pid
sleep(0.75)
if __name__ == '__main__':
main()
笔记:
类似的鼠标事件脚本可以通过使用命令并解析其输出的 shell 脚本来完成xdotool getmouselocation
,如下所示:
$ xdotool getmouselocation
x:1140 y:420 screen:0 window:14680095