当前位置: 首页 > news >正文

Linux 输入子系统实战:01设备信息查询程序

前言

本文档从零开始,不仅讲解代码功能,还补充Linux 输入子系统基础二进制位图核心原理位运算详解,并完整复现你实操中遇到的所有错误(编译错误、运行错误、权限错误),让你彻底理解「代码怎么写、数据怎么来、位图怎么解、错在哪、怎么改」。


第一章 前置知识:Linux 输入子系统基础

1.1 一切皆文件

在 Linux 中,键盘、鼠标、触摸屏、电源键等所有输入设备,都被抽象为/dev/input/eventx设备文件。

  • event0:电源键
  • event1:键盘
  • event2/3/4:鼠标操作硬件 = 打开 / 读取这个文件。

1.2 输入事件类型(内核定义)

Linux 内核用EV_XXX定义所有输入事件:

  • EV_SYN:同步事件(通知事件发送完成)
  • EV_KEY:按键事件(键盘、鼠标左键)
  • EV_REL:相对坐标(鼠标移动)
  • EV_ABS:绝对坐标(触摸屏)
  • EV_MSC:杂项事件
  • EV_LED:键盘 LED 灯(大小写灯)
  • EV_REP:长按重复按键

1.3 核心系统调用

  1. open():打开设备文件
  2. ioctl()设备控制专用函数,向内核驱动查询硬件信息
  3. close():关闭文件,释放资源

第二章 完整源码 + 逐行超详细注释

c

运行

// Linux输入子系统核心头文件:定义设备结构体、事件类型、ioctl命令 #include <linux/input.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> // 提供 open() 函数 #include <sys/ioctl.h> // 提供 ioctl() 设备控制函数 #include <stdio.h> // 提供 printf() 打印函数 #include <unistd.h> // 提供 close() 函数,修复文件描述符泄漏 /* * 程序功能:查询输入设备的硬件信息 + 支持的事件类型 * 运行格式:sudo ./01_get_input_info /dev/input/eventx */ int main(int argc, char **argv) { // 变量定义 int fd; // 文件描述符:打开设备后返回的编号 int err; // 存储ioctl函数的返回值(判断是否成功) int len; // 存储内核返回的位图数据长度 int i, bit; // 双层循环计数器 unsigned char byte; // 存储位图的单个字节 struct input_id id; // 内核结构体:存储设备硬件ID(总线/厂商/产品/版本) unsigned int evbit[2]; // 存储【事件位图】的数组:2个int = 8字节 = 64位 // 事件名称数组:和内核EV_XXX宏一一对应,用于打印可读的事件名 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 ", }; // ===================== 1. 参数校验 ===================== if (argc != 2) // argc=参数个数,必须是2(程序名+设备路径) { printf("Usage: %s <dev>\n", argv[0]); return -1; // 参数错误,退出程序 } // ===================== 2. 打开输入设备 ===================== fd = open(argv[1], O_RDWR); // 以读写模式打开设备文件 if (fd < 0) { printf("open %s err\n", argv[1]); return -1; // 打开失败,退出 } // ===================== 3. 查询硬件ID信息 ===================== err = ioctl(fd, EVIOCGID, &id); // EVIOCGID:内核命令 → 获取设备ID if (err == 0) // 调用成功 { printf("bustype = 0x%x\n", id.bustype ); // 总线类型 printf("vendor = 0x%x\n", id.vendor ); // 厂商ID printf("product = 0x%x\n", id.product ); // 产品ID printf("version = 0x%x\n", id.version ); // 设备版本 } // ===================== 4. 查询+解析事件位图 ===================== // EVIOCGBIT(0, size):内核命令 → 获取设备支持的事件类型位图 len = ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit); if (len > 0 && len <= sizeof(evbit)) { printf("support ev type: "); // 第一层循环:遍历位图的【每一个字节】 for (i = 0; i < len; i++) { byte = ((unsigned char *)evbit)[i]; // 取出单个字节 // 第二层循环:遍历字节的【每一位】(0~7) for (bit = 0; bit < 8; bit++) { // 位运算判断:当前位=1 → 支持该事件 if (byte & (1 << bit)) { printf("%s ", ev_names[i*8 + bit]); } } } printf("\n"); } // ===================== 5. 关闭设备文件 ===================== close(fd); // 必须关闭,避免资源泄漏 return 0; }

