Скрипт Bash, который автоматически меняет раскладки клавиатуры и мыши на основе активного окна

UPDATE-полностью рабочий скрипт, расположенный в нижней части моего ответа для тех, кто не заинтересован в процессе получения там.

Я пытался написать сценарий bash, который использует xbindkeys, xkb и XInput set-button-map, чтобы автоматически изменять макеты моей клавиатуры Razer Tartarus и мыши Logitech G502 Proteus на основе текущего активного окна. Я решил сделать это, постоянно запустив сценарий в фон в бесконечном цикле, который проверяет, отличается ли активное окно от последней проверки. Я видел, как другие предлагали тебе .xbindkeysrc запускает другой скрипт для каждой комбинации клавиш, который проверяет активное окно перед тем, как решить, какую команду отправить, но с помощью 13-кнопочной мыши и 21-кнопочной клавиатуры количество необходимых скриптов быстро выйдет из-под контроля, особенно после того, как я начну добавлять сочетания.

autoProfileSwitch:

#!/bin/bash

Last=""

proteus_id=$(
    xinput list | 
    sed -n 's/.*G502.*id=([0-9]*).*pointer.*//p'
)
[ "$proteus_id" ] || exit

tartarus_id=$(
    xinput list |
    sed -n 's/.*Tartarus.*id=([0-9]*).*keyboard.*//p'
)
[ "$tartarus_id" ] || exit

tartarus_profile="default"
proteus_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
xbindkeys_profile=".xbindkeysrc"

while true; do
  Class=`xprop -id `xprop -root |nawk '/_NET_ACTIVE_WINDOW/ {print ;       exit;}'` |nawk -F = '/WM_CLASS/ {N=split(, A, ", ");  gsub(/"/,"",A[2]); print A[2]; exit;}'`

  if [ "$Class" != "$Last" ]
  then

    case $Class in
        "Dwarf_Fortress")   
            tartarus_profile="dwarfFortress"
            proteus_profile="1 3 2 4 5 6 7 8 9 10 11 12 13"
            xbindkeys_profile="dwarfFortress";;

        "Firefox")          
            tartarus_profile="default"
            proteus_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
            xbindkeys_profile=".xbindkeysrc";;

        "")                 
            tartarus_profile="default"
            proteus_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
            xbindkeys_profile=".xbindkeysrc";;

        *)                  
            tartarus_profile="default"
            proteus_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
            xbindkeys_profile=".xbindkeysrc";;
    esac

    if pgrep -x "xbindkeys" > /dev/null
    then
        killall xbindkeys
    fi

    xbindkeys -f $HOME/xbindkeys profiles/$xbindkeys_profile

    tartarusProfile -p $tartarus_profile
    #setxkbmap -device $tartarus_id -print | 
        #sed 's/(xkb_symbols.*)"/+tartarus('$tartarus_profile')"/' | 
        #xkbcomp -I$HOME/xbindkeys profiles/xkb -i $tartarus_id -synch -$DISPLAY 2>/dev/null

    for i in $proteus_id
        do
            xinput set-button-map $i $proteus_profile
        done

    Last="$Class"
  fi

done

Я попытался переместить содержимое моего сценария tartarusProfile в сценарий autoProfileSwitch (причина неиспользуемой переменной tartarus_id и закомментированных строк непосредственно под вызовом tartarusProfile), но по какой-то причине продолжал получать ошибку "sed не мог очистить stdout: Broken pipe". Код прекрасно работает, когда в собственном скрипте

tartarusProfile:

#!/bin/bash

# Set profile variable to argument (or default if none)

PROFILE="default"

while getopts p: option; do
    case "$option" in
        p) PROFILE=$OPTARG;;
    esac
done

# Get xinput device id for Razer Tartarus

tartarus_id=$(
    xinput list |
    sed -n 's/.*Tartarus.*id=([0-9]*).*keyboard.*//p'
)
[ "$tartarus_id" ] || exit

# Remap Razer Tartarus to selected profile

setxkbmap -device $tartarus_id -print | 
 sed 's/(xkb_symbols.*)"/+tartarus('$PROFILE')"/' | 
 xkbcomp -I$HOME/xbindkeys profiles/xkb -i $tartarus_id -synch - $DISPLAY 2>/dev/null

эти скрипты в основном работает по назначению, но есть некоторые странные вещи, которые я не могу изолировать. Для начала: вызовы xkb, похоже, происходят только в том случае, если окно терминала открыто и не свернуто (или еще в одном экземпляре, который я опишу позже), даже когда я запускаю скрипт с "autoProfileSwitch &"; xbindkeys и xinput вызываются независимо от того, открыто ли окно терминала.

