Введение
Многие embedded-устройства используют сенсорные экраны как основной способ взаимодействия с пользователем, и в отсутствие полноценной оконной системы (статья 243) обработка касаний требует отдельной настройки на уровне Qt input-плагинов. В статье разберём, как настроить и откалибровать сенсорный ввод для embedded Qt-приложения, работающего через eglfs.
Концепция
Qt поддерживает несколько плагинов ввода для embedded-сценариев: evdevtouch (чтение событий касания напрямую из ядра Linux через интерфейс evdev) и libinput (более современная, универсальная библиотека обработки ввода, используемая по умолчанию во многих современных embedded-дистрибутивах). Калибровка сенсорного экрана нужна, когда физические координаты касания, считываемые драйвером сенсора, не совпадают точно с координатами пикселей на экране (что особенно часто бывает при использовании сенсорной панели и дисплея от разных производителей, смонтированных вместе механически) — Qt предоставляет встроенный инструмент калибровки и переменные окружения для применения матрицы преобразования координат.
Пример кода: Сенсорный экран и
# Указание конкретного устройства ввода для evdevtouch-плагина
export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/event3
# Альтернатива через libinput (рекомендуется для современных дистрибутивов)
export QT_QPA_GENERIC_PLUGINS=libinput
# Запуск встроенного в Qt инструмента калибровки сенсорного экрана
/opt/qt/examples/touchscreen/calibration
# Результат калибровки — матрица преобразования координат,
# применяемая через переменную окружения при последующих запусках приложения
export QT_QPA_EGLFS_TSLIB_CALIBRATION="1.0023 -0.0012 -15.4 0.0008 0.9987 -8.2"
// Программная обработка событий касания в QML-приложении
// (после корректной аппаратной калибровки события приходят с правильными координатами)
import QtQuick
MultiPointTouchArea {
anchors.fill: parent
onPressed: function(touchPoints) {
for (const point of touchPoints) {
console.log("Касание в координатах:", point.x, point.y);
}
}
minimumTouchPoints: 1
maximumTouchPoints: 5 // поддержка мультитач для распознавания жестов
}
// Программная проверка корректности калибровки во время разработки —
// логирование "сырых" координат для диагностики проблем калибровки
#include <QGuiApplication>
#include <QTouchEvent>
class TouchDiagnosticFilter : public QObject
{
protected:
bool eventFilter(QObject *watched, QEvent *event) override
{
if (event->type() == QEvent::TouchBegin || event->type() == QEvent::TouchUpdate) {
auto *touchEvent = static_cast<QTouchEvent *>(event);
for (const auto &point : touchEvent->points()) {
qDebug() << "Касание (диагностика):" << point.position();
}
}
return QObject::eventFilter(watched, event);
}
};
Пояснения к коду
Переменные окружения QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS/QT_QPA_GENERIC_PLUGINS определяют, через какой именно плагин и устройство Qt получает события касания — на практике для нового embedded-устройства часто требуется методом проб найти правильное устройство /dev/input/eventN, соответствующее именно сенсорной панели (а не, например, кнопкам питания или другому input-устройству, которые также могут быть представлены файлами в /dev/input/).
QT_QPA_EGLFS_TSLIB_CALIBRATION — результат процесса калибровки, представляющий собой матрицу аффинного преобразования (масштабирование, поворот, смещение), переводящую «сырые» координаты, считываемые драйвером сенсора, в реальные пиксельные координаты экрана; эта матрица обычно сохраняется один раз после процедуры калибровки на производственной линии и переиспользуется при каждом последующем запуске приложения на конкретном экземпляре устройства. MultiPointTouchArea в QML и TouchDiagnosticFilter в C++ показывают два уровня обработки касаний — высокоуровневый QML-компонент для обычной логики приложения, и низкоуровневый eventFilter, перехватывающий необработанные события QTouchEvent, полезный именно для диагностики проблем калибровки на этапе настройки нового устройства.
Подводные камни
- Калибровка, выполненная для одного конкретного физического экземпляра устройства, не переносится автоматически на другие экземпляры той же модели при массовом производстве — небольшие механические отличия между разными физическими сборками сенсорной панели и дисплея означают, что в идеале калибровка должна выполняться индивидуально для каждого произведённого устройства на этапе производственного тестирования, а не один раз для «эталонного» образца с последующим копированием результата на все остальные.
- Путаница между несколькими input-плагинами (
evdevtouch,libinput, специфичными для производителя драйверами), одновременно пытающимися обрабатывать один и тот же физический сенсор. Если в системе случайно активны два конкурирующих способа обработки ввода для одного устройства, события касания могут приходить дублированными или искажёнными — для каждого физического входного устройства должен быть однозначно определён ровно один обрабатывающий его путь. - Температурный и механический дрифт калибровки сенсорной панели со временем эксплуатации устройства. Для устройств, работающих в сложных условиях (промышленное оборудование с перепадами температур, частая механическая вибрация), однократная калибровка на производстве может со временем потерять точность — для таких сценариев стоит предусмотреть встроенный в само приложение интерфейс повторной калибровки, доступный конечному пользователю или сервисному инженеру без необходимости перепрошивки устройства.
- Тестирование обработки касаний только на устройстве разработки (которое может использовать другой, упрощённый сценарий ввода, например, эмуляцию касания через мышь в режиме разработки на десктопе) без проверки на реальном целевом сенсорном экране. Поведение мультитач-жестов, скорость и точность распознавания касаний значительно отличаются между симулированным вводом мышью на десктопе и реальным сенсорным экраном, и финальная проверка должна обязательно проходить на целевом физическом устройстве.