Shell 腳本版本

Shell 腳本版本

我想知道是否有一種方法可以使一個操作根據其所在的工作區而產生兩種不同的效果。

例如:如果在工作區 1 上,則使用聚焦 Empathy 聊天清單的指令,但如果在工作區 2 上,則使用開啟 Chrome 的指令。

它將與將滑鼠懸停在 Compiz 螢幕的右邊緣相關聯。

這可能嗎?

答案1

看一下xdotoolget_desktop將輸出目前視圖中的桌面。

對於有 Unity 的 Ubuntu,工作區被呼叫viewports並以左上角的 x 和 y 位置的座標形式呈現。

例如,

$ xdotool get_desktop_viewport     
4780 0

您可以使用該資訊來確定您所在的工作區,並為每個工作區執行命令。

答案2

筆記:答案已用 python 重寫,以獲得更好的性能,但沒有 GUI 元素。參見 參考資料 部分Python版本

Shell 腳本版本

介紹

下面的腳本允許根據目前活動的工作空間執行特定的命令。它旨在綁定到鍵盤快捷鍵。可以在此處找到正在運行的腳本的演示: https://www.youtube.com/watch?v=oxim3JbeiVM

取得腳本

從這篇文章複製腳本來源或透過以下步驟安裝:

  1. sudo apt-get install git
  2. cd /opt ; sudo git clone https://github.com/SergKolo/sergrep.git
  3. sudo chmod -R +x sergrep

該文件是/opt/sergrep/unity_viewport_commands.sh

用法和選項概述

該腳本具有以下標誌:

  • -r為目前視窗運行命令
  • -g產生新的指令列表
  • -h列印說明文字
  • -v查看目前設定
  • -s更改單一視窗的設置

該腳本旨在綁定到具有特定 flag 的鍵盤快捷鍵。例如, Ctrl++AltI 被綁定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"不會。


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

相關內容