跳转到正文
知识笔记
通用

Linux Input 事件读取与解析 ​

事件通路 ​

Linux Input 子系统将按键、键盘、鼠标和触摸屏等设备上报的数据组织为输入事件。evdev 接口通过 /dev/input/eventX 向用户空间提供这些事件。

text
输入设备 → 设备驱动 → Input 子系统 → evdev → /dev/input/eventX → 应用程序

设备发现 ​

bash
ls -l /dev/input/
cat /proc/bus/input/devices
grep -E 'Name|Handlers' /proc/bus/input/devices

Name 描述设备,Handlers 列出对应处理器与 event 节点。节点编号可能随注册顺序变化,应先确认映射,不要直接假定 event0 始终为同一设备。

text
N: Name="20cc000.snvs:snvs-powerkey"
H: Handlers=kbd event0

N: Name="goodix-ts"
H: Handlers=event1

N: Name="gpio_keys@0"
H: Handlers=kbd event2

struct input_event 与事件含义 ​

包含 <linux/input.h> 后使用系统提供的 struct input_event,不要自行假定结构体的字节长度或重定义时间字段。

字段含义
time事件时间信息,布局以目标系统头文件为准
type事件类型,如 EV_KEY、EV_REL、EV_ABS、EV_SYN
code类型内的具体编号,如 KEY_ENTER、KEY_POWER、ABS_X
value对应事件值,解释方式取决于 type 和 code

对于 EV_KEY,value 为 0 表示松开,1 表示按下,2 表示自动重复。判断指定按键应同时检查 type 与 code:

c
if (ev.type == EV_KEY && ev.code == KEY_ENTER) {
    if (ev.value == 1) {
        printf("KEY_ENTER pressed\n");
    } else if (ev.value == 0) {
        printf("KEY_ENTER released\n");
    }
}

EV_SYN / SYN_REPORT 标记一组事件的同步边界。一次按下与松开操作可能产生以下事件序列:

text
EV_KEY  KEY_ENTER  1
EV_SYN  SYN_REPORT 0
EV_KEY  KEY_ENTER  0
EV_SYN  SYN_REPORT 0

读取接口与阻塞行为 ​

未设置非阻塞模式时,read() 通常等待事件可读后返回。返回值是字节数;缓冲区足够大时,一次可以接收多个事件。程序应检查错误、零返回和读取长度,再按 sizeof(struct input_event) 解析。

C 语言事件读取示例 ​

以下保留单事件读取示例。运行前将节点改为实际设备,并确认读取权限。示例没有处理所有退出场景;生产代码还应区分 EINTR、设备断开和非阻塞返回。

c
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    int fd;
    ssize_t ret;
    struct input_event ev;

    fd = open("/dev/input/event0", O_RDONLY);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    while (1) {
        ret = read(fd, &ev, sizeof(ev));
        if (ret < 0) {
            perror("read");
            break;
        }

        if (ret != sizeof(ev))
            continue;

        printf("type=%u code=%u value=%d\n",
               ev.type,
               ev.code,
               ev.value);
    }

    close(fd);

    return 0;
}
bash
gcc -Wall -Wextra input_read.c -o input_read
./input_read

输出形式如下,数值用于说明事件含义,不代表目标板的实测日志:

text
type=1 code=28 value=1
type=0 code=0 value=0
type=1 code=28 value=0
type=0 code=0 value=0

验证与常见问题 ​

  • 无输出:确认选择的设备是否产生事件,区分正常阻塞与设备选错。
  • 打开失败:记录错误码,检查节点存在性和权限。
  • 收到多个事件:按结构体大小逐条解析,并使用 SYN_REPORT 确认事件分组。
  • 键值不符:先记录 type、code、value,再确认设备实际使用的按键或坐标编码。

本文说明接口与示例用法,尚未附特定开发板的完整验证日志。实测时应记录设备名称、内核版本、操作动作与对应事件。

参考资料 ​