USB子系统学习(四)使用libusb读取鼠标数据
文章目录
- 1、声明
- 2、HID协议
- 2.1、描述符
- 2.2、鼠标数据格式
- 3、应用程序
- 4、编译应用程序
- 5、测试
1、声明
本文是在学习韦东山《驱动大全》USB子系统时,为梳理知识点和自己回看而记录,全部内容高度复制粘贴。
韦老师的《驱动大全》:商品详情
其对应的讲义资料:https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
libusb api:https://libusb.sourceforge.io/api-1.0/libusb_api.html
2、HID协议
HID:Human Interface Devices, 人类用来跟计算机交互的设备。就是鼠标、键盘、游戏手柄等设备。对于USB接口的HID设备,有一套协议。
2.1、描述符
HID设备有如下描述符:

- HID设备的"设备描述符"并无实际意义,没有使用"设备描述符"来表示自己是HID设备。
- HID设备只有一个配置,所以只有一个配置描述符。
- 接口描述符:
- bInterfaceClass为3,表示它是HID设备。
- bInterfaceSubClass是0或1,1表示它支持"Boot Interface"(表示PC的BIOS能识别、使用它),0表示必须等操作系统启动后通过驱动程序来使用它。
- bInterfaceProtocol:0-None, 1-键盘, 2-鼠标。
- 端点描述符:HID设备有一个控制端点、一个中断端点。

对于鼠标,HOST可以通过中断端点读到数据。
2.2、鼠标数据格式
通过中断传输可以读到鼠标数据,它是8字节的数据,格式如下:
| 偏移 | 大小 | 描述 |
|---|---|---|
| 0 | 1字节 | |
| 1 | 1字节 | 按键状态 |
| 2 | 2字节 | X位移 |
| 4 | 2字节 | Y位移 |
| 6 | 1字节或2字节 | 滚轮 |
按键状态里,每一位对应鼠标的一个按键,等1时表示对应按键被点击了,格式如下:
| 位 | 长度 | 描述 |
|---|---|---|
| 0 | 1 | 鼠标的左键 |
| 1 | 1 | 鼠标的右键 |
| 2 | 1 | 鼠标的中间键 |
| 3 | 5 | 保留,设备自己定义bit3: 鼠标的侧边按键bit4: |
X位移、Y位移都是8位的有符号数。对于X位移,负数表示鼠标向左移动,正数表示鼠标向右移动,移动的幅度就使用这个8位数据表示。对于Y位移,负数表示鼠标向上移动,正数表示鼠标向下移动,移动的幅度就使用这个8位数据表示。
3、应用程序
本次应用程序是使用同步接口读取鼠标数据。
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <libusb-1.0/libusb.h>int main(int argc, char **argv)
{int err;libusb_device *dev, **devs;int num_devices;int endpoint;int interface_num;int transferred;int count = 0;unsigned char buffer[8];struct libusb_config_descriptor *config_desc;struct libusb_device_handle *dev_handle = NULL;int found = 0;/* libusb init */err = libusb_init(NULL);if (err < 0) {fprintf(stderr, "failed to initialise libusb %d - %s\n", err, libusb_strerror(err));exit(1);}/* get device list */if ((num_devices = libusb_get_device_list(NULL, &devs)) < 0) // 获取设备描述符列表(函数返回设备描述符数量){fprintf(stderr, "libusb_get_device_list() failed\n");libusb_exit(NULL);exit(1);} fprintf(stdout, "libusb_get_device_list() ok\n");/* for each device, get config descriptor */for (int i = 0; i < num_devices; i++){dev = devs[i];err = libusb_get_config_descriptor(dev, 0, &config_desc); // 获取配置描述符if (err) {fprintf(stderr, "could not get configuration descriptor\n");continue;}fprintf(stdout, "libusb_get_config_descriptor() ok\n");/* parse interface descriptor, find usb mouse */for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) // 枚举所有接口描述符{const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; // 获取配置描述符里的第一个接口描述符interface_num = intf_desc->bInterfaceNumber; // 记录该接口描述符的编号(编号是从0开始)if (intf_desc->bInterfaceClass != 3 || intf_desc->bInterfaceProtocol != 2) // 判断是否是HID设备和是否是鼠标协议continue;/* 找到了USB鼠标 */fprintf(stdout, "find usb mouse ok\n");for (int ep = 0; ep < intf_desc->bNumEndpoints; ep++) // 枚举所有端点描述符{// 判断是否是中断传输,是否是输入端点(输入输出都是以USB Host来讨论,所以该端点是USB Device输出到USB Host)if ((intf_desc->endpoint[ep].bmAttributes & 3) == LIBUSB_TRANSFER_TYPE_INTERRUPT || (intf_desc->endpoint[ep].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN){/* 找到了输入的中断端点 */fprintf(stdout, "find in int endpoint\n");endpoint = intf_desc->endpoint[ep].bEndpointAddress;found = 1;break;}}if (found)break;}libusb_free_config_descriptor(config_desc);if (found)break; }if (!found){/* free device list */libusb_free_device_list(devs, 1);libusb_exit(NULL);exit(1);}/* libusb open */if (found){err = libusb_open(dev, &dev_handle);if (err){fprintf(stderr, "failed to open usb mouse\n");exit(1);}fprintf(stdout, "libusb_open ok\n");}/* free device list */libusb_free_device_list(devs, 1);/* claim interface */libusb_set_auto_detach_kernel_driver(dev_handle, 1); err = libusb_claim_interface(dev_handle, interface_num);if (err){fprintf(stderr, "failed to libusb_claim_interface\n");exit(1);}fprintf(stdout, "libusb_claim_interface ok\n");/* libusb interrupt transfer */while (1){err = libusb_interrupt_transfer(dev_handle, endpoint, buffer, 8, &transferred, 5000); // 发起中断传输,阻塞等待,5s超时时间if (!err) {/* parser data */printf("%04d datas: ", count++);printf("recv datas len = %d\n", transferred);for (int i = 0; i < transferred; i++){printf("%02x ", buffer[i]);}printf("\n");} else if (err == LIBUSB_ERROR_TIMEOUT){fprintf(stderr, "libusb_interrupt_transfer timout\n");} else {const char *errname = libusb_error_name(err);fprintf(stderr, "libusb_interrupt_transfer err : %d, %s\n", err, errname);//exit(1);}}/* libusb close */libusb_release_interface(dev_handle, interface_num);libusb_close(dev_handle);libusb_exit(NULL);
}
4、编译应用程序
假设你的开发板是ubuntu系统:
# 安装libusb库
$ sudo apt install libusb-1.0-0-dev# 编译程序
$ gcc -o readmouse readmouse.c -lusb-1.0
5、测试
将usb鼠标插入开发板:

