如何实现抓取/dev/input/event#事件、替换后写入并取消抓取?
解决触摸屏事件拦截与修改的正确方案
你的核心问题在于错误地尝试将修改后的事件写回原输入设备,这违背了Linux输入子系统的设计逻辑。原输入设备是硬件事件的来源,修改后的事件应该通过虚拟输入设备(uinput)发送,同时通过EVIOCGRAB独占原设备,确保原始事件不会流向桌面。
正确流程步骤
- 以RDWR权限打开目标触摸屏设备(
/dev/input/event#),调用ioctl(fd, EVIOCGRAB, 1)独占设备,此时所有原始触摸事件只会被你的程序读取,不会传递到桌面。
- 以RDWR权限打开目标触摸屏设备(
- 循环读取原设备的事件:
- 若事件不需要修改,直接丢弃(因设备已被独占,事件不会流出)。
- 若需要修改,调整事件的
value或其他字段后,准备通过uinput发送。
- 初始化uinput虚拟设备:
- 打开
/dev/uinput(部分系统路径为/dev/input/uinput)。 - 通过
ioctl复制原触摸屏的事件类型(如EV_ABS、EV_KEY)、轴信息(如ABS_X、ABS_Y的范围)等属性,确保虚拟设备与原设备输入能力一致。 - 调用
ioctl(fd_uinput, UI_DEV_CREATE)创建虚拟设备。
- 将修改后的事件写入uinput设备,每次事件组结束后必须发送
EV_SYN类型的SYN_REPORT事件,通知系统处理该组输入。
- 将修改后的事件写入uinput设备,每次事件组结束后必须发送
- 程序退出时,先调用
ioctl(fd_uinput, UI_DEV_DESTROY)销毁虚拟设备,再取消原设备的抓取(ioctl(fd, EVIOCGRAB, 0))并关闭文件描述符。
- 程序退出时,先调用
关键代码片段示例
初始化uinput设备(复制原设备属性)
int setup_uinput(int original_fd) { int uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); if (uinput_fd < 0) return -1; // 复制原设备的事件位掩码 unsigned long evbit[EV_MAX/8 + 1] = {0}; ioctl(original_fd, EVIOCGBIT(0, EV_MAX), evbit); ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN); for (int i = 0; i < EV_MAX; i++) { if (evbit[i/8] & (1 << (i%8))) { ioctl(uinput_fd, UI_SET_EVBIT, i); // 复制ABS事件的轴范围 if (i == EV_ABS) { struct input_absinfo absinfo; for (int j = 0; j < ABS_MAX; j++) { if (ioctl(original_fd, EVIOCGABS(j), &absinfo) == 0) { ioctl(uinput_fd, UI_SET_ABSBIT, j); ioctl(uinput_fd, UI_SET_ABSINFO, &absinfo); } } } } } // 设置虚拟设备名称与总线类型 struct uinput_setup setup = {0}; strcpy(setup.name, "Modified Touchscreen"); setup.id.bustype = BUS_USB; ioctl(uinput_fd, UI_DEV_SETUP, &setup); ioctl(uinput_fd, UI_DEV_CREATE); return uinput_fd; }
发送修改后的事件
void send_modified_event(int uinput_fd, struct input_event *ev) { // 写入修改后的事件 write(uinput_fd, ev, sizeof(struct input_event)); // 发送同步事件触发系统处理 struct input_event syn = {0}; syn.type = EV_SYN; syn.code = SYN_REPORT; syn.value = 0; write(uinput_fd, &syn, sizeof(struct input_event)); }
原有方案失效原因
- 用
EVIOCGRAB独占原设备时,该设备的所有事件(包括你写入的)都会被程序的read调用捕获,无法传递到桌面。 - 若先取消抓取再写入原设备,设备独占状态解除后,系统会恢复处理原设备事件流,写入的新事件会和后续原始事件一同流向桌面,导致输入混乱。
内容的提问来源于stack exchange,提问作者Thai Nguyen
相关产品推荐
相关产品推荐

