一、第 1 节:输入系统核心框架(7.1-7.2)—— 统一管理所有输入设备
1.1 核心概念:输入设备 vs 输入系统
- 输入设备:键盘、鼠标、触摸屏、摇杆等,用户和系统交互的硬件
- 输入系统:Linux 为统一管理所有输入设备设计的框架,在驱动层和应用层都做了统一
- 驱动层:把不同硬件的输入,转换成统一的
input_event事件 - 应用层:用统一的 API 读取事件,不用关心底层硬件差异
- 驱动层:把不同硬件的输入,转换成统一的
1.2 输入系统分层架构(面试必背)
![]()
用户空间:APP(直接读/dev/input/eventX) / tslib / libinput 内核空间: ├─ 输入系统事件层(input event handlers):evdev_handler(最常用) ├─ 输入系统核心层(input core):承上启下,分发事件 └─ 输入系统驱动层(drivers):鼠标、键盘、触摸屏等硬件驱动 硬件层:鼠标、键盘、触摸屏等输入设备- 核心数据流程(APP 读 /dev/input/event0 为例):
- APP 发起
read操作,无数据则休眠 - 用户操作硬件,产生中断
- 驱动层处理中断,读取数据,封装成
struct input_event上报给核心层 - 核心层通过
evdev_handler把事件存入内核 buffer,唤醒等待的 APP - APP 读取
input_event,处理输入
- APP 发起
1.3 核心结构体(笔试必写)
当输入设备被操作(如按键按下、鼠标移动等),驱动程序会捕获这些操作并将其封装为
input_event结构体。这些事件被放入一个队列中,等待应用程序读取
1.struct input_event:输入事件的核心载体
// include/uapi/linux/input.h struct input_event { struct timeval time; // 事件发生时间(秒+微秒) __u16 type; // 事件类型(EV_KEY/EV_REL/EV_ABS等) __u16 code; // 事件代码(具体哪个键/哪个轴) __s32 value; // 事件值(按下/松开、坐标值、压力值等) }; struct timeval { __kernel_time_t tv_sec; // 秒 __kernel_suseconds_t tv_usec; // 微秒 };type(事件类型)核心宏(面试必背):
宏 含义 适用设备 EV_SYN同步事件 所有设备(标记一组数据结束) EV_KEY按键事件 键盘、按键、触摸屏按下 EV_REL相对位移事件 鼠标(相对坐标) EV_ABS绝对位移事件 触摸屏(绝对坐标) EV_MSC其他杂项事件 辅助信息 EV_SW开关事件 开关类设备
char *ev_names[] = { "EV_SYN ", "EV_KEY ", "EV_REL ", "EV_ABS ", "EV_MSC ", "EV_SW ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "NULL ", "EV_LED ", "EV_SND ", "NULL ", "EV_REP ", "EV_FF ", "EV_PWR ", };code(事件代码)核心宏:
EV_KEY类:KEY_0~KEY_9、KEY_A~KEY_Z、BTN_TOUCH(触摸屏按下)EV_REL类:REL_X/REL_Y(鼠标相对坐标)EV_ABS类:ABS_X/ABS_Y(触摸屏绝对坐标)、ABS_PRESSURE(压力值)、多点触摸相关宏(ABS_MT_SLOT/ABS_MT_TRACKING_ID等)
value(事件值):
- 按键:
0= 松开,1= 按下,2= 长按 - 坐标:触摸屏的 X/Y 坐标值、鼠标的相对位移
- 压力:触摸屏的按压压力值
- 按键:
2.struct input_id:设备唯一标识
struct input_id { __u16 bustype; // 总线类型(USB/I2C/SPI等) __u16 vendor; // 厂商ID __u16 product; // 产品ID __u16 version; // 版本号 };3.事件边界(事件之间的界线)
APP 怎么知道它已经读到了完整的数据?
- 应用程序通过读取一系列
input_event结构体来获取完整的输入数据。驱动程序在上报一系列相关事件后,会上报一个“同步事件”,其type、code和value字段均为0,表示一组相关事件上报完毕。 - 应用程序通过检测同步事件来确定何时读取到了完整的数据
1.4 调试技巧(嵌入式开发必备)
1. 确定输入设备节点
- 查看设备节点:
ls /dev/input/* -l或ls /dev/event* -l - 查看设备对应硬件:
cat /proc/bus/input/devices- 输出中
Handlers=kbd event1表示:该键盘对应/dev/input/event1 B:位图:表示设备支持的事件类型(如EV=b表示支持EV_SYN/EV_KEY/EV_ABS)
- 输出中
其中:
I: 设备ID (struct input_id)
这个字段的四个值对应的是 /usr/include/linux/input.h 中的 input_id 结构体。
- bustype 表示总线类型。
- vendor 表示与厂商相关的ID。
- product 表示与产品相关的ID。
- version 表示版本ID。
N: 设备名称 (Name)
&nbs