第三章 核心难点:事件位图 原理 + 逐位详尽解析

3.1 什么是事件位图?(新手必懂)

内核不用字符串告诉程序支持哪些事件,而是用二进制位(bit)

  • 1 个 bit 代表 1 种事件
  • bit = 1→ 设备支持该事件
  • bit = 0→ 设备不支持该事件

3.2 位图数据结构

代码中unsigned int evbit[2]

  • 1 个unsigned int= 4 字节
  • 2 个 =8 字节 = 64 个 bit
  • 64 个 bit → 对应 64 种事件类型

3.3 关键位运算公式(代码核心)

  1. 掩码生成1 << bit→ 把数字 1 左移 bit 位,只保留当前位为 1
  2. 位判断byte & (1 << bit)
    • 结果 ≠ 0 → 当前位是 1(支持事件)
    • 结果 = 0 → 当前位是 0(不支持)
  3. 事件索引i * 8 + bit→ 找到对应事件名称

3.4 你的真实设备位图解析(键盘 event1)

步骤 1:内核返回原始数据

你的键盘返回位图:0x00120007拆分为8 个字节

plaintext

字节0:0x07 字节1:0x00 字节2:0x12 字节3:0x00 字节4:0x00 字节5:0x00 字节6:0x00 字节7:0x00

步骤 2:逐字节逐位拆解


① 字节 0:0x07 → 二进制:0000 0111

表格

位 bit掩码 1<<bit与运算结果是否支持事件索引事件名
00000 00011✅ 是0EV_SYN
10000 00101✅ 是1EV_KEY
20000 01000❌ 否2EV_REL
3~7其他0❌ 否3~7

② 字节 1:0x00 → 二进制:0000 0000

所有位都是 0 →无支持事件


③ 字节 2:0x12 → 二进制:0001 0010

表格

位 bit掩码 1<<bit与运算结果是否支持事件索引事件名
10000 00101✅ 是17EV_LED
40001 00001✅ 是20EV_REP
其他其他0❌ 否其他

④ 字节 3~7:全 0 → 无支持事件

步骤 3:最终打印结果

plaintext

support ev type: EV_SYN EV_KEY EV_MSC EV_LED EV_REP

第四章 完整实操流程 + 你遇到的所有错误汇总

4.1 编译代码(你的错误 + 正确命令)

❌ 错误命令(你实际输入)

bash

运行

gcc- o 01_get_input_info 01_get_input_info.c

❌ 报错信息

plaintext

Command 'gcc-' not found

✅ 错误原因

  1. gcc后面多写了-,命令拼写错误
  2. -o参数格式错误

✅ 正确编译命令

bash

运行

gcc 01_get_input_info.c -o 01_get_input_info

4.2 第一次运行(参数缺失错误)

❌ 错误命令

bash

运行

./01_get_input_info

❌ 报错信息

plaintext

Usage: ./01_get_input_info <dev>

✅ 错误原因

程序必须传入设备路径参数(/dev/input/eventx),未传参直接退出。


4.3 正确运行命令(权限 + 参数齐全)

✅ 命令

bash

运行

sudo ./01_get_input_info /dev/input/event1

✅ 说明

  1. sudo:Linux 硬件设备需要管理员权限
  2. /dev/input/event1:你的键盘设备路径

✅ 你的真实运行结果

plaintext

bustype = 0x11 vendor = 0x1 product = 0x1 version = 0xab41 support ev type: EV_SYN EV_KEY EV_MSC EV_LED EV_REP

第五章 所有常见错误 + 解决方案(完整版)

