Linux input输入子系统
Linux input
更多内容可以查看我的github
Linux输入子系统框架
Linux输入子系统由驱动层、核心层、事件处理层三部分组成。
- 驱动层:输入设备的具体驱动程序,负责与具体的硬件设备进行交互,并将底层的硬件输入转化为统一的事件形式,向核心层发送
- 核心层:连接驱动层和事件处理层,负责对下层提供驱动层借口,向上层提供事件处理接口
- 事件处理层:负责对输入事件进行处理,并将处理结果传递给应用程序
- 层的设备抽象出对应的接口提供给应用层。将底层设备的触发的事件通过这个接口传达给应用层。
核心层的代码在 linux/drivers/input/input.c 中实现
重要结构体
input_dev
这个结构体属于驱动层,描述了一个具体的input设备,记录相关的硬件信息,事件位图等,
struct input_dev {const char *name; // 设备名称struct input_id id; // 设备id,存储输入设备的总线、厂商等信息...unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; // 支持事件类型unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; // 按键位图unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; // 相对位移位图...struct list_head h_list; // 内核链表头struct list_head node; // 内核链表节点
};
Linux设备支持的事件类型:
| 事件类型 | 编码 | 事件描述 |
|---|---|---|
| EV_SYN | 0x00 | 同步事件 |
| EV_KEY | 0x01 | 按键事件(鼠标,键盘等) |
| EV_REL | 0x02 | 相对坐标(如:鼠标移动,报告相对最后一次位置的偏移) |
| EV_ABS | 0x03 | 绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置) |
| EV_MSC | 0x04 | 其它 |
| EV_SW | x05 | 开关 |
| EV_LED | 0x11 | 按键/设备灯 |
| EV_SND | 0x12 | 声音/警报 |
| EV_REP | 0x14 | 重复 |
| EV_FF | x15 | 力反馈 |
| EV_PWR | 0x16 | 电源 |
| EV_FF_STATUS | 0x17 | 力反馈状态 |
| EV_MAX | 0x1f | 事件类型最大个数和提供位掩码支持 |
input_handler
这个结构体属于事件处理层,描述一个事件处理器
struct input_handler {void *private;// 事件处理函数void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);void (*events)(struct input_handle *handle,const struct input_value *vals, unsigned int count);bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);// 设备匹配函数bool (*match)(struct input_handler *handler, struct input_dev *dev);// 设备连接函数,匹配成功后连接int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);void (*disconnect)(struct input_handle *handle);void (*start)(struct input_handle *handle);bool legacy_minors;int minor;const char *name;// 设备支持列表const struct input_device_id *id_table;struct list_head h_list;struct list_head node;
};
input_handle
这个结构体属于核心层,描述一个配对的input设备和input设备处理器
struct input_handle {void *private;int open; // 打开标志const char *name; // 名称struct input_dev *dev;struct input_handler *handler;struct list_head d_node;struct list_head h_node;
};
input_handle_list
struct input_handle_list {struct list_head list;struct input_handle *first;struct input_handle *last;
};
两条重要链表
在 input.c 中,全局维护了两条重要的链表,分别是输入设备链表和事件处理器链表
static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);
总结
上面结构体的链表的关系如下面两图所示(这个图好难画-.-,就在网上找了一个,原文连接)