执行程序:
$ sudo ./readmouse

移动鼠标:

滚轮滑动:

按键状态:

另外,每个鼠标的数据格式是不一样的。以上测试结果只是我使用的鼠标。
相关文章:
USB子系统学习(四)使用libusb读取鼠标数据
文章目录 1、声明2、HID协议2.1、描述符2.2、鼠标数据格式 3、应用程序4、编译应用程序5、测试 1、声明 本文是在学习韦东山《驱动大全》USB子系统时,为梳理知识点和自己回看而记录,全部内容高度复制粘贴。 韦老师的《驱动大全》:商品详情 …...
【产品小白】用户调研的需求是否都采纳?
在用户调研中,并非所有需求都应被直接采纳,而应通过系统分析转化为符合产品战略的有效决策。以下是关键思考框架: 1. 用户需求 ≠ 产品需求 矛盾性:用户个体需求可能相互冲突(如A功能的去留),需…...
软件测试就业
文章目录 2.6 初识一、软件测试理论二、软件的生产过程三、软件测试概述四、软件测试目的五、软件开发与软件测试的区别?六、学习内容 2.7 理解一、软件测试的定义二、软件测试的生命周期三、软件测试的原则四、软件测试分类五、软件的开发与测试模型1.软件开发模型…...
qt部分核心机制
作业 1> 手动将登录项目实现,不要使用拖拽编程 并且,当点击登录按钮时,后台会判断账号和密码是否相等,如果相等给出登录成功的提示,并且关闭当前界面,发射一个跳转信号,如果登录失败&#…...
【RocketMQ】RocketMq之ConsumeQueue深入研究
目录 一:RocketMq 整体文件存储介绍 二:ConsumeQueue 的文件结构 三:ConsumeQueue 写入和查询流程 一:RocketMq 整体文件存储介绍 存储⽂件主要分为三个部分: CommitLog:存储消息的元数据。所有消息都会…...
如今物联网的快速发展对hmi的更新有哪些积极影响
一、功能更加丰富 物联网的快速发展使得 HMI(人机界面)能够连接更多的设备和系统,从而实现更加丰富的功能。例如,通过与传感器网络的连接,HMI 可以实时显示设备的运行状态、环境参数等信息,为用户提供更加…...
linux 性能60秒分析
linux 60秒分析 需要运行的工具是 1、uptime 2、dmesg | tail 3、vmstat 1 4、mpstat -P ALL 1 5、pidstat 1 6、iostat -xz 1 7、free -m 8、sar -n DEV 1 9、sar -n TCP,ETCP 1 10、topuptime 快速检查平均负载 [rootaaaaaa ~]# uptime15:17:20 up 3 days, 14 min, 7 us…...
Redisson全面解析:从使用方法到工作原理的深度探索
文章目录 写在文章开头详解Redisson基本数据类型基础配置字符串操作列表操作映射集阻塞队列延迟队列更多关于Redisson详解Redisson 中的原子类详解redisson中的发布订阅模型小结参考写在文章开头 Redisson是基于原生redis操作指令上进一步的封装,屏蔽了redis数据结构的实现细…...
neo4j-解决导入数据后出现:Database ‘xxxx‘ is unavailable. Run :sysinfo for more info.
目录 问题描述 解决方法 重新导入 问题描述 最近在linux上部署了neo4j,参照之前写的博客:neo4j-数据的导出和导入_neo4j数据导入导出-CSDN博客 进行了数据导出、导入操作。但是在进行导入后,重新登录网页版neo4j,发现对应的数据库状态变…...
51单片机之引脚图(详解)
8051单片机引脚分类与功能笔记 1. 电源引脚 VCC(第40脚):接入5V电源,为单片机提供工作电压。GND(第20脚):接地端,确保电路的电位参考点。 2.时钟引脚 XTAL1(第19脚&a…...
Hangfire.NET:.NET任务调度
引言:为何选择 Hangfire? 在开发.NET 应用程序时,我们常常会遇到这样的场景:应用程序需要定期发送报告,像财务报表,每日业务数据汇总报告等,这些报告需要定时生成并发送给相关人员;…...
深入解析:React 事件处理的秘密与高效实践
在 React 中,事件处理是构建交互式应用的核心。本文将带你深入探索 React 事件处理的机制、最佳实践以及如何避免常见陷阱,助你写出更高效、更健壮的代码。 1. React 事件处理的独特之处 合成事件(SyntheticEvent) React 使用合…...
开源像素字体,可用于独立游戏开发
方舟像素字体 / Ark Pixel Font 开源的泛中日韩像素字体,使用 SIL 开放字体许可证 第1.1版(SIL Open Font License 1.1)授权。 支持 10、12 和 16 像素尺寸。 支持语言特殊字形:中文-中国大陆、中文-香港特别行政区、中文-台湾…...
【论文阅读】Comment on the Security of “VOSA“
Comment on the Security of Verifiable and Oblivious Secure Aggregation for Privacy-Preserving Federated Learning -- 关于隐私保护联邦中可验证与遗忘的安全聚合的安全性 论文来源摘要Introduction回顾 VOSA 方案对VOSA不可伪造性的攻击对于类型 I 的攻击对于类型 II 的…...
了解传输层TCP协议
目录 一、TCP协议段格式 二、TCP原理 1.确认应答 2.超时重传 3.连接管理 建立连接 断开连接 4.滑动窗口 5.流量控制 6.拥塞控制 7.延时应答 8.捎带应答 9.面向字节流 10.TCP异常情况 TCP,即Transmission Control Protocol,传输控制协议。人如…...
flask实现用户名查重,重复的用户名阻止注册,以及如何优化
在 Flask 中实现用户名查重,并阻止重复的用户名进行注册,可以使用数据库(如 SQLite、MySQL、PostgreSQL)存储用户信息,并在注册时检查用户名是否已存在。以下是实现步骤: 1. 安装 Flask 及 SQLAlchemy 确保…...
ASP.NET Core对JWT的封装
目录 JWT封装 [Authorize]的注意事项 JWT封装 NuGet 库 |Microsoft.AspNetCore.Authentication.JwtBearer 9.0.1https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearerhttps://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBea…...
wordpressAI工具,已接入Deepseek 支持自动生成文章、生成图片、生成长尾关键词、前端AI窗口互动、批量采集等
基于关键词或现有内容生成SEO优化的文章,支持多种AI服务(如OpenAI、百度文心一言、智谱AI等),并提供定时任务、内容采集、关键词生成等功能。 核心功能 文章生成 关键词生成:根据输入的关键词生成高质量文章。 内容…...
Ollama部署 DeepSeek-R1:70B 模型的详细步骤
1. 确认环境准备 (1) 硬件要求 显存需求:70B 参数的模型需要大量显存。若使用 NVIDIA T4(16GB 显存),需多卡并行(如 8 卡)或开启量化(如 q4_0、q8_0)。内存需求:建议至…...
PAT乙级( 1009 说反话 1010 一元多项式求导)C语言版本超详细解析
1009 说反话 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过 80的字符串。字符串由若干单词和若干空格组成,其中单词是由英文字母&#x…...
WARPED框架:单目RGB驱动的机器人视觉运动策略学习
1. WARPED框架:单目RGB驱动的机器人视觉运动策略学习新范式在机器人模仿学习领域,如何高效获取高质量的示范数据一直是个核心挑战。传统方法通常需要昂贵的多视角相机阵列、深度传感器或专用硬件设备,这不仅增加了部署成本,更限制…...
终极Windows热键侦探指南:3分钟解决快捷键冲突难题
终极Windows热键侦探指南:3分钟解决快捷键冲突难题 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你是否曾经遇…...
如何高效获取网盘直链:8大平台的完整解决方案
如何高效获取网盘直链:8大平台的完整解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 / 迅…...
PP 蜂窝板挤出成型核心原理与关键设备解析
PP 蜂窝板挤出成型核心原理与关键设备解析一、PP 蜂窝板材料特性与成型难点PP(聚丙烯)蜂窝板兼具质轻、高刚性、耐水防潮、可循环四大优势,在物流、建筑、车厢、包装领域替代传统实心板材趋势明显。 其成型难点集中在:蜂窝芯超薄、…...
基于Helm Chart在Kubernetes中部署docker-mailserver邮件服务器
1. 项目概述与核心价值最近在折腾自建邮件服务器,发现了一个宝藏项目:docker-mailserver。它把邮件服务里那些复杂的组件,比如 Postfix、Dovecot、SpamAssassin、ClamAV 这些,全都打包进了一个 Docker 镜像里,开箱即用…...
实战解析:Python如何一步步解开JWE加密令牌的秘密
1. 认识JWE:加密令牌的守护者 第一次遇到JWE加密令牌时,我完全懵了。作为一个习惯处理普通JWT的后端开发者,发现常用的jwt.io网站居然无法解析这个令牌,就像拿着钥匙却找不到锁孔。JWE(JSON Web Encryption)…...
基于Jina Reader与Exa API的免费网页抓取与搜索工具实践
1. 项目概述:一个轻量级的网络信息抓取与处理工具最近在折腾一些自动化信息处理的项目,发现很多时候需要从网上快速抓取内容或者进行关键词搜索,然后对结果进行结构化处理。市面上的工具要么太重,要么收费,要么就是API…...
别再为本科毕业论文熬大夜!Paperxie 智能写作,一键搞定终稿的正确姿势
paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AI PPThttps://www.paperxie.cn/ai/dissertationhttps://www.paperxie.cn/ai/dissertation 又到了本科毕业论文冲刺的季节,多少同学还在对着空白文档发呆?选题纠结半天定不下来&…...
【Kanzi 资源系统完全笔记】
一、Resource 的类层次结构Kanzi 中所有资源(Resource)都继承自 Object 基类。下图是常见的资源继承体系(根据图片整理):Object└── Resource├── GPUResource # 位于 GPU 显存中的资源(纹理、…...
2016年FPGA市场格局:巨头并购、技术演进与工程师实战指南
1. 2016年FPGA市场格局:一场没有悬念的卫冕战聊起2016年的FPGA市场,就像看一场结局早已注定的体育比赛。赛灵思(Xilinx)毫无悬念地再次登顶年度营收榜首,这已经是它连续十几年稳坐头把交椅了。根本不需要什么复杂的财务…...