表格

错误场景报错信息错误原因解决方案
编译错误Command 'gcc-' not foundgcc 命令拼写错误(多了 -)使用正确命令:gcc xxx.c -o xxx
运行错误Usage: ./xxx <dev>未传入设备路径参数运行时加 /dev/input/eventx
权限错误Permission denied普通用户无法访问硬件命令前加 sudo
无数据输出打印为空设备节点选择错误更换 event0/event1/event4
编译警告implicit declaration of ‘close’缺少头文件添加 #include <unistd.h>

第六章 核心知识点总结

  1. 程序逻辑打开设备 → 查询硬件 ID → 查询事件位图 → 位运算解析 → 打印结果
  2. 位图本质用二进制位表示设备能力,是 Linux 内核高效通信的核心设计
  3. 关键命令
    • EVIOCGID:读取硬件 ID
    • EVIOCGBIT:读取事件位图
  4. 实操铁律
    • 编译命令不能写错
    • 运行必须加sudo
    • 必须指定正确的设备路径
  5. 位运算双层循环 +&运算,是解析位图的唯一方法
http://www.jsqmd.com/news/548450/

相关文章:

  • Vue3+Monaco Editor:从零封装一个支持SQL语法与智能提示的代码编辑器
  • Realistic Vision V5.1 虚拟摄影棚:QT开发跨平台AI图像生成桌面应用
  • 大模型微调:教科书级数据工程,200条数据提升170%BLEU!揭秘金融与医疗领域爆款模型的底层逻辑
  • 华大HC32F460芯片FPU配置全攻略:从IAR支持包安装到硬件浮点验证
  • 使用Matlab分析与可视化伏羲模型输出结果
  • Wan2.1-umt5赋能微信小程序:智能对话功能开发全流程
  • 实战演练:基于kimi与快马平台快速开发一个交互式销售数据可视化看板
  • 代码随想录算法训练营第十天|LeetCode 232 用栈实现队列、LeetCode 225 用队列实现栈、LeetCode 20 有效的括号、LeetCode 1047 删除字符串中的所有相邻重复项
  • LabWindows/CVI报错
  • MCMC可视化指南:用动画理解马尔可夫链的收敛过程
  • Java智能地址解析工具address-parse:从混乱文本到结构化数据的终极解决方案
  • OpenClaw+Qwen3.5-9B:自动化竞品监测与分析报告生成
  • 小白也能懂的EmbeddingGemma-300m:用Ollama一键部署嵌入模型
  • 实时手机检测-通用企业应用案例:手机回收站自动分拣系统集成
  • 2026年热门的耐震压力表/隔膜压力表优质供应商推荐(信赖) - 行业平台推荐
  • Windows Cleaner终极指南:3步解决C盘爆红的免费神器!
  • 造相-Z-Image-Turbo亚洲美女LoRA实战:小宇宙播客封面图情绪传达技巧
  • 阿里龙虾悟空体验2:快上手的小助理才是正解
  • Claude Code 使用指南
  • 【latex】探索LaTeX中加粗文本的多种方法及其在表格中的优化应用
  • StructBERT在舆情监控中的应用:实时热点情感分析
  • RMBG-2.0抠图工具性能测试:RTX 3060上平均1.8秒处理一张图
  • 万物识别中文通用领域快速体验:上传图片自动识别,无需技术背景
  • S2-Pro算法优化解析:从LSTM到Transformer的演进与落地实践
  • 终极指南:5步完成黑苹果智能配置工具快速搭建
  • 墙面涂料里的有害物质到底有哪些?
  • 如何用Unity打造一款MMORPG:从零开始的全流程实战教程
  • Cosmos-Reason1-7B科研实操:科研实验视频数据的自动现象标注与推理报告生成
  • AcousticSense AI部署指南:小白也能搭建的音乐分析平台
  • 5步解锁多用户远程桌面:面向家庭与小型团队的RDP Wrapper实用指南