嵌入式Qt/QML应用无法接收键盘事件(Linux帧缓冲/VNC/systemd)
问题:ARM嵌入式设备Qt/QML应用无法响应VNC及USB键盘事件
我需要远程控制ARM嵌入式设备上的Qt/QML应用,计划用VNC实现,但按键无响应,同时设备本地USB键盘也无法工作。
背景信息
- 应用平时通过GPIO硬键控制,自定义代码将硬键输入转为Qt事件发送:
QCoreApplication::postEvent(..., new QKeyEvent(QEvent::KeyPress, ...));
- 尝试VNC方案:
- 设备端启动命令:
x11vnc -rawfb map:/dev/fb0@800x480x32 -forever -rotate -90 -dk - PC端连接命令:
gvncviewer 192.168.1.1:0 - 屏幕可正常显示,但Qt应用完全不响应VNC发送的按键。
- 设备端启动命令:
- Qt应用通过systemd服务启动,已尝试绑定TTY,服务配置:
[Unit] Description=Instrument IHM After=network.target [Service] StandardInput=tty-force StandardOutput=tty StandardError=tty TTYPath=/dev/tty0 Restart=always ExecStartPost=/path/to/my_application --platform linuxfb:fb=/dev/fb0:rotation=90 -plugin evdevkeyboard:/dev/input/event0 Restart=on-failure RestartSec=2s [Install] WantedBy=multi-user.target
- VNC服务器日志已捕获到键盘事件(示例片段):
05/03/2024 09:17:30 # keyboard(down, 0xff54 "Down") uip=0 14.6279 05/03/2024 09:17:31 # keyboard(up, 0xff54 "Down") uip=0 14.7875 05/03/2024 09:17:32 # keyboard(down, 0xff52 "Up") uip=0 15.7994 05/03/2024 09:17:32 # keyboard(up, 0xff52 "Up") uip=0 15.8880
解决方案
1. 修复systemd服务启动命令错误
你的systemd配置误用了ExecStartPost,该指令是主服务启动后执行的命令,而非启动应用的指令。需替换为ExecStart:
[Service] # 替换ExecStartPost为ExecStart ExecStart=/path/to/my_application --platform linuxfb:fb=/dev/fb0:rotation=90 -plugin evdevkeyboard:/dev/input/event0
ExecStartPost会让应用脱离systemd的TTY绑定上下文,导致无法正确接收输入事件。
2. 确认evdevkeyboard插件的设备路径
- 查看设备输入节点列表:
ls /dev/input/ - 用
evtest验证目标节点是否为键盘设备:
若event0不是键盘设备,替换为正确的节点(如event1)。evtest /dev/input/event0
3. 调整VNC服务器的事件注入方式
当前x11vnc -rawfb模式仅捕获帧缓冲,无法直接向LinuxFB平台的Qt应用注入事件,可尝试两种方案:
方案A:使用fbvncserver(专为LinuxFB设计)
安装后启动:
fbvncserver -f /dev/fb0 -w 800 -h 480 -d 32 -r -90
该VNC服务器直接操作帧缓冲,同时支持向evdev设备注入事件,Qt的evdevkeyboard插件可直接捕获。
方案B:启用x11vnc的uinput模拟
通过uinput模块模拟输入设备,启动命令添加-uinput参数:
x11vnc -rawfb map:/dev/fb0@800x480x32 -forever -rotate -90 -dk -uinput
需确保内核已加载uinput模块:
modprobe uinput
4. 验证Qt应用的事件接收逻辑
- 在应用中添加日志,打印所有键盘事件:
bool MyWindow::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); qDebug() << "Received key press:" << keyEvent->key(); } return QWidget::event(event); } - 确保窗口可获取焦点:
Window { focusPolicy: Qt.StrongFocus // ... }
5. 修复权限问题
- 临时赋予设备节点读写权限:
chmod 666 /dev/input/event0 /dev/fb0 - 永久解决:将应用运行用户加入
input和video组:usermod -aG input,video your_username
内容的提问来源于stack exchange,提问作者Jean-Loup Sabatier
相关产品推荐
相关产品推荐

