如何在 Wayland 上校准触摸屏?

如何在 Wayland 上校准触摸屏?

我有一台运行 Gnome 和 Wayland 的 Fedora 35 笔记本。它有一个内置触摸屏,即使在多显示器设置中也能正常工作,并且无需校准。
我有两个外部显示器(一个普通的 4k 显示器和一个 1080p USB-C 触摸屏)。当我连接这些显示器时,我禁用内部笔记本电脑屏幕,因为我在该设置中不需要它。所以我最终得出这样的结论:

显示器设置

这完全没问题。 (右屏为外接触摸屏,左屏为外接4k显示器。)

问题是触摸屏认为它是 5760x2160 像素,而实际上只是 1920x1080,导致触摸输入不正确:

错误的触摸输入2

为了解决这个问题,我找到了这篇文章:Arch Wiki - 校准_触摸屏 但它依赖于 xinput,而 Wayland 上似乎不存在 xinput。

不过,这篇文章确实提到了一种使用 udev 持续校准触摸屏的方法。为此,我需要计算变换矩阵,我按照文章中所述进行了计算:

现在,尽可能准确地计算这些:

c0 = touch_area_width / total_width
c2 = touch_area_height / total_height
c1 = touch_area_x_offset / total_width
c3 = touch_area_y_offset / total_height

矩阵是

[ c0 0 c1 ] [ 0 c2 c3 ] [ 0 0 1 ]

其表示为逐行数组:

c0 0 c1 0 c2 c3 0 0 1

我最终得到了这个:

c0 = touch_area_width / total_width     | 1920/(3840+1920)=0.333333333
c2 = touch_area_height / total_height   | 1080/2160=0.5
c1 = touch_area_x_offset / total_width  | 3840/(3840+1920)=0.666666667
c3 = touch_area_y_offset / total_height | 0/2160=0

c0 0 c1 0 c2 c3 0 0 1                   | 0.333333333 0 0.666666667 0 0.5 0 0 0 1

然后本文继续展示使用简单变换矩阵的 udev 规则示例:

/etc/udev/rules.d/99-acer-touch.rules

ENV{ID_VENDOR_ID}==“2149”,ENV{ID_MODEL_ID}==“2703”,ENV{WL_OUTPUT}="DVI1",ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0"

因此,我似乎需要知道供应商 ID 和型号 ID(我认为与产品 ID 相同)以及“WL_OUTPUT”(我将其称为监视器连接器)。

通过以下方式获取供应商 ID 和产品 IDlsusb很简单:

$ lsusb
Bus 005 Device 007: ID 1d5c:7102 Fresco Logic Generic Billboard Device
Bus 005 Device 006: ID 222a:0001 ILI Technology Corp. Multi-Touch Screen
Bus 005 Device 005: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
# ... Those 5 devices show up when I connect the touch screen. I removed the rest from the list.

好的,现在我有了供应商 ID (222a) 和产品 ID (0001)。

然后我编写了这个荒谬的 python 脚本来通过 dbus 找出监视器连接器的名称,因为如果没有以下命令,我无法弄清楚如何做到这一点xrandr --query

#!/usr/bin/python3

# https://dbus.freedesktop.org/doc/dbus-python/tutorial.html
# https://github.com/GNOME/mutter/blob/b5f99bd12ebc483e682e39c8126a1b51772bc67d/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml
# https://ask.fedoraproject.org/t/change-scaling-resolution-of-primary-monitor-from-bash-terminal/19892

import dbus
bus = dbus.SessionBus()

display_config_well_known_name = "org.gnome.Mutter.DisplayConfig"
display_config_object_path = "/org/gnome/Mutter/DisplayConfig"

display_config_proxy = bus.get_object(display_config_well_known_name, display_config_object_path)
display_config_interface = dbus.Interface(display_config_proxy, dbus_interface=display_config_well_known_name)

serial, physical_monitors, logical_monitors, properties = display_config_interface.GetCurrentState()

for x, y, scale, transform, primary, linked_monitors_info, props in logical_monitors:
    for linked_monitor_connector, linked_monitor_vendor, linked_monitor_product, linked_monitor_serial in linked_monitors_info:
        for monitor_info, monitor_modes, monitor_properties in physical_monitors:
            monitor_connector, monitor_vendor, monitor_product, monitor_serial = monitor_info
            if linked_monitor_connector == monitor_connector:
                print("Display: " + monitor_properties.get("display-name") + " - Connector: " + monitor_connector)

输出是:

Display: RTK 22" - Connector: DP-2
Display: LG Electronics 27" - Connector: DP-5

我现在知道连接器是 DP-2。

然后我创建了这个简单的 bash 脚本并运行它sudo

#!/bin/bash
VENDOR_ID=222a
PRODUCT_ID=0001
MONITOR_CONNECTOR=DP-2
CALIBRATION_MATRIX="0.333333333 0 0.666666667 0 0.5 0 0 0 1"

UDEV_RULE="ENV{ID_VENDOR_ID}==\"${VENDOR_ID}\",ENV{ID_MODEL_ID}==\"${PRODUCT_ID}\",ENV{WL_OUTPUT}=\"${MONITOR_CONNECTOR}\",ENV{LIBINPUT_CALIBRATION_MATRIX}=\"${CALIBRATION_MATRIX}\""
UDEV_RULES_FILE="/etc/udev/rules.d/99-touchscreen-cal.rules"

echo "${UDEV_RULE}" > "${UDEV_RULES_FILE}"
udevadm control --reload-rules && udevadm trigger

我没有任何错误。然后我仔细检查了生成的规则文件:

$ cat /etc/udev/rules.d/99-touchscreen-cal.rules 
ENV{ID_VENDOR_ID}=="222a",ENV{ID_MODEL_ID}=="0001",ENV{WL_OUTPUT}="DP-2",ENV{LIBINPUT_CALIBRATION_MATRIX}="0.333333333 0 0.666666667 0 0.5 0 0 0 1"

所以一切都应该有效,对吧?但事实并非如此。触摸屏输入仍然像以前一样不正确。

我有什么想法可以解决这个问题吗?

编辑:

当我不禁用内部触摸屏时,外部触摸屏会将所有触摸输入发送到该内部触摸屏,而不是将触摸输入分散到所有显示器上。 (如果我触摸外接1080p触摸屏的右下角,则该触摸会在笔记本电脑等内置4k触摸屏的右下角注册......) 3 个显示器
(从左到右:外接4k屏、外接1080p触摸屏、内置4k触摸屏)

编辑2:

根据文章中,让触摸屏在多显示器设置中正常工作的唯一方法是使用 X11。根据libinput currently assumes the touchscreen(s) covers all available monitors.我知道不正确的文章,因为我的内部(非 USB)触摸屏工作得很好,即使在多显示器设置中也是如此。

相关内容