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

Qt 使用RAW INPUT获取HID触摸屏,笔设备,鼠标的原始数据,最低受支持的客户端:Windows XP [仅限桌面应用]

        在开发绘图应用程序时,经常会需要读取笔设备的数据,通过对笔数据的解析,来判断笔的坐标,粗细。如果仅仅只是读取鼠标的坐标,就需要人为在应用程序端去修改笔的粗细,并且使用体验不好,如果可以实时获取到触摸屏的笔数据的话,就可以大大提高体验感。

        获取USB-HID设备的数据,有多种方式

  1. 使用Raw Input API
  2. 使用Windows底层库,如Windows API,Windows HID API
  3. 使用第三方库,如hidapi,libusb等等

        本博文主要分析Raw Input API的操作,官网解析地址:https://learn.microsoft.com/en-us/windows/win32/inputdev/about-raw-input

        从官网的概述可以知道Raw Input API为应用程序提供了一种稳定而可靠的方式,可以接受来自任何 HID(包括键盘和鼠标)的原始输入。

        并且具有这些优点。

Qt使用Raw Input API具体步骤

  1. 注册原始输入
  2. 重写nativeEvent函数
  3. 执行原始输入的标准读取

(解析截自官网)

1.注册原始输入

        为了注册设备,应用程序首先创建 一个 RAWINPUTDEVICE 结构的数组,这些结构为所需的设备指定 顶级集合 (TLC) 。 TLC 由“使用情况页”定义, (设备) 类 (设备) 。 例如,若要获取键盘 TLC,请设置 UsagePage = 0x01 和 UsageID = 0x06。 应用程序调用 RegisterRawInputDevices 来注册设备。

        请注意,应用程序可以注册当前未附加到系统的设备。 附加此设备后,Windows 管理器将自动将原始输入发送到应用程序。 若要获取系统上的原始输入设备列表,应用程序会调用 GetRawInputDeviceList。 应用程序使用此调用中的 hDevice 调用 GetRawInputDeviceInfo 以获取设备信息。

TCL:

Usage Page

HID usages are organized into usage pages of related controls. A specific control usage is defined by its usage page, a usage ID, a name, and a description. A usage page value is a 16-bit unsigned value.

Examples of usage pages include:

Expand table

Page IDPage Namehidusage.h constant
0x01Generic Desktop ControlsHID_USAGE_PAGE_GENERIC
0x05Game ControlsHID_USAGE_PAGE_GAME
0x08LEDsHID_USAGE_PAGE_LED
0x09ButtonHID_USAGE_PAGE_BUTTON

Usage ID

In the context of a usage page, a valid usage identifier, or usage ID, indicates a usage in a usage page. A usage ID of zero is reserved. A usage ID value is an unsigned 16-bit value.

Examples of controls that are listed on the Generic Desktop Controls usage page:

Expand table

Usage IDUsage Namehidusage.h constant
0x01PointerHID_USAGE_GENERIC_POINTER
0x02MouseHID_USAGE_GENERIC_MOUSE
0x04JoystickHID_USAGE_GENERIC_JOYSTICK
0x05Game PadHID_USAGE_GENERIC_GAMEPAD
0x06KeyboardHID_USAGE_GENERIC_KEYBOARD
0x07KeypadHID_USAGE_GENERIC_KEYPAD
0x08Multi-axis ControllerHID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER

bool Dialog::RegisitWindow(HWND hwnd)
{if ( nullptr == hwnd ){return FALSE;}RAWINPUTDEVICE rid[1];rid[0].usUsagePage = 0x0D;rid[0].usUsage = 0x02; // 笔设备rid[0].dwFlags = RIDEV_INPUTSINK;rid[0].hwndTarget = hwnd;if (!RegisterRawInputDevices(rid, 1, sizeof(rid[0]))){return FALSE;}return TRUE;
}

2.重写nativeEvent函数

bool Dialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
{}

3.执行原始输入的标准读取

        应用程序从任何 HID 接收原始输入,其 顶级集合 (TLC) 与注册中的 TLC 匹配。 当应用程序收到原始输入时,其消息队列将获取 WM_INPUT 消息, 并且队列 状态标志QS_RAWINPUT设置为 (QS_INPUT 还包括此标志) 。 应用程序在前台和后台时可以接收数据。

有两种方法可以读取原始数据:无缓冲 (或标准) 方法和缓冲方法。 无缓冲区方法一次获取一个 RAWINPUT 结构的原始数据,并且足以用于许多 HID。 在这里,应用程序调用 GetMessage 以获取 WM_INPUT 消息。 然后,应用程序使用包含在 WM_INPUT 中的 RAWINPUT 句柄调用 GetRawInputData。 有关示例,请参阅 执行原始输入的标准读取。

