Linux Input子系统1(基于Linux6.6)---基础介绍
一、Linux中的input子系统介绍
Linux中的input子系统是负责处理各种输入设备(如键盘、鼠标、触摸屏、游戏控制器等)与操作系统之间交互的核心部分。它是Linux内核中负责抽象和管理输入设备的一个子系统,能够处理不同类型的硬件输入,提供统一的接口,使得各种输入设备能够在不同的硬件平台和驱动程序之间进行兼容。
1.1、Input子系统的组成
-
Input事件接口: Input子系统通过标准的事件接口 (
/dev/input/eventX) 提供输入设备的状态和事件数据。每当设备发生状态变化时,它会通过该接口将事件传递给用户空间程序(例如,X服务器或图形界面)。 -
设备驱动: 各种输入设备(如键盘、鼠标、触摸板等)有各自的驱动程序,负责与硬件进行交互,并将硬件生成的输入事件传递到Linux内核的输入子系统中。驱动程序通常在内核空间中工作。
-
输入事件类型: 输入事件是由设备驱动生成的,通常包括几种类型,例如:
EV_KEY:按键事件(例如,键盘上的按键按下或释放)。EV_ABS:绝对值事件(例如,鼠标的位置或触摸屏上的触摸点位置)。EV_REL:相对值事件(例如,鼠标的移动)。EV_SYN:同步事件,标记输入设备的状态更新。EV_MSC:额外的控制事件,例如中断、滚轮等。
-
设备模型: Input子系统与Linux设备模型紧密集成,输入设备通过设备模型中的节点与内核及用户空间进行通信。每个输入设备都会在内核中创建一个
input_dev结构体,它包含了该设备的信息、状态和输入事件的处理函数。
1.2、输入设备的分类
- 按键设备:如键盘、按键板等,负责按键事件的输入。
- 相对设备:如鼠标、触控板、触摸屏等,这些设备提供相对位置信息(例如,鼠标的移动距离)。
- 绝对坐标设备:例如触摸屏、绘图板等设备,它们提供的是屏幕上的绝对位置。
- 游戏设备:如游戏手柄、飞行摇杆等,通常包括多个按钮和控制轴(如X、Y坐标)。
1.3、输入事件流
在Linux中,输入事件流大致分为以下几个阶段:
-
硬件生成输入事件: 输入设备(如键盘、鼠标)产生一个物理事件,比如按键被按下或鼠标位置发生变化。
-
设备驱动处理事件: 输入设备的驱动程序接收这些硬件事件,并将它们转换为标准化的输入事件(例如
EV_KEY,EV_REL,EV_ABS等)。驱动程序通过内核的input subsystem将这些事件传递到系统中。 -
内核中断和事件分发: 内核的输入子系统会将这些事件转发到相应的输入设备节点。例如,当鼠标移动时,
input_event()函数会被调用,并将该事件放入相应的事件队列。 -
用户空间处理事件: 用户空间的程序(例如X Window系统、Wayland、图形界面或其他应用程序)通过读取
/dev/input/eventX设备节点,获取这些事件并进行处理。例如,X服务器通过这些事件来处理键盘输入和鼠标操作。
1.4、与用户空间的交互
-
设备文件: 输入设备通常暴露为
/dev/input/eventX设备文件(X为设备编号)。用户空间程序可以通过读取这些文件来获取输入事件。常见的输入设备文件包括:/dev/input/event0:第一个输入设备。/dev/input/mouse0:鼠标设备。/dev/input/kbd:键盘设备(在某些系统中可能会使用)。
程序可以通过标准的文件IO接口(
open(),read(),close()等)读取事件数据。例如,X Window系统通过读取/dev/input/eventX来获得键盘或鼠标的输入事件。 -
输入事件接口: 每个输入设备会暴露一个事件接口,用户空间程序可以从中读取事件数据。通过
ioctl()系统调用,程序可以查询设备的特性(如支持的事件类型、键值等),以及控制设备的行为。
1.5、Input子系统的配置和管理
-
xinput命令: 在Linux桌面环境中,xinput是一个常用的工具,允许用户配置和管理输入设备。它可以列出所有已识别的输入设备、查看设备的属性、禁用或启用某些设备等。 -
udev设备管理器:udev是Linux下的设备管理器,负责动态管理设备节点。它为输入设备提供了自动化的配置功能,如在设备插入时自动加载适当的驱动、创建设备文件、设置设备权限等。 -
Input事件调试: 可以使用
evtest工具来调试和测试输入设备。通过evtest,你可以查看输入设备的原始事件,帮助诊断硬件问题或调试驱动程序。
1.6、常见的输入设备驱动
- 键盘驱动(
atkbd,psmouse等):这些驱动程序负责处理传统键盘和鼠标的输入。 - 触摸屏驱动(
ft5x_ts,evdev等):这些驱动程序处理触摸屏等设备的输入。 - 游戏控制器驱动(
joydev,xpad等):这些驱动程序负责管理游戏控制器(如游戏手柄、飞行摇杆等)的输入。
Linux input 子系统将一个输入设备的输入过程分成了设备驱动(input device driver)和事件驱动(input event driver)两个层。前者负责从底层硬件采集数据;后者负责与用户程序接口,将采集到的数据分发给不同的用户接口。通过这样的设计,将千差万别的设备统一到了为数不多的几种驱动接口上。同一种事件驱动可以用来处理多个同类设备;同一个设备也可以和多种事件驱动相衔接。而事件驱动和设备驱动则由输入核心层进行连接,匹配。
上:输入事件驱动层 (打包数据,面向应用)
中:输入核心层 (向下提供注册接口,向上给具体的hander发送数据)
下:输入设备驱动层 (底层驱动,面向硬件)
二、举例分析
应用程序使用input子系统的核心是,对驱动层打包好的数据进行分析。其中打包的数据结构如下:
/*
* The event structure itself
*/
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
一个设备驱动可能对应两个设备驱动,比如鼠标既可以对应mouse,也可以对应event。
event事件设备驱动程序是通用的,可以包括所有类型的输入设备,也是目前的主流,我们就以它为例分析。
应用层操作驱动有2条路:/dev目录下的设备文件,/sys目录下的属性文件。两个效果是一样的,用那个都可以。

