我正在 xorg 上使用带有两个相同(ELO 品牌)触摸屏的应用程序。我想自动将正确的触摸面板分配给相应的显示器,即使 USB 电缆或显示器电缆重新插入也是如此。 (我必须运行一次设置实用程序,以检查哪个面板属于哪个显示器,但这不是问题)。
显示器和触摸面板都有序列号,我最好将它们放入配置文件中,在启动时查找它们并从那里运行正确的 xinput 命令。最好通过 udev 完成此操作,因为这可能是正确的方法。
我之前所做的是:
- 运行
xinput
查看输入:
$ xinput
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ Logitech USB-PS/2 Optical Mouse id=9 [slave pointer (2)]
⎜ ↳ Atmel Atmel maXTouch Digitizer id=10 [slave pointer (2)]
⎜ ↳ Atmel Atmel maXTouch Digitizer id=11 [slave pointer (2)]
⎜ ↳ Atmel Atmel maXTouch Digitizer id=15 [slave pointer (2)]
⎜ ↳ Atmel Atmel maXTouch Digitizer id=16 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard ... etcetera
然后列出 Atmel 面板的设备:
xinput --list-props 10|grep Device.Node|cut -f2 -d'"'
,这给了我/dev/input/event11
(对其他 3 个 Atmel id 也执行此操作)。然后运行udevadm看看哪些是触摸屏和读取序列号:
udevadm info /dev/input/event11
给我
N: input/event11
L: 0
S: input/by-path/pci-0000:00:14.0-usb-0:7:1.1-event
S: input/by-id/usb-Atmel_Atmel_maXTouch_Digitizer_E21R077282-event-if01
E: DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7:1.1/0003:03EB:8A6E.0003/input/input12/event11
E: DEVNAME=/dev/input/event11
E: MAJOR=13
E: MINOR=75
E: SUBSYSTEM=input
E: USEC_INITIALIZED=5462678
E: ID_INPUT=1
E: ID_INPUT_TOUCHSCREEN=1
E: ID_INPUT_WIDTH_MM=341
E: ID_INPUT_HEIGHT_MM=273
E: ID_VENDOR=Atmel
E: ID_VENDOR_ENC=Atmel
E: ID_VENDOR_ID=03eb
E: ID_MODEL=Atmel_maXTouch_Digitizer
E: ID_MODEL_ENC=Atmel\x20maXTouch\x20Digitizer
E: ID_MODEL_ID=8a6e
E: ID_REVISION=1034
E: ID_SERIAL=Atmel_Atmel_maXTouch_Digitizer_E21R077282
E: ID_SERIAL_SHORT=E21R077282
E: ID_TYPE=hid
E: ID_BUS=usb
E: ID_USB_INTERFACES=:030000:
E: ID_USB_INTERFACE_NUM=01
E: ID_USB_DRIVER=usbhid
E: ID_PATH=pci-0000:00:14.0-usb-0:7:1.1
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_7_1_1
E: LIBINPUT_DEVICE_GROUP=3/3eb/8a6e:usb-0000:00:14.0-7
E: DEVLINKS=/dev/input/by-path/pci-0000:00:14.0-usb-0:7:1.1-event /dev/input/by-id/usb-Atmel_Atmel_maXTouch_Digitizer_E21R077282-event-if01
现在我有了面板的序列号。
然后我需要连接的显示器:xrandr -q --verbose
显示监视器和 edid 块。因为 edid 信息是只读且不可变的,所以我现在可以将其用作固定标识符。 (虽然我可以,但不需要跑步edid-decode
)。
我省略了从 xrandr 输出中获取监视器名称的脚本;但最后,我可以连接ID_SERIAL_SHORT=E21R077282
必须监视 DP-4 的Atmel 数字化仪xinput --map-to-output 10 DP-4
:并将另一个 Atmel 面板添加到 DP-6。
但这感觉就像是大量的数字运算,从 到id=10
到/dev/input/event11
序列号。
- 这可以用 udev 规则来完成吗?
- 我应该制定一个区分 on 的 udev 规则
ID_SERIAL_SHORT
吗? - 但那么,它应该如何处理这些信息呢?
- 即如何将信息从 udev 传输到 xorg?
- 并且
udev
也能够从 xorg 获取监视器信息?或者说我应该如何建立两者之间的联系?
答案1
简短的回答:你不能(更新:你能, 见下文)
udev
都是关于 USB 设备处理的。将某些内容插入 USB 端口时,udev
会发生一个操作,您可以关联许多内容,包括在 udev 规则中运行任何自定义脚本。
然而,(a) 不能保证 X11 服务器当时正在运行,并且 (b) 即使它正在运行,它也可能由不同的用户拥有,如果您可以将某些东西潜入其中,这将是一个安全漏洞通过系统调用的特权脚本来访问 X11 服务器udev
。
例如,您不能合法地调用xinput
命令作为 udev 规则的一部分,它不应该能够执行任何操作,即使如果由登录到桌面的用户调用相同的命令也可以正常运行。
有很多关于规则的建议(例如 Wacom 触摸板):
ATTRS{idVendor}=="056a", ACTION=="add", ENV{DISPLAY}=":0.0", ENV{XAUTHORITY}="/home/someusername/.Xauthority", RUN+="/usr/local/sbin/wacom.sh $env{DEVNAME}"
其中wacom.sh
脚本依次进行适当的xinput
调用,但它们假设了许多不一定正确的事情:DISPLAY 实际上是,:0.0
或者 root 可以访问指定的.Xauthority
文件(并不总是正确的,取决于主目录的方式)已安装)或者用户名在多用户系统上始终相同。
唯一合法的解决方法是在插入 USB 触摸设备后由用户手动运行脚本。您可以将其与面板/桌面上的按钮关联,但系统无法调用它udev
。
下面是我用来将并排排列的两个相同的触摸屏显示器映射到一个扩展桌面的示例。我使用 xinput/udevadm(根据设备有不同的检测方案)和所有屏幕和设备的硬编码序列号,将左侧手写笔/触摸屏映射到左侧显示器,将右侧手写笔/触摸屏映射到右侧显示器。解析 EDID 时的确切搜索字符串很大程度上取决于操作系统和 edid 解码版本,因此可能需要根据您的情况进行调整,我无法找出提取 EDID 信息的通用方法。
#!/bin/bash
LEFT_USB=XXXXXXX
LEFT_HDMI=YYYYYYY
RIGHT_USB=ZZZZZZZ
RIGHT_HDMI=TTTTTTT
### all xinput devices
ids=`xinput list --id-only`
left_ids=""
right_ids=""
for i in $ids
do
node=`xinput list-props $i | grep Device\ Node | cut -f2 -d\"`
if [ ! -z "$node" ]; then
serial=`udevadm info $node | grep ID_SERIAL_SHORT | cut -f2 -d=`
touch_id=`xinput list $i | grep "TouchClass" | sed -r 's/[^0-9]*([0-9]+).*/\1/'`
pen_id=`xinput list $i | grep Pen | cut -f2 -d= | cut -f1`
if [ "$serial" == "$LEFT_USB" ]; then
left_ids+="$pen_id $touch_id "
elif [ "$serial" == "$RIGHT_USB" ]; then
right_ids+="$pen_id $touch_id "
fi
fi
done
left_ids=`echo $left_ids | uniq | xargs`
right_ids=`echo $right_ids | uniq | xargs`
### all connected displays
DISPLAYS=`xrandr | grep \ connected | cut -f1 -d\ `
for d in $DISPLAYS
do
serial=`xrandr -q --verbose | sed -n "/$d connected/,/HDCP/p" | edid-decode | grep '\ \ Serial\ Number:' | cut -f2 -d: | xargs`
if [ "$serial" == "$LEFT_HDMI" ]; then
for i in $left_ids
do
xinput map-to-output $i $d
done
elif [ "$serial" == "$RIGHT_HDMI" ]; then
for i in $right_ids
do
xinput map-to-output $i $d
done
fi
done
exit 0
编辑:
imdn 提出了一个有趣的替代方案在 Arch Linux 系统管理论坛中。基本思想是利用由规则创建的信号量文件udev
,并将其添加inotifywait
到 X 配置(例如,file-inotify
从 启动服务~/.xprofile
)以监视对该锁定文件的任何更改,并xinput
在发生变化时执行适当的命令发生。原则上似乎可行,但我无法让它继续下去。
唯一正确的解决方案是更改 X 配置本身,并在配置新指针设备时调用适当选项的设置。如果设备名称是唯一的,则只需在/etc/X11/xorg.d/*
based on中添加规则即可。MatchProduct
此示例适用于 Wacom Cintiq 平板电脑,在 Ubuntu 23.04、xfce4 上进行测试:
## this file is /etc/X11/xorg.conf.d/50-wacom.conf
# xrandr:
# DVI-0 connected primary 2560x1600+0+0 (main monitor)
# DisplayPort-0 connected 1920x1080+2560+0 (Wacom Cintiq tablet)
# Wacom tablet can be configured to be --right-of 1920x1080+2560+0 or --below 1920x1080+0+1600
# --right-of means x-shift=2560/(2560+1920)=0.571429, x-scale=1920/(2560+1920)=0.428571, yscale=1080/1600=0.675
# Option "TransformationMatrix" "0.428571 0 0.571429 0 0.675 0 0 0 1"
# --below means y-shift=1600/(1600+1080)=0.597015, y-scale=1080/(1600+1080)=0.402985, xscale=1920/2560=0.75
# Option "TransformationMatrix" "0.75 0 0 0 0.402985 0.597015 0 0 1"
# Refs:
# https://unix.stackexchange.com/questions/58117/determine-xinput-device-manufacturer-and-model
# https://askubuntu.com/questions/178140/xinput-coordinate-transformation-matrix-in-xorg-conf
# https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations
#
# Can match by a common substring for all Wacom devices (as reported by xinput):
# MatchProduct "Wacom ISDv5 307 Pen stylus"
# MatchProduct "Wacom ISDv5 307 Pen eraser"
# MatchProduct "Wacom ISDv5 309 Finger touch"
Section "InputClass"
Identifier "Wacom Cintiq"
Driver "wacom"
MatchProduct "Wacom ISDv5"
Option "TransformationMatrix" "0.428571 0 0.571429 0 0.675 0 0 0 1"
EndSection
如果有两个相同的设备具有相同的产品 ID(唯一的唯一标识符是序列号),事情就会变得更加复杂。不幸的是,MatchSerial
xorg 中不存在选项,但可以设置一个TAG
inudev
规则,然后使用MatchTag
in xorg
。
编辑:
最后,这是正确的解决方案。以下示例适用于我并排的两个 FlatFrog 面板。这个特定解决方案的优点在于,所有子设备在激活时都会继承这些缩放属性,因此无需单独追逐触摸/手写笔/橡皮擦。
### this is /etc/udev/rules.d/69-flatfrog.rules
ACTION=="remove", GOTO="flatfrog_end"
KERNEL!="event[0-9]*", GOTO="flatfrog_end"
ATTRS{idVendor}=="25b5", ATTRS{idProduct}="0082", ENV{ID_SERIAL_SHORT}=="XXXXXXXXX", ENV{ID_INPUT.tags}="FlatFrogRHS"
ATTRS{idVendor}=="25b5", ATTRS{idProduct}="0082", ENV{ID_SERIAL_SHORT}=="YYYYYYYYY", ENV{ID_INPUT.tags}="FlatFrogLHS"
LABEL="flatfrog_end"
### this is /etc/X11/xorg.conf.d/10-flatfrog.conf
Section "InputClass"
Identifier "RHstylus"
MatchTag "FlatFrogRHS"
Option "TransformationMatrix" "0.5 0 0.5 0 1 0 0 0 1"
EndSection
Section "InputClass"
Identifier "LHstylus"
MatchTag "FlatFrogLHS"
Option "TransformationMatrix" "0.5 0 0 0 1 0 0 0 1"
EndSection
参考:https://gitlab.freedesktop.org/xorg/xserver/-/issues/1592