相比之下,缓冲方法一次获取 RAWINPUT 结构的数组。 这是为可以生成大量原始输入的设备提供的。 在此方法中,应用程序调用 GetRawInputBuffer 来获取 RAWINPUT 结构的数组。 请注意, NEXTRAWINPUTBLOCK 宏用于遍历 RAWINPUT 结构的数组。 有关示例,请参阅 执行原始输入的缓冲读取。

若要解释原始输入,需要有关 HID 的详细信息。 应用程序通过使用设备句柄调用 GetRawInputDeviceInfo 来获取设备信息。 此句柄可以来自 WM_INPUT,也可以来自 RAWINPUTHEADER 的 hDevice 成员。

bool Dialog::nativeEvent(const QByteArray &eventType, void *message, long *result)
{MSG* msg = (MSG*)message;LPBYTE lpb;RAWINPUT* raw;UINT dwSize;if(msg->message == WM_INPUT){GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));lpb = new BYTE[dwSize];if (lpb == nullptr) {qDebug() << "内存分配失败。";return false;}if (GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) {qDebug() << "GetRawInputData 返回的大小不正确!";delete[] lpb;return false;}raw = (RAWINPUT*)lpb;if (raw->header.dwType == RIM_TYPEHID) {qDebug() << "接收到 HID 输入。";//在这里可以使用raw->data.hid.bRawData解析数据。}delete[] lpb;}return false;
}

相关文章:

Qt 使用RAW INPUT获取HID触摸屏,笔设备,鼠标的原始数据,最低受支持的客户端:Windows XP [仅限桌面应用]

在开发绘图应用程序时&#xff0c;经常会需要读取笔设备的数据&#xff0c;通过对笔数据的解析&#xff0c;来判断笔的坐标&#xff0c;粗细。如果仅仅只是读取鼠标的坐标&#xff0c;就需要人为在应用程序端去修改笔的粗细&#xff0c;并且使用体验不好&#xff0c;如果可以实…...

easyexcel导出excel文件到s3服务器

导出excel文件是开发中常见的需求 常见的做法一般是直接通过请求接口响应对象HttpServletResponse把文件输出 我们可以使用原生的poi工具类操作.也可以使用easypoi.easyexcel等基于poi二次封装的工具处理 下面是代码 /*** 导出列表** param request* param response*/Overri…...

xss.haozi.me靶场“0x0B-0x12”通关教程

君衍. 一、0x0B 实体编码绕过二、0x0C script绕过三、0x0D 注释绕过四、0X0E ſ符号绕过五、0x0F 编码解码六、0x10 直接执行七、0x11 闭合绕过八、0x12 闭合绕过 XSS-Labs靶场“1-5”关通关教程 XSS-Labs靶场“6-10”关通关教程 Appcms存储型XSS漏洞复现 XSS-Labs靶场“11-13、…...

linux--redhat系统Yum源配置

1&#xff09;说明 redhat yum命令使用报错解决-重新配置yum源 解决--更改yum源 2&#xff09;更改yum源 &#xff08;1&#xff09;进入源目录 cd /etc/yum.repos.d/ &#xff08;2&#xff09;备份 redhat 默认源 mv redhat.repo redhat.repo-bak &#xff08;3&#xff09;…...

el-Switch 开关二次确认

前言 最近在做毕设&#xff0c;有个需求是点击按钮控制用户的状态是否禁用&#xff0c;就看到element有个switch组件可以改造一下&#xff0c;就上网看了一下&#xff0c;结果为了这个效果忙活了很久。。。所以说记录一下&#xff0c;让大家少踩坑。 前置条件 先看完我的需求再…...

(二)丶RabbitMQ的六大核心

