В вопросе разобрался, только не работает мультитач. Нейросеть написала инструкцию и программу.
Установите библиотеку для работы с устройствами ввода в Python:
sudo apt update && sudo apt install -y python3-evdev
Создайте файл скрипта-фильтра:
sudo nano /usr/local/bin/touch_filter.py
Вставьте следующий код, заменив имя "Microstep Touch" на имя вашего тачскрина (из вывода evtest), а значения 1000 и 570 на координаты вашей фантомной точки:
#!/usr/bin/env python3
import evdev
from evdev import UInput, ecodes
import sys
TARGET_NAME = "QDtech MPI7003 Touchscreen"
# Лимиты отсечения аппаратного сбоя max/max
MAX_X_TRIGGER = 1010
MAX_Y_TRIGGER = 590
def main():
devices = [evdev.InputDevice(path) for path in evdev.list_devices()]
device = None
for d in devices:
if TARGET_NAME in d.name:
device = d
break
if not device:
print(f"Устройство {TARGET_NAME} не найдено!")
sys.exit(1)
try:
device.grab()
except OSError:
pass
# Конфигурация полноценного ST + MT устройства ввода
events_config = {
ecodes.EV_KEY: [ecodes.BTN_TOUCH],
ecodes.EV_ABS: [
(ecodes.ABS_X, evdev.AbsInfo(value=0, min=0, max=1024, fuzz=0, flat=0, resolution=0)),
(ecodes.ABS_Y, evdev.AbsInfo(value=0, min=0, max=600, fuzz=0, flat=0, resolution=0)),
(ecodes.ABS_MT_SLOT, evdev.AbsInfo(value=0, min=0, max=9, fuzz=0, flat=0, resolution=0)),
(ecodes.ABS_MT_POSITION_X, evdev.AbsInfo(value=0, min=0, max=1024, fuzz=0, flat=0, resolution=0)),
(ecodes.ABS_MT_POSITION_Y, evdev.AbsInfo(value=0, min=0, max=600, fuzz=0, flat=0, resolution=0)),
(ecodes.ABS_MT_TRACKING_ID, evdev.AbsInfo(value=0, min=0, max=65535, fuzz=0, flat=0, resolution=0))
]
}
ui = UInput(events_config, name=device.name + " Patched", vendor=device.info.vendor, product=device.info.product)
last_x, last_y = 0, 0
is_touching = False
current_tracking_id = 0
has_abs_in_frame = False
print("Патч кликов и удержания координат запущен...")
for event in device.read_loop():
# 1. Отслеживаем нажатие/отпускание клавиши тача
if event.type == ecodes.EV_KEY and event.code == ecodes.BTN_TOUCH:
is_touching = bool(event.value)
if is_touching:
current_tracking_id = (current_tracking_id + 1) % 65535
# Отправляем сигнал НАЖАТИЯ
ui.write(ecodes.EV_KEY, ecodes.BTN_TOUCH, 1)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_SLOT, 0)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_TRACKING_ID, current_tracking_id)
else:
# Отправляем сигнал ОТПУСКАНИЯ (Критично для работы кнопок!)
ui.write(ecodes.EV_KEY, ecodes.BTN_TOUCH, 0)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_SLOT, 0)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_TRACKING_ID, -1) # Закрываем MT слот
ui.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
ui.syn()
continue
# 2. Обрабатываем координаты, только если палец прижат
if event.type == ecodes.EV_ABS and is_touching:
if event.code in (ecodes.ABS_X, ecodes.ABS_MT_POSITION_X):
val_x = event.value
if val_x >= MAX_X_TRIGGER:
val_x = last_x # Игнорируем прыжок в максимум
else:
last_x = val_x
has_abs_in_frame = True
ui.write(ecodes.EV_ABS, ecodes.ABS_X, val_x)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_POSITION_X, val_x)
elif event.code in (ecodes.ABS_Y, ecodes.ABS_MT_POSITION_Y):
val_y = event.value
if val_y >= MAX_Y_TRIGGER:
val_y = last_y
else:
last_y = val_y
has_abs_in_frame = True
ui.write(ecodes.EV_ABS, ecodes.ABS_Y, val_y)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_POSITION_Y, val_y)
# 3. Закрываем кадр по сигналу оригинального SYN
if event.type == ecodes.EV_SYN:
# Если палец нажат, но контроллер выдал пустой кадр — удерживаем старые координаты
if is_touching and not has_abs_in_frame and last_x > 0 and last_y > 0:
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_SLOT, 0)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_TRACKING_ID, current_tracking_id)
ui.write(ecodes.EV_ABS, ecodes.ABS_X, last_x)
ui.write(ecodes.EV_ABS, ecodes.ABS_Y, last_y)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_POSITION_X, last_x)
ui.write(ecodes.EV_ABS, ecodes.ABS_MT_POSITION_Y, last_y)
# Отправляем SYN только если палец нажат (для предотвращения ложных пустых пакетов)
if is_touching:
ui.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
ui.syn()
has_abs_in_frame = False # Сброс флага для следующего кадра
if __name__ == "__main__":
main()
Сделайте скрипт исполняемым:
sudo chmod +x /usr/local/bin/touch_filter.py
Разрешение на создание виртуальных устройств ввода. Для того чтобы скрипт мог безболезненно перехватывать и создавать новые HID-устройства (через подсистему uinput), системный модуль ядра uinput должен автоматически загружаться при старте платы.Принудительно загрузите модуль:
sudo modprobe uinput
Добавьте его в список автозагрузки, чтобы настройки не слетели:
echo "uinput" | sudo tee -a /etc/modules
Добавление фильтра в автозагрузку Radxa OS. Чтобы скрипт работал в фоне как системная служба, создадим конфигурационный файл systemd.Создайте файл службы:
sudo nano /etc/systemd/system/touch-filter.service
Вставьте туда конфигурацию:
[Unit]
Description=MPI7006 Touchscreen Phantom Jump Filter
After=multi-user.target
Wants=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/touch_filter.py
Restart=always
RestartSec=2
User=root
[Install]
WantedBy=multi-user.target
Запустите службу и добавьте её в автозагрузку:
sudo systemctl daemon-reload
sudo systemctl enable touch-filter.service
sudo systemctl start touch-filter.service
Результат:Скрипт полностью заберет под свой контроль бракованный USB-дескриптор. Система перестанет реагировать на прыжки, так как Python-фильтр будет «съедать» пакет данных в момент их отправки контроллером Goodix, обеспечивая абсолютно плавное удержание пальца на экране.