2.1、应用举例
先写一个简单的应用程序。
其作用是,读电脑鼠标的数据并打印出来。
#include <linux/input.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define INPUT_MOUSE "/dev/input/event3" /* 电脑的键盘 */
#define INPUT_KEY "/dev/input/event1" /* 电脑的鼠标 */
int main(void)
{
int fd = -1, ret = -1;
struct input_event ev;
fd = open(INPUT_MOUSE , O_RDONLY); /* 打开鼠标的设备文件 */
if(fd < 0)
{
perror("open");
return -1;
}
while(1)
{
memset(&ev, 0, sizeof(struct input_event));
ret = read(fd, &ev, sizeof(struct input_event)); /* 读鼠标(会阻塞) */
if(ret != sizeof(struct input_event))
{
perror("read");
close(fd);
return -1;
}
/* 打印读到的键值 */
printf("--------------------\n");
printf("type = %u.\n", ev.type);
printf("code = %u.\n", ev.code);
printf("value = %u.\n", ev.value);
}
return 0;
}
下面是移动打印出来的数据。
--------------------
type = 2. /* 相对坐标设备(鼠标) */
code = 0. /* x轴 */
value = 1. /* 位移方向 */
--------------------
type = 2. /* 相对坐标设备(鼠标) */
code = 1. /* y轴 */
value = 1. /* 位移方向 */
--------------------
type = 0. /* 同步包 */
code = 0.
value = 0.
--------------------
type = 2.
code = 0.
value = 1.
--------------------
type = 2.
code = 1.
value = 1.
--------------------
type = 0.
code = 0.
value = 0.

2619

被折叠的 条评论
为什么被折叠?



