徐中民 2025-10-13 19:30 采纳率: 98.6%
浏览 10
已采纳

QT eglfs旋转后触摸坐标错乱

在使用Qt的EGLFS平台插件时,若通过设置环境变量QT_QPA_EGLFS_ROTATION实现屏幕旋转(如90/180/270度),常出现触摸坐标与显示内容不匹配的问题。具体表现为:用户点击屏幕某位置时,Qt应用响应的触控事件坐标仍基于原始未旋转的坐标系,导致交互错乱。此问题源于EGLFS在旋转后未自动校正输入设备的坐标映射,需手动调整 tslib 或 libinput 的输入坐标变换矩阵,或通过自定义QPA插件干预坐标转换流程,确保触摸输入与显示方向一致。
  • 写回答

1条回答 默认 最新

  • 冯宣 2025-10-22 13:20
    关注

    一、问题背景与现象描述

    在嵌入式Linux系统中使用Qt框架时,EGLFS(EGL Full Screen)平台插件常用于无窗口管理器的场景,直接通过OpenGL ES渲染到帧缓冲设备。为了适配不同物理安装方向的显示屏(如竖屏或倒置),开发者通常通过设置环境变量 QT_QPA_EGLFS_ROTATION 来实现显示内容的旋转(支持90、180、270度)。

    然而,一个普遍存在的问题是:当屏幕旋转后,触摸输入坐标未同步旋转,导致用户点击屏幕上某一点时,Qt应用程序接收到的触控事件坐标仍基于原始未旋转的坐标系,从而引发交互错位。

    例如,当设置 QT_QPA_EGLFS_ROTATION=90 后,显示内容顺时针旋转90度,但触摸点 (x, y) 未被转换为新的坐标系,造成“点不准”现象。

    二、根本原因分析

    • EGLFS不自动处理输入设备坐标变换:Qt的EGLFS插件仅负责图形渲染层面的旋转,并不会干预底层输入事件的坐标映射。
    • 输入子系统独立于显示旋转:tslib 或 libinput 等输入驱动获取的原始触摸数据来自硬件设备节点(如/dev/input/eventX),其坐标范围和方向由设备本身决定,不受QT_QPA_EGLFS_ROTATION影响。
    • Qt QPA抽象层缺失自动校准机制:虽然QPA(Qt Platform Abstraction)允许自定义平台插件,但默认EGLFS实现未集成旋转后的输入坐标修正逻辑。

    三、解决方案分类与对比

    方案类型适用场景依赖组件维护成本灵活性
    修改tslib配置使用tslib的老式系统ts.conf, TSLIB_CALIBFILE
    配置libinput transformation现代系统使用Wayland或libinputlibinput + udev rules
    自定义QPA插件拦截输入事件需要深度控制输入流程C++开发能力极高
    应用层手动坐标转换临时调试或特定应用QWidget/QML处理

    四、具体实施路径

    1. 方案一:通过tslib进行坐标变换(适用于旧系统)
      # 修改 /etc/ts.conf
      module_raw input
      module pthres pmin=1
      module variance delta=30
      module dejitter delta=100
      module linear rotate=90  # 可选值:0, 90, 180, 270
      设置 TSLIB_TSDEVICETSLIB_CONFFILE 环境变量确保正确加载。
    2. 方案二:利用libinput坐标变换矩阵 创建udev规则文件:
      # /etc/udev/rules.d/99-touchscreen-calibration.rules
      ACTION=="add", KERNEL=="event[0-9]*", SUBSYSTEM=="input", \
      ENV{ID_INPUT_TOUCHSCREEN}=="1", \
      ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 1 0 0"
      上述矩阵表示90度旋转(x' = -y + width, y' = x)。
    3. 方案三:开发自定义QPA插件 继承 QEglFSKmsHwScreen 或重写 QPlatformInputContext,在事件分发前注入坐标变换逻辑。 示例代码片段:
      void CustomEglFSIntegration::processInputEvent(QInputEvent *event)
      {
          if (rotation == Qt::Rotate90) {
              for (auto &point : touchPoints) {
                  qreal newX = point.y();
                  qreal newY = screenSize.width() - point.x();
                  point.setPosition(QPointF(newX, newY));
              }
          }
          QWindowSystemInterface::sendEvent(window, event);
      }

    五、调试与验证流程图

    graph TD A[设置QT_QPA_EGLFS_ROTATION=90] --> B{是否启用tslib?} B -- 是 --> C[检查ts.conf中rotate参数] B -- 否 --> D{使用libinput?} D -- 是 --> E[添加LIBINPUT_CALIBRATION_MATRIX] D -- 否 --> F[开发自定义QPA插件] C --> G[运行ts_test校准] E --> H[使用evtest测试原始事件] F --> I[编译并替换平台插件] G --> J[验证Qt应用触控准确性] H --> J I --> J

    六、高级技巧与最佳实践

    对于多屏或动态旋转场景,建议在Qt应用启动时动态读取旋转角度,并通过信号槽机制广播给所有界面组件进行局部坐标补偿。可结合DBus监听屏幕方向变化事件,实现热切换。

    此外,可通过重写 QPlatformScreen::transformOrientation() 方法,在QPA层统一处理旋转逻辑,避免分散在多个模块中。

    推荐使用 evtest /dev/input/eventX 工具捕获原始触摸事件,确认底层坐标是否已正确变换;再用 qDebug() 输出Qt接收的QTouchEvent坐标,比对二者一致性。

    若使用Yocto构建系统,可在image配方中预置udev规则和tslib配置,确保部署一致性。

    注意:某些GPU驱动(如Vivante GC系列)在旋转后可能改变帧缓冲内存布局,需同步调整EGL surface绑定方式。

    在Qt6中,由于QPA架构进一步抽象,建议优先采用 QSGRhiPlatform 相关接口替代传统EGLFS定制方式。

    对于电容屏精度不足问题,可叠加软件滤波算法(如滑动平均、卡尔曼滤波)提升用户体验。

    务必在目标硬件上实测不同亮度、温度条件下的触控稳定性,排除硬件漂移干扰。

    建立自动化测试脚本,模拟点击四个角落及中心点,验证坐标映射准确性。

    文档化每台设备的旋转参数与输入校准配置,便于后期维护与批量部署。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 10月23日
  • 创建了问题 10月13日