
我有以下腳本來定義 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 規則運行時與從熟悉的圖形終端運行時的行為差異(由於環境變數的差異等原因)的組合。
問題一:環境變數。
先解決第二個問題:這和下面的情況類似從 cronjob 運行時 shell 腳本的行為有所不同。
若要將您的環境與 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 階段之前執行。
—吉爾斯“所以——別再作惡了”,https://unix.stackexchange.com/a/65792/30049
這一切都很好,但是當人們嘗試這個時,它就不再起作用了:
我贊成您對詳細資訊的回答,但我不確定這是否正確,原因如下:我嘗試使用了
sleep
幾秒鐘。插入電源後,平板電腦會在不到一秒的時間內開始工作,因此在執行命令時,設備已被 偵測到並正在使用X
。但還是不行?
由於我沒有您的硬體或作業系統,因此我無法複製您的問題。但這是我從其他線程中收集到的信息:sleep
延遲本身是不夠的。有些人有解決方法,例如:
使用子 shell 並循環直到列出設備在
xsetwacom --list devices
。使用
at
命令,認為不清楚為什麼會這樣。
也許我見過的最徹底的解決方案是連結線程使用systemd服務檔案:
我最終不得不使用由 udev 規則觸發的 systemd 服務來啟動腳本:
$ 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
)。