
У меня есть следующий скрипт для определения назначений кнопок моего Wacom Intuos S 2:
/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh
#!/bin/bash
export DISPLAY=:0
export XAUTHORITY=/home/scriptim/.Xauthority
/usr/bin/sleep 1 # wait for device to be ready
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 3 'key +'
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 8 'key +Ctrl z -Ctrl'
/usr/bin/xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 9 'key +Ctrl +Shift z -Ctrl -Shift'
Этот скрипт работает нормально, если запустить его вручную.
Моя цель — автоматически запускать этот скрипт при каждом подключении планшета. Я попробовал сделать это с помощью следующего udev
правила:
/etc/udev/rules.d/10-wacom_intuos_s_2_pad.rules
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="056a", ATTRS{idProduct}=="033b", RUN+="/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh"
Однако скрипт не отображает кнопки, если я подключаю панель.
Я использую Arch Linux ( 5.5.10-arch1-1
)
$ lsusb
...
Bus 004 Device 015: ID 056a:033b Wacom Co., Ltd CTL-490 [Intuos Draw (S)]
...
$ udevadm info -a -n hidraw0
...
looking at parent device '/devices/pci0000:00/0000:00:10.0/usb4/4-2':
KERNELS=="4-2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{bcdDevice}=="0100"
ATTRS{bmAttributes}=="80"
ATTRS{bMaxPower}=="498mA"
ATTRS{manufacturer}=="Wacom Co.,Ltd."
ATTRS{quirks}=="0x0"
ATTRS{maxchild}=="0"
ATTRS{bNumInterfaces}==" 3"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{devpath}=="2"
ATTRS{ltm_capable}=="no"
ATTRS{busnum}=="4"
ATTRS{devnum}=="15"
ATTRS{tx_lanes}=="1"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bNumConfigurations}=="1"
ATTRS{speed}=="12"
ATTRS{version}==" 2.00"
ATTRS{product}=="Intuos PS"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{idVendor}=="056a"
ATTRS{configuration}==""
ATTRS{devspec}=="(null)"
ATTRS{urbnum}=="174"
ATTRS{bConfigurationValue}=="1"
ATTRS{removable}=="unknown"
ATTRS{rx_lanes}=="1"
ATTRS{idProduct}=="033b"
...
$ udevadm test --action="add" /devices/pci0000:00/0000:00:10.0/usb4/4-2
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.
Load module index
Parsed configuration file /usr/lib/systemd/network/99-default.link
Created link configuration context.
Reading rules file: /usr/lib/udev/rules.d/10-dm.rules
Reading rules file: /etc/udev/rules.d/10-wacom_intuos_s_2_pad.rules
...
Reading rules file: /usr/lib/udev/rules.d/65-libwacom.rules
...
Reading rules file: /usr/lib/udev/rules.d/wacom.rules
Invalid inotify descriptor.
DEVPATH=/devices/pci0000:00/0000:00:10.0/usb4/4-2
DEVNAME=/dev/bus/usb/004/015
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=56a/33b/100
TYPE=0/0/0
BUSNUM=004
DEVNUM=015
MAJOR=189
MINOR=398
ACTION=add
SUBSYSTEM=usb
ID_VENDOR=Wacom_Co._Ltd.
ID_VENDOR_ENC=Wacom\x20Co.\x2cLtd.
ID_VENDOR_ID=056a
ID_MODEL=Intuos_PS
ID_MODEL_ENC=Intuos\x20PS
ID_MODEL_ID=033b
ID_REVISION=0100
ID_SERIAL=Wacom_Co._Ltd._Intuos_PS
ID_BUS=usb
ID_USB_INTERFACES=:030000:030102:
ID_VENDOR_FROM_DATABASE=Wacom Co., Ltd
ID_MODEL_FROM_DATABASE=CTL-490 [Intuos Draw (S)]
ID_PATH=pci-0000:00:10.0-usb-0:2
ID_PATH_TAG=pci-0000_00_10_0-usb-0_2
USEC_INITIALIZED=4102997566
run: '/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh'
Unload module index
Unloaded link configuration context.
$ journalctl -xe
Mar 22 17:38:55 scriptim systemd-udevd[5927]: 1-1: Process '/usr/local/bin/wacom_intuos_s_2_pad_button_mapping.sh' failed with exit code 255.
решение1
По сути, это сочетание состояния гонки и разницы в поведении xsetwacom
при запуске из правила udev по сравнению с запуском из привычного графического терминала, например, из-за различий в переменных среды.
Проблема 1: переменная окружения.
Сначала рассмотрим вторую проблему: это похоже на ситуацию, когдаСкрипты оболочки ведут себя по-разному при запуске из cronjob.
Чтобы сравнить свою среду со средой udev, запуститеили env
или printenv
:
printenv > my-env.txt
из графического терминала, а затем добавьте этот скрипт udev:
/usr/bin/printenv > /tmp/udev-env.txt
Затем вы можете сравнить my-env.txt
и udev-env.txt
.
Чтобы определить, какие переменные среды xsetwacom
используются,установитьltrace
ивыполните команду вроде этой:
ltrace -f -e getenv -o my-ltrace-01.log xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
Поскольку у меня нет устройства Wacom, я не могу выполнить полную команду.
$ xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
Cannot find device 'Wacom Intuos S 2 Pad pad'.
Однако, основываясь только на том, как далеко xsetwacom
он заходит, прежде чем выйти, я могу сказать, что он использует DISPLAY
и XAUTHORITY
.
15447 libX11.so.6->getenv("DISPLAY") = ":0"
15447 libxcb.so.1->getenv("DISPLAY") = ":0"
15447 libxcb.so.1->getenv("DISPLAY") = ":0"
15447 libXau.so.6->getenv("XAUTHORITY") = "/home/nathaniel/.Xauthority"
15447 libX11.so.6->getenv("XLIBBUFFERSIZE") = nil
15447 libX11.so.6->getenv("XLIB_SKIP_ARGB_VISUALS") = nil
15447 libX11.so.6->getenv("XKB_DEBUG") = nil
15447 libX11.so.6->getenv("_XKB_OPTIONS_ENABLE") = nil
15447 libX11.so.6->getenv("XKB_DISABLE") = nil
15447 +++ exited (status 0) +++
Вы можете найти эти значения, распечатав их.
$ printf 'DISPLAY=%q\n' "$DISPLAY"
DISPLAY=:0
$ printf 'XAUTHORITY=%q\n' "$XAUTHORITY"
XAUTHORITY=/home/nathaniel/.Xauthority
Затем определите их в верхней части скрипта.
#!/bin/bash
# Just an example, yours will be different.
export DISPLAY=:0
export XAUTHORITY=/home/nathaniel/.Xauthority
sleep 1
# The rest of the script.
Скрипт все еще может не работать по другим причинам, но устранение различий в переменных окружения, похоже, было достаточным для других людей. Другой пользователь всвязанный вопросудалось заставить его работать на Ubuntu 18.04 следующим образом:
Вам необходимо добавить два переменных экспорта в ваш скрипт, один для
DISPLAY
иXAUTHORITY
. Они используются для идентификации и доступа к правильному сеансу X. Вы можете получить соответствующие значения, запустив его,env
войдя в систему как ваш обычный пользователь.
Проблема 2: Состояние гонки.
Теперь о состоянии гонки: xsetwacom
команда полагается на то, что X-сервер распознает оборудование, поэтому запуск его до того, как он будет готов, приведет к сбою. sleep 1
Очевидно, когда-то этого было достаточно, но теперь уже нет. (Иногда люди используютsleep 2
,sleep 3
, илиsleep 4
, без какой-либо особой причины. Вообще говоря, меня беспокоит, что это sleep 1
вообще необходимо.)
При подключении устройства:
- Linux обнаруживает устройство и создает запись устройства на основе правил udev.
- X-сервер обнаруживает устройство.
Вы не можете выполнить его
xsetwacom
до этапа 2. Ваш скрипт не выполняется, поскольку вы запускаете его на этапе 1, когда X еще не знает устройство.
—Жиль «ТАК- хватит быть злым»,https://unix.stackexchange.com/a/65792/30049
Это все хорошо, но когда люди пробуют сделать вот так, это уже не работает:
Я проголосовал за ваш ответ за подробности, но я не уверен, что это правильно по следующей причине: я пробовал использовать
sleep
с кучей секунд. При подключении планшет работает менее чем через секунду, поэтому к моменту выполнения команд устройство уже обнаружено и используетсяX
. Но все равно не работает?
Поскольку у меня нет вашего оборудования или ОС, я не могу воспроизвести вашу проблему. Но вот что я почерпнул из других тем: задержка sleep
сама по себе недостаточна. У некоторых людей есть обходные пути, такие как:
использование подоболочки и выполнение цикла до тех пор, пока устройство не будет указано в спискев
xsetwacom --list devices
.используя
at
команду, думал, не совсем понятно, почему это работает.
Возможно, самое полное решение, которое я видел, находится всвязанная темас использованием служебных файлов systemd:
В итоге мне пришлось запустить скрипт с помощью службы systemd, запущенной правилом udev:
$ cat /etc/udev/rules.d/99-wacom.rules SUBSYSTEM=="usb", ENV{ID_VENDOR_ID}=="056a", ENV{ID_MODEL_ID}=="0302", TAG+="systemd"
[...]
Позволяет
TAG+="systemd"
другим службам systemd (системным или пользовательским) зависеть от устройства (регистрирует его как единицу устройства, см. mansystemd.device
).