другая проблема заключается в том, что клавиша" Tab " иногда привязана к моей правой кнопке мыши (в дополнение к предполагаемой замене MMB и RMB) при переключении на мои профили Dwarf Fortress, несмотря на то, что в профиле xbindkeys нет ничего, чтобы вызвать его.

наконец: несмотря на то, что xbindkeys не требует, чтобы окно терминала было открыто, что-то странное происходит, когда я перехожу из Dwarf Fortress в другое окно, когда оно закрыто. Прямо сейчас мое значение по умолчанию-привязка кнопки G7 моей мыши к клавише "f", чтобы разрешить быстрый полноэкранный режим на видео, но когда я переключаюсь с Dwarf Fortress в другом окне первый щелчок G7 дает " s "(ничего в xbindkeys, которые должны вызывать это), а второй щелчок дает ожидаемое"f". После того, как G7 становится моим ключом "f", xkb вызывается, и мой тартар также переключается на значение по умолчанию. Это, как правило, не позволяет xkb переключаться обратно на профиль Dwarf Fortress, когда это необходимо, даже когда открыто окно терминала.

любая помощь очень была бы оценена, и я могу обеспечить больше информации если необходимый.

5
задан DreadPirateLynx
источник

1 ответов

после дальнейшего тестирования, я сузил проблему до этого раздела кода:

setxkbmap -device $tartarus_id -print | 
    sed 's/\(xkb_symbols.*\)"/+tartarus('$tartarus_profile')"/' | 
    xkbcomp -I$HOME/xbindkeys\ profiles/xkb -i $tartarus_id -synch - $DISPLAY 2>/dev/null

моя предыдущая проблема с ошибкой сломанной трубы была связана с опечаткой, в которой я случайно удалил пространство между-и $ DISPLAY, поэтому этот код теперь работает в основном скрипте. Проблема в том, что этот раздел кода временно портит мою конфигурацию xbindkeys, и новая раскладка клавиатуры вступает в силу только после того, как xbindkeys выпрямляется. Xbindkeys управляет только чтобы выпрямить себя после того, как я нажимаю кнопку мыши, что он имеет отскок, но всегда есть что-то не так с этим первым щелчком мыши. Я знаю, что это код, который вызывает проблемы, потому что я прокомментировал все остальное, и проблема по-прежнему сохраняется, даже когда меняется только профиль xkb.

обновление 1: несмотря на то, что я делал все, что в моих силах, чтобы избежать этого, я в конце концов уступил и нашел время, чтобы выяснить, как добавить макеты для xkb, читая ответ такие, что теперь я могу называть

setxkbmap -device $tartarus_id -layout tartarus -variant $tartarus_profile

это решило одну из моих двух оставшихся проблем: мой Тартар успешно восстанавливается, как только активное окно изменяется. Моя мышь все еще ведет себя странно.

Это странно. Вся проблема" кнопка G7, отправляющая " s "первый щелчок", кажется, остановилась, но "вкладка" по-прежнему сопоставляется с моей кнопкой RMB и G9 для первого щелчка в Dwarf Fortress. Я не заметил какие-либо другие нарушения, но я точно не добавил кучу профилей, чтобы увидеть, как это продолжает играть. Что бы ни происходило, похоже, это связано с кнопками на моей мыши, настроенными для отправки нажатий клавиш, которые совпадают с ключами, которые изменились на Тартаре.

в любом случае, скрипт работает достаточно хорошо, и я готов начать его использовать. Если это только первый щелчок любой конкретной кнопки мыши, которая является неправильной (а не каждый кнопка заметьте), это то, с чем я могу жить; если моя проблема с мышью будет исправлена в будущем, это просто бонус.

обновление 2: в то время как troubeshooting странное поведение моей мыши, я изменил порядок команд, так что xbindkeys не работает в то время как setxkbmap вносит изменения. Я также попытался переключиться с xte на xdotool при отправке ключей и удалении "+ Release" из проблемных кнопок в моих конфигурациях xbindkeys. Поведение становятся реже, но все же случается изредка.

на несвязанной заметке использование xprop для получения активного класса window давало мне некоторые проблемы с полноэкранным видео, поэтому я переключился на использование xdotool, чтобы получить имя активного окна, которое, честно говоря, намного более читаемо в любом случае и, похоже, работает отлично.