当我们使用input_register_device()注册一个设备的时候,就会将设备添加到input_dev_list链表中,同时便利input_handler_list进行匹配,匹配成功就会调用input_handler->connect()函数进行连接
事件相关结构体
input_event
事件的输入就是以一个input_event为基本单位的
struct input_event {struct timeval time; /* 事件发生的时间 */__u16 type; /* 事件总类型 */__u16 code; /* 事件子类型 */__s32 value; /* 事件的值 */
};
evdev_client
struct evdev_client {unsigned int head;unsigned int tail;unsigned int packet_head; /* [future] position of the first element of next packet */spinlock_t buffer_lock; /* protects access to buffer, head and tail */struct fasync_struct *fasync;struct evdev *evdev;struct list_head node;int clk_type;bool revoked;unsigned int bufsize;struct input_event buffer[];
};
- head:表示客户端缓冲区中下一个要读取的事件的索引。当客户端从缓冲区读取事件时,它会从 buffer[head] 开始读取,并递增 head 的值。因此,head 指向的是最老的未读取事件的位置。
- tail:表示客户端缓冲区中下一个要写入的事件的索引。当输入事件到达并需要被缓冲时,它将被写入到 buffer[tail] 的位置,并递增 tail 的值。因此,tail 指向的是最新的未写入事件的位置。
实际上,evdev_client 实现了一个环形队列,head是头指针,tail是尾指针,这两个指针都是以 input_event 为单位移动的。
packet_head 与 head 和 tail 不同, 它以数据包(多个input_event)为单位,主要负责记录缓冲区的入口偏移量。
buffer 就是循环队列数组,即缓冲区
所以,根据这些变量我们可以知道,当循环队列满的时候,head = tail;当循环队列空的时候,packet_head = tail。
evdev
struct evdev {int open; // 设备打开计数struct input_handle handle; wait_queue_head_t wait; // 等待队列,没有事件时进程睡眠struct evdev_client __rcu *grab; // 事件响应// 客户端链表,可以有多个进程访问设备struct list_head client_list;spinlock_t client_lock; /* protects client_list */struct mutex mutex;struct device dev;struct cdev cdev;bool exist;
};
总结
- input_event: 表示一个输入事件
- evdev_client: 表示一个用户空间的应用程序或实体设备与输入设备之间的连接
- evdev: 输入设备驱动程序的接口实现,应用程序可以通过evdev与evdev_client之间的交互,实现输入事件的读取和输入
流程
这部分建议阅读源码
在输入设备驱动(input_dev)中,一般通过轮询或者中断方式获取事件的原始值,经过一些处理后,通过input_event()函数将数据上报给核心层(input_core)。
在核心层中,通过input_handle_event()和input_pass_values()对数据进行处理(type、code、value),然后使用input_to_handler()函数将数据上报给事件处理层(input_handler),在input_to_handler()中,使用input_handler结构体中的事件处理函数(event、events、filter)上报,这些函数可以在evdev.c的1235行的evdev_handler中找到。
在事件处理层中,通过evdev_events()和evdev_pass_values()为事件加上时间戳,完成了一个完整的input_event,然后使用__pass_event()将事件传递给用户空间(evdev_client的buffer中)
在__pass_event()中,事件input_event会被填充到evdev_client的buffer中。对于用于空间的应用程序,可以通过read()函数调用内核空间的evdev_read()函数,然后调用evdev_fetch_next_event()函数从环形缓冲区中读取input_event事件
相关文章:
Linux input输入子系统
Linux input 更多内容可以查看我的github Linux输入子系统框架 Linux输入子系统由驱动层、核心层、事件处理层三部分组成。 驱动层:输入设备的具体驱动程序,负责与具体的硬件设备进行交互,并将底层的硬件输入转化为统一的事件形式ÿ…...
dataworks调度参数
概述 调度参数是DataWorks任务调度时使用的参数,调度参数会根据任务调度的业务时间及调度参数的取值格式自动替换取值,实现在任务调度时间内参数的动态取值。 调度参数通过赋值方式分为自定义参数(推荐)和系统内置变量两大类。 …...
JavaScript第五讲:事件,条件循环语句,错误处理
前言 在编程的世界里,事件、条件和循环语句、以及错误处理是构建任何复杂程序或应用的基石。无论是开发一个简单的网页交互,还是构建一个庞大的企业级系统,这些基础概念都扮演着至关重要的角色。今天星途将通过这篇文章,分别深入…...
BrainGPT1,一个帮你b站点歌放视频的多模态多轮对话模型
BrainGPT1,一个帮你b站点歌放视频的多模态多轮对话模型 返回论文目录 项目地址 模型地址 作者:华东师范大学,计算机科学与技术学院,智能教育研究院的小怪兽会微笑。 介绍 BrainGPT1是一个工具调用多轮对话模型,与G…...
带DSP音效处理D类数字功放TAS5805M中文资料
国产替代D类数字功放中文资料访问下方链接 ACM8628 241W立体声182W单通道数字功放中文寄存器表 内置DSP多种音频处理效果ACM8628M-241W立体声或182W单通道数字功放 1 特性 具有增强处理能力和低功率损耗的 TAS5805M 23W、无电感器、数字输入、立体声、闭环 D 类音频放大器 …...
java中BigDecimal的比较
BigDecimal是Java中的一个类,位于java.math包中,它提供了任意精度的有符号十进制数字的表示,以及对这些数字进行算术运算的方法 BigDecimal的主要用途包括: 1.金融计算:金融领域对数值的精度要求非常高,使…...
张大哥笔记:你卖什么,就反着来卖
普通人打工的一生,就是努力工作,买房,买车,送孩子上好的学校,为了孩子不要输在起跑线上,拼命报各种补习班等,这些都是普通人认为的主流价值观文化,也造就了一批批的赚钱机器…...
Nginx(openresty) 开启gzip压缩功能 提高web网站传输速度
1 开启nginx gzip压缩后,网页的图片,css、js等静态资源的大小会减少,节约带宽,提高传输效率,给用户快的体验,给用户更好的体验. 2 安装 #centos 8.5 yum install gzip 3 配置 #建议统一配置在http段 vim /usr/loca…...
nn.Embedding使用
nn.Embedding使用 Embedding.weight会从标准正态分布中初始化成大小为(num_embeddings, embedding_dim)的矩阵 PE矩阵的作用就是替换这个标准正态分布 input中的标号表示从矩阵对应行获取权重来表示单词 # 1.设置embedding结构 max_seq_len 1000 # 句…...
Qt6 mathgl数学函数绘图
1. 程序环境 Qt6.5.1, mingw11.2mathgl 8.0.1: https://sourceforge.net/projects/mathgl/,推荐下载mathgl-8.0.LGPL-mingw.win64.7z,Windows环境尝试自己编译mathgl会缺失一些库,补充完整也可以自己编译,路径"D:\mathgl-8.0.LGPL-mingw.win64\bin"添加至系统环境…...
Nginx配置文件中静态资源文件禁止通过目录查看
Nginx配置文件中静态资源文件禁止通过目录查看 nginx作为文件服务器访问静态资源时,默认是可以通过目录路径查看该目录下的所有文件的,这样会被检查出漏洞,容易造成静态资源泄露。 方案 location /images {autoindex off;autoindex_exact_…...
力扣Hot100-有效的括号(栈stack)
给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括…...
Android下HWC以及drm_hwcomposer普法(上)
Android下HWC以及drm_hwcomposer普法(上) 引言 按摩得全套,错了,做事情得全套,普法分析也是如此。drm_hwcomposer如果对Android图形栈有一定研究的童鞋们应该知道它是Android提供的一个的图形后端合成处理HAL模块的实现。但是在分析这个之前…...
OpenCV学习 基础图像操作(十七):泛洪与分水岭算法
原理 泛洪填充算法和分水岭算法是图像处理中的两种重要算法,主要用于区域分割,但它们的原理和应用场景有所不同,但是他们的基础思想都是基于区域迭代实现的区域之间的划分。 泛洪算法 泛洪填充算法(Flood Fill)是一…...
Docker基础命令(三)
同步docker容器中的时间和本地时间一致 背景: 在很多时候, 训练模型的时候, 记录的log日志中标记的时间和实际的时间不一致, 往往是容器时间和本地时间不一致照成的. 方案 场景一: 正在运行的容器,可以宿主机直接执行命令给某个容器同步时间 #方法1 直接在宿主机…...
Python的第三方库OS库
读者大大们好呀!!!☀️☀️☀️ 🔥 欢迎来到我的博客 👀期待大大的关注哦❗️❗️❗️ 🚀欢迎收看我的主页文章➡️寻至善的主页 文章目录 🔥前言🚀OS/SHUTIL 的方法描述🚀OS/SHUTIL…...
两个数相加减高级实现
不使用实现两数相加 #include <stdio.h> int plus(int a, int b) {int sum0,addication0;while(b!0){sum a^b;addication (a&b)<<1;a sum;b addication;}return a; }不使用-实现两数相减 #include <stdio.h> int sub(int a, int b) {int sum0,abdc…...
小白跟做江科大32单片机之对射式红外传感器计次
原理部分 1中断示意图,中断会打断主函数的执行,终端执行完成之后再返回主函数继续执行 2.STM32中断 这些灰色的是内核中断 这些白色的是普通中断 3.NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组…...
安装Kubernetes v3 ----以docker的方式部署
以docker的方式部署 docker run -d \ --restartunless-stopped \ --namekuboard \ -p 80:80/tcp \ -p 10081:10081/tcp \ -e KUBOARD_ENDPOINT"http://192.168.136.55:80" \ -e KUBOARD_AGENT_SERVER_TCP_PORT"10081" \ -v /root/kuboard-data:/data \ e…...
新游启航 失落的方舟台服注册指南 一文教会你方舟台服注册
新游启航!失落的方舟台服注册指南!一文教会你方舟台服注册 失落的方舟作为本月最受期待游戏之一,在上线之际许多玩家已经有点急不可待了。这款游戏是由开发商Smile gate开发的一款MMORPG类型游戏,这款游戏的基本玩法与其他MMORPG…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