一丶什么是MQ Message Queue(消息队列&#xff09;简称MQ&#xff0c;是一种应用程序对应用程序的消息通信机制。在MQ中&#xff0c;消息以队列形式存储&#xff0c;以便于异步传输&#xff0c;在MQ中&#xff0c;发布者&#xff08;生产者&#xff09;将消息放入队列&#xff…...

微信小程序实现上下手势滑动切换

效果图 思路 实现一个微信小程序的复合滚动页面&#xff0c;主要通过Swiper组件实现垂直方向的轮播功能&#xff0c;每个轮播项内部使用Scroll-View组件来展示可垂直滚动的长内容&#xff0c;如图片和文本。 代码 <!-- wxml --> <view class"swiper-container…...

详解命令docker run -d --name container_name -e TZ=Asia/Shanghai your_image

docker run 是Docker的主要命令&#xff0c;用于从镜像启动一个新的容器。下面详细解释并举例说明 -d, --name, -e TZ 参数的用法&#xff1a; -d 或 --detach&#xff1a; 这个标志告诉Docker以守护进程&#xff08;后台&#xff09;模式运行容器。这意味着当你执行 docker ru…...

javaEE7

1. <% page pageEncoding"UTF-8"%><% page import"java.io.*"%> <% page import"java.util.*"%> <% page import"java.math.*"%> <html> <head><title>网站计数器</title></head&…...

int与integer的区别

int和integer都是用来表示整数的数据类型&#xff0c;但有一些细微的区别。 int是Java中的基本数据类型&#xff0c;它可以存储整数值。int类型在内存中占4个字节&#xff0c;范围为-2,147,483,648到2,147,483,647。int类型使用最频繁&#xff0c;因为它的存储空间较小&#x…...

Golang实现Redis分布式锁(Lua脚本+可重入+自动续期)

Golang实现Redis分布式锁&#xff08;Lua脚本可重入自动续期&#xff09; 1 概念 应用场景 Golang自带的Lock锁单机版OK&#xff08;存储在程序的内存中&#xff09;&#xff0c;分布式不行 分布式锁&#xff1a; 简单版&#xff1a;redis setnx》加锁设置过期时间需要保证原…...

音乐播放器-C#实现

音乐播放器-C#实现 目录 一、 代码介绍 二、 音乐播放器-C#实现 三、 音乐播放器-C#实现 四、 音乐播放器-C#实现 五、 音乐播放器-C#实现 代码介绍 代码中使用了.NET框架中的System.Media命名空间来处理音频文件的播放和控制。这段代码创建了一个简单的音乐播放器界…...

如何本地搭建hMailServer邮件服务

文章目录 前言1. 安装hMailServer2. 设置hMailServer3. 客户端安装添加账号4. 测试发送邮件5. 安装cpolar6. 创建公网地址7. 测试远程发送邮件8. 固定连接公网地址9. 测试固定远程地址发送邮件 前言 hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpola…...

裸机编程的几种模式、架构与缺陷。

大多数嵌入式的初学者都是从单片机裸机编程开始的&#xff0c;对于初学者来说&#xff0c;裸机编程更加直观、简单&#xff0c;代码所见及所得&#xff0c;调试也非常方便&#xff0c;区别于使用操作系统需要先了解大量的操作系统基础知识&#xff0c;调度的基本常识&#xff0…...

TSINGSEE青犀视频AI方案:数据+算力+算法,人工智能的三大基石

背景分析 随着信息技术的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐渗透到我们生活的各个领域&#xff0c;从智能家居到自动驾驶&#xff0c;从医疗诊断到金融风控&#xff0c;AI的应用正在改变着我们的生活方式。而数据、算法和算力&#xff0c;正是构成…...

Linux认识与学习BASH

Linux认识与学习BASH 认识BASH这个Shellshell是什么系统的合法shell与/etc/shells功能Bash Shell的功能查询命令是否为Bash shell 的内置命令(type)命令的执行与快速编辑按钮 shell的变量功能什么是变量&#xff1f;变量的使用与设置&#xff1a;echo、变量设置规则、unset环境…...

Python JSON 序列化以及反序列化 文件读写

Python JSON 序列化以及反序列化 JSON (JavaScript Object Notation) 是一种轻量级的文本数据存储格式。JSON 数据通常存储在字符串中&#xff0c;即JSON字符串&#xff0c;其实就是一字符串&#xff0c;只是带有一定的格式&#xff0c;可以被解析。本文使用的 Python 版本为3…...

Spring MVC 返回JSON数据

1. 前置准备 1.1 导入jackson依赖 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.0</version> </dependency>1.2 添加json数据转化器 EnableWebMvc …...

前端基础——HTML傻瓜式入门(1)

该文章Github地址&#xff1a;https://github.com/AntonyCheng/html-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…...

【AI】如何创建自己的自定义ChatGPT

如何创建自己的自定义ChatGPT 目录 如何创建自己的自定义ChatGPT大型语言模型(LLM)GPT模型ChatGPTOpenAI APILlamaIndexLangChain参考推荐超级课程: Docker快速入门到精通Kubernetes入门到大师通关课本文将记录如何使用OpenAI GPT-3.5模型、LlamaIndex和LangChain创建自己的…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...