обновление 3: переместил проверку идентификаторов мыши и клавиатуры в основной цикл и использовал ли они были найдены для определения менять или не менять свои профили. В результате скрипт теперь может обрабатывать мыши и клавиатуры, подключенные/отключенные во время работы.

обновление 4: оказалось, что странное поведение xbindkeys на самом деле не было исправлено. Короче говоря: это проблема как с xte, так и с xdotool, когда подключено несколько клавиатур с разными раскладками. Найдено решение для тех, кто испытывает эту проблему: добавьте xdotool ключ Cancel && к начало каждой строки макроса, которая вызывает xdotool (я предполагаю, что это работает и для xte, но я не пробовал). Например:

"xdotool key Return"
b:10

становится

"xdotool key Cancel && xdotool key Return"
b:10

это приводит к тому, что первый вызов xdotool (что обычно неправильно) отправляет "мертвый" ключ, а второй вызов дает вам то, что вы действительно хотели.

вот актуальный сценарий autoProfileSwitch для тех, кто хочет попробовать для своей мыши и сочетания клавиш. Сделай мне одолжение и upvote этот вопрос, если вы найдете этот скрипт пригодится:

#!/bin/bash

# Set Mouse and Keypad Names
# Edit These To Uniquely Identify Your Mouse and Keyboard in Xinput Output
# Leading and Trailing Wildcard Characters Not Necessary For Partial Names
mouse_name="YourMouseNameHere"
keypad_name="YourKeypadNameHere"

# Location of Xbindkeys Configuration Files
xbindkeys_dir="$HOME/xbindkeys profiles"

# Set Initialization Profiles
# keypad_layout Is an XKB Symbols File
# keypad_profile Is an XKB Symbols Definition within keypad_layout
# mouse_profile Is an xinput set-button-map Button Map String
# macro_profile Is an Xbindkeys Configuration File
keypad_layout="tartarus"
keypad_profile="default"
mouse_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
macro_profile=".xbindkeysrc"

# Keep Track of Last Time Active Window Changed
Last=""

# Main Loop
while true; do

  # Get Mouse and Keypad Xinput IDs
  mouse_id=$(
    xinput list | 
    sed -n 's/.*'$mouse_name'.*id=\([0-9]*\).*pointer.*//p'
  )

  keypad_id=$(
    xinput list |
    sed -n 's/.*'$keypad_name'.*id=\([0-9]*\).*keyboard.*//p'
  )

  # Get Name of Active Window
  Name="$(xdotool getwindowfocus getwindowname)"

  # Execute if Currently Active Window is Different from the Last Time It Changed
  if [ "$Name" != "$Last" ]
  then

    # Set Profiles Based on Name of Currently Active Window
    case $Name in
        Dwarf\ Fortress)   
            keypad_profile="dwarfFortress"
            mouse_profile="1 3 2 4 5 6 7 8 9 10 11 12 13"
            macro_profile="dwarfFortress";;

        *Firefox)          
            keypad_profile="blankSlate"
            mouse_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
            macro_profile="firefox";;

        *)                  
            keypad_profile="default"
            mouse_profile="1 2 3 4 5 6 7 8 9 10 11 12 13"
            macro_profile=".xbindkeysrc";;
    esac

    # Kill Xbindkeys
    if pgrep -x "xbindkeys" 1>/dev/null
    then
        killall xbindkeys
    fi  

    # Change Keypad Keymap to Appropriate Profile
    # Layout Is the Name of Your XKB Symbols File
    # Variant Is the Name of an xkb_symbols Section of the Layout File
    # Save Layout to /usr/share/X11/xkb/symbols/ 
    # Modify /usr/share/X11/xkb/rules/evdev .../evdev.xml and .../evdev.lst to Include Your Layout
    # Run "sudo dpkg-reconfigure xkb-data" After Any Changes to xkb/ Directory    
    # See https://askubuntu.com/a/483026 For More Info
    [ ! "$keypad_id" ] || setxkbmap -device $keypad_id -layout $keypad_layout -variant $keypad_profile

    # Restart Xbindkeys Using Appropriate Profile
    xbindkeys -f "$xbindkeys_dir"/$macro_profile

    # Set Mouse Profile
    # For When Your Device Appears More Than Once in Xinput
    [ ! "$mouse_id" ] || for i in $mouse_id; do xinput set-button-map $i $mouse_profile; done

    # This Is the Last Time The Active Window Changed
    Last="$Name"
  fi

# Short Sleep to Minimize CPU Usage
sleep .5

done
0
отвечен DreadPirateLynx 2017-11-15 18:13:03
источник

Другие вопросы bash linux xbindkeys xkb