
Ich habe das folgende Skript, um die Tastenzuordnungen meines Wacom Intuos S 2 zu definieren:
/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'
Dieses Skript funktioniert einwandfrei, wenn ich es manuell ausführe.
Mein Ziel ist es, dieses Skript automatisch auszuführen, wenn das Pad angeschlossen wird. Ich habe das mit der folgenden udev
Regel versucht:
/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"
Allerdings ordnet das Skript die Tasten nicht zu, wenn ich das Pad anschließe.
Ich verwende 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.
Antwort1
Im Wesentlichen handelt es sich dabei um eine Kombination aus einem Race Condition und dem unterschiedlichen Verhalten beim xsetwacom
Ausführen über eine Udev-Regel im Vergleich zum Ausführen über ein bekanntes grafisches Terminal, was beispielsweise auf Unterschiede bei den Umgebungsvariablen zurückzuführen ist.
Problem 1: Umgebungsvariable.
Kommen wir zunächst zum zweiten Problem: Dies ist vergleichbar mit der Situation, in derShell-Skripte verhalten sich anders, wenn sie von einem Cronjob ausgeführt werden.
Um Ihre Umgebung mit der udev-Umgebung zu vergleichen, führen Sie ausentweder env
oder printenv
:
printenv > my-env.txt
von einem grafischen Terminal aus und fügen Sie dann das folgende Udev-Skript hinzu:
/usr/bin/printenv > /tmp/udev-env.txt
Dann können Sie vergleichen my-env.txt
und udev-env.txt
.
Um abzuleiten, welche Umgebungsvariablen xsetwacom
verwendet werden,Installierenltrace
UndFühren Sie einen Befehl wie diesen aus:
ltrace -f -e getenv -o my-ltrace-01.log xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
Da ich kein Wacom-Gerät habe, kann ich den vollständigen Befehl nicht ausführen.
$ xsetwacom set 'Wacom Intuos S 2 Pad pad' Button 1 'key -'
Cannot find device 'Wacom Intuos S 2 Pad pad'.
Allein anhand der xsetwacom
zurückgelegten Strecke bis zum Beenden kann ich jedoch erkennen, dass es DISPLAY
und verwendet 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) +++
Diese Werte können Sie durch Ausdrucken ermitteln.
$ printf 'DISPLAY=%q\n' "$DISPLAY"
DISPLAY=:0
$ printf 'XAUTHORITY=%q\n' "$XAUTHORITY"
XAUTHORITY=/home/nathaniel/.Xauthority
Definieren Sie sie dann oben im Skript.
#!/bin/bash
# Just an example, yours will be different.
export DISPLAY=:0
export XAUTHORITY=/home/nathaniel/.Xauthority
sleep 1
# The rest of the script.
Das Skript könnte aus anderen Gründen immer noch nicht funktionieren, aber für manche Leute scheint es ausreichend gewesen zu sein, die Unterschiede in den Umgebungsvariablen zu beseitigen. Ein anderer Benutzer in einemVerwandte Fragekonnte es unter Ubuntu 18.04 folgendermaßen zum Laufen bringen:
Sie müssen Ihrem Skript zwei Variablenexporte hinzufügen, einen für
DISPLAY
undXAUTHORITY
. Diese werden zum Identifizieren und Zugreifen auf die richtige X-Sitzung verwendet. Sie können die entsprechenden Werte abrufen, indem Sie es ausführen,env
während Sie als normaler Benutzer angemeldet sind.
Problem 2: Race Condition.
Nun zum Race Condition: Der xsetwacom
Befehl verlässt sich darauf, dass der X-Server die Hardware erkennt. Wenn er also ausgeführt wird, bevor er bereit ist, schlägt er fehl. Das sleep 1
war anscheinend einmal ausreichend, ist es aber nicht mehr. (Manchmal verwenden die Leutesleep 2
,sleep 3
, odersleep 4
, ohne besonderen Grund. Generell beunruhigt es mich, dass das sleep 1
überhaupt notwendig ist.)
Wenn Sie das Gerät anschließen:
- Linux erkennt das Gerät und erstellt einen Geräteeintrag basierend auf Udev-Regeln.
- Der X-Server erkennt das Gerät.
Sie können nicht
xsetwacom
vor Phase 2 ausführen. Ihr Skript schlägt fehl, weil Sie es in Phase 1 ausführen, wenn X das Gerät noch nicht kennt.
—Gilles: „Also, hör auf, böse zu sein“,https://unix.stackexchange.com/a/65792/30049
Das ist ja alles schön und gut, aber wenn man das hier probiert, funktioniert es nicht mehr:
Ich habe Ihre Antwort wegen der Details positiv bewertet, bin mir aber aus folgendem Grund nicht sicher, ob sie richtig ist: Ich habe versucht, es
sleep
mit einigen Sekunden zu verwenden. Beim Anschließen funktioniert das Tablet nach weniger als einer Sekunde. Wenn die Befehle ausgeführt werden, wird das Gerät also bereits erkannt und verwendetX
. Aber es funktioniert immer noch nicht?
Da ich weder Ihre Hardware noch Ihr Betriebssystem habe, kann ich Ihr Problem nicht reproduzieren. Aber Folgendes habe ich aus anderen Threads herausgelesen: Die sleep
Verzögerung allein reicht nicht aus. Manche Leute haben Workarounds wie:
Verwenden einer Subshell und Ausführen einer Schleife, bis das Gerät aufgelistet istIn
xsetwacom --list devices
.mit dem
at
Befehl, dachte, es ist nicht klar, warum das funktioniert.
Die vielleicht gründlichste Lösung, die ich gesehen habe, ist dieVerlinkter ThreadVerwenden von systemd-Dienstdateien:
Letztendlich musste ich das Skript mit einem systemd-Dienst starten, der durch eine Udev-Regel ausgelöst wurde:
$ cat /etc/udev/rules.d/99-wacom.rules SUBSYSTEM=="usb", ENV{ID_VENDOR_ID}=="056a", ENV{ID_MODEL_ID}=="0302", TAG+="systemd"
[...]
Dadurch
TAG+="systemd"
werden andere systemd-Dienste (System oder Benutzer) vom Gerät abhängig (registriert es als Geräteeinheit, siehe mansystemd.device
).