文章目录

  • 虚拟HID设备
    • 1. HID架构
    • 2. HID接口函数
      • 2.1 Device Discovery and Setup
      • 2.2 Data Movement
      • 2.3 Report Creation and Interpretation
    • 3. 虚拟设备
      • 3.1 HidRegisterMinidriver
      • 3.2 IRP_MJ_INTERNAL_DEVICE_CONTROL
      • 3.3 效果

虚拟HID设备

对于HID设备的虚拟化,主要包括:

  1. 虚拟化鼠标。
  2. 虚拟化键盘。
  3. 虚拟化触摸板(手写笔)。

本文我们来探讨上述HID设备虚拟化的基本实现原理(关于HID设备的虚拟化,需要了解HID描述符相关基础知识,可以参见另外一篇文章:关于HID描述符)。

1. HID架构

在Windows下面HID的基本架构如下:

HID Clients包括有驱动,服务以及应用程序,他们都和HIDClass.sys进行通信;通常来说每一次通信的对象都是一个指定的设备(例如键盘,鼠标等)。通常通过hardware ID或者HID Collection来标识一个设备,通过通信遵循如下规则:

  • 用户模式驱动或者应用程序通过HIDClass提供的HidD_xxx来获取HID Collection。
  • 内核驱动或者用户驱动以及应用程序通过HID分析支持程序HidP_xxx,内核驱动程序使用HID 类驱动的IOCTL来处理HID报表。
Mode Drivers Applications
User Mode HidD_Xxx HidP_Xxx
Kernel Mode HidD_Xxx
IOCTL_HID_xxx
N/A

HID Transport是具体的硬件设备,我们HID Transport向上提供硬件相关信息,HID Client从来不主动和HID Transport直接通信,都是通过HIDClass.sys来进行中转的,这样给我们HID Client和HID Transport的开发都带来了非常大的便利;这也是Windows MiniPort驱动实现的基本框架。

对于HID的设备的虚拟,我们主要是需要实现HID Transport。

2. HID接口函数

Windows提供了如下的HID函数接口来或者和操作HID设备:

  1. Device Discovery and Setup。
  2. Data Movement。
  3. Report Creation and Interpretation。

2.1 Device Discovery and Setup

API 描述
HidD_GetAttributes 请求获得HID设备的厂商ID、产品ID和版本号
HidD_GetHidGuid 请求获得HID设备的GUID
HidD_GetIndexString 请求获得由索引识别的字符串
HidD_GetManufactureString 请求获得设备制造商字符串
HidD_GetPhysicalDescriptor 请求获得设备实体字符串
HidD_GetPreparsedData 请求获得与设备能力信息相关的缓冲区的代号
HidD_GetProductString 请求获得产品字符串
HidD_GetSerialNumberString 请求获得产品序列号字符串
HidD_GetNumInputBuffer 获得驱动程序用于存储输入报表的环形缓冲区的大小,默认值是8
HidD_SetNumInputBuffer 设置驱动程序用于存储输入报表的环形缓冲区的大小

2.2 Data Movement

API 描述
HidD_GetInputReport 从设备读取一个特征报表
HidD_SetFeature 向设备传送一个特征报表
HidD_SetOutputReport 向设备传送输出报表
WriteFile 向设备传送输出报表
ReadFile 从设备读取输入报表

2.3 Report Creation and Interpretation

API 描述
HidP_GetButtonCaps 请求获得HID报表中所有按钮的能力
HidP_GetButtons 从设备读取包含每个按下的按钮的用法(Usage)的缓冲区的指针,该请求可以设定一个Usage Page
HidP_GetButtonEx 从设备读取包含每个按下的按钮的Usage和Usage Page的缓冲区的指针
HidP_GetCaps 请求获得用于描述设备能力的结构的指针
HidP_GetLinkCollectionNotes 请求获得描述在顶层集合中的连接集合(Link Collection)关系的结构的数组
HidP_GetSpecificButtonCaps 请求获得报表中按钮的能力,该请求可以设定一个Usage Page、Usage或是Link Collection
HidP_GetSpecificValueCaps 请求获得报表中数值的能力,该请求可以设定一个Usage Page、Usage或是Link Collection
HidP_GetValueCaps 请求获得 HID 报表中所有数值的能力
HidP_MaxUsageListLength 请求获得 HID 报表中可以回传的按钮的最大数目,该请求可以设定一个Usage Page
HidP_UsageListDifference 比较两个按钮列表,并且求出在一个列表中设定而在另一个列表中没有设定的按钮
HidP_GetScaledUsageValue 从设备读取一个已经经过比例因子调整的有符号数值
HidP_GetUsageValue 从设备读取一个指向数值的指针
HidP_GetUsageValueArray 从设备读取包含多个数据项的Usage的数据
HidP_SetButtons 向设备传送设置按钮的数据
HidP_SetScaledUsageValue 将一个实际数值转换成设备使用的逻辑数值,并将其插入到报表中
HidP_SetUsageValue 向设备传送数据
HidP_SetUsageValueArray 向设备传送包含多个数据项的Usage的数据

3. 虚拟设备

3.1 HidRegisterMinidriver

对于一个HID的Miniport硬件驱动来说,都是通过HidRegisterMinidriver函数来完成注册的,这个函数是HIDClass.sys提供,也就是说HIDClass.sys提供了框架,给我们MiniPort驱动的开发。

对于HidRegisterMinidriver工作大致可以总结为如下:

  1. IoAllocateDriverObjectExtension创建驱动的上下文HIDCLASS_DRIVER_EXTENSION
  2. 保存MiniPort驱动的相关信息到HIDCLASS_DRIVER_EXTENSION结构中,如下:
RtlCopyMemory(hidDriverExtension->MajorFunction,minidriverObject->MajorFunction,sizeof( PDRIVER_DISPATCH ) * (IRP_MJ_MAXIMUM_FUNCTION + 1) );minidriverObject->DriverUnload = HidpDriverUnload;hidDriverExtension->AddDevice = driverExtension->AddDevice;

3.2 IRP_MJ_INTERNAL_DEVICE_CONTROL

对于HID的虚拟硬件设备,对上层实现的接口都是通过IRP_MJ_INTERNAL_DEVICE_CONTROL来提供的,HID需要实现的相关IOCTL如下:

//
// Internal IOCTLs for the class/mini driver interface.
//#define IOCTL_HID_GET_DEVICE_DESCRIPTOR             HID_CTL_CODE(0)
#define IOCTL_HID_GET_REPORT_DESCRIPTOR             HID_CTL_CODE(1)
#define IOCTL_HID_READ_REPORT                       HID_CTL_CODE(2)
#define IOCTL_HID_WRITE_REPORT                      HID_CTL_CODE(3)
#define IOCTL_HID_GET_STRING                        HID_CTL_CODE(4)
#define IOCTL_HID_ACTIVATE_DEVICE                   HID_CTL_CODE(7)
#define IOCTL_HID_DEACTIVATE_DEVICE                 HID_CTL_CODE(8)
#define IOCTL_HID_GET_DEVICE_ATTRIBUTES             HID_CTL_CODE(9)
#define IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST    HID_CTL_CODE(10)

我们知道HID最重要的两个描述符是:

  1. HID设备描述符。HID设备描述符通过IOCTL_HID_GET_DEVICE_DESCRIPTOR向上层提供。
  2. HID报表描述符。HID报表描述符通过IOCTL_HID_GET_REPORT_DESCRIPTOR向上层提供。

其他操作包括IOCTL_HID_READ_REPORT实现用来读取报表描述符,IOCTL_HID_WRITE_REPORT用来写入报表描述符。

这里我们需要定义两个描述符,例如可以定义如下:

HID_REPORT_DESCRIPTOR           DefaultReportDescriptor[] = {0x06,0x00, 0xFF,                // USAGE_PAGE (Vender Defined Usage Page)     0x09,0x01,                          // USAGE (Vendor Usage 0x01)      0xA1,0x01,                           // COLLECTION (Application)        0x85,CONTROL_FEATURE_REPORT_ID,           // REPORT_ID (1)                      0x09,0x01,                          // USAGE (Vendor Usage 0x01)              0x15,0x00,                          // LOGICAL_MINIMUM(0)                   0x26,0xff, 0x00,                // LOGICAL_MAXIMUM(255)               0x75,0x08,                          // REPORT_SIZE (0x08)                     0x95,0x01,                          // REPORT_COUNT (0x01)                    0xB1,0x00,                          // FEATURE (Data,Ary,Abs)0x09,0x01,                          // USAGE (Vendor Usage 0x01)              0x75,0x08,                          // REPORT_SIZE (0x08)                     0x95,INPUT_REPORT_BYTES,           // REPORT_COUNT (0x01)                    0x81,0x00,                      // INPUT (Data,Ary,Abs)0xC0                                // END_COLLECTION                       };HID_DESCRIPTOR              DefaultHidDescriptor = {0x09,   // length of HID descriptor0x21,   // descriptor type == HID  0x210x0100, // hid spec release0x00,   // country code == Not Specified0x01,   // number of HID class descriptors{ 0x22,   // report descriptor type 0x22sizeof(DefaultReportDescriptor) }  // total length of report descriptor
};

3.3 效果

通过实现相关的HID硬件特性之后,我们可以虚拟化如下HID设备:

并且我们可以直接操作虚拟化的驱动来模拟各种HID设备信息,如下我们利用虚拟HID键盘向系统开始菜单输入一个Hello:

如何在串流云桌面中实现外设的远程控制输入——HID人机接口设备驱动简介(键鼠、手写板等)相关推荐

  1. 虚拟桌面分屏_桌面中的灭霸 三星C49HG90 32:9超带鱼屏体验

    本文作者:dpgisdpg 前言 参加一起Show桌面活动,顺便搞定之前未做的三星C49HG90DMC显示器开箱作业. 搭建一套美如画的桌面,工程堪比"复仇者联盟",不但需要足够的 ...

  2. 全球主流云桌面传输协议

    转载:https://zhuanlan.zhihu.com/p/40351781 ⚽ 2018年世界杯都来了,你还在看几年前的云桌面传输协议文章吗?来看新鲜出炉的! 上期我们谈到了影响云桌面性能的三个 ...

  3. 痞子衡嵌入式:理解i.MXRT中FlexSPI外设lookupTable里配置访问行列混合寻址Memory的参数值...

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT中FlexSPI外设lookupTable里配置访问行列混合寻址Memory的参数值. 关于 FlexSPI 外设的 loo ...

  4. 云桌面VOI计算存储在服务器端,云桌面中VOI架构有什么优势和劣势?

    原标题:云桌面中VOI架构有什么优势和劣势? VOI架构是和信下一代云桌面的核心亮点之一,也是其区别于市面上大多数云桌面的核心价值所在.但正如单一VDI架构云桌面有明显的优劣势一样,单一的VOI架构云 ...

  5. usb禁止重定向_远程桌面中的USB重定向技术解析(功能篇)

    在运行远程和虚拟桌面的数据中心内,网络管理员可以对计算环境的各个方面进行控制.只有一点除外,就是本地外围设备. 本地外围设备包括所有连接到终端上的设备,例如USB驱动器.鼠标或打印机.它们逐渐成为终端 ...

  6. 远程桌面中Tab键不能补全的解决办法

    我们曾在之前的一篇文章中介绍了windows远程连接ubuntu的方法,在成功登陆远程桌面环境之后,发现在终端中Tab键不能自动补齐(但是Ctrl +Tab 可以用,但是需要按下组合键才能补全的话,时 ...

  7. centos桌面进入服务器,解决如何在centos7桌面中打开终端_网站服务器运行维护

    如何解决在Centos中NAT无法上网_网站服务器运行维护 在Centos中NAT无法上网的解决方法:首先将网络设置为"DHCP"自动获取IP:然后查看主机的相关服务是否开启:最后 ...

  8. 并联串联混合的电压和电流_串、并联电路中的电流与电压规律

    在电学的学习中,串.并联电路中的电流与电压规律以及欧姆定律是我们解电路的理论基础,所以串.并联电路的电流与电压规律的重要性不言而喻.但往往有一些同学将这些结论记的岔三落四,更别提应用了.所以每年学习至 ...

  9. 在WINDOWS SERVER 上或远程桌面中使用 MUTEX

    引用: http://www.cnblogs.com/fg0711/archive/2012/05/03/2480502.html 使用Mutex需要注意的两个细节 可能你已经注意到了,例子中在给Mu ...

最新文章

  1. Python:机器视觉与Tesseract介绍
  2. 中南大学c语言上机考试题库,中南大学C++题库之选择题
  3. 一步一步学习VirtualBox安装CentOS7和CentOS8
  4. 什么叫做“假学习”?什么叫做“真学习”?
  5. 基于层次过滤的文本生成
  6. 数据规则列表加导入导出
  7. 网站开发中很有用的几个 jQuery 地图插件
  8. 【HASH】【UVA 10125】 Sumset
  9. Spring项目启动后报连接MYSQL错误两则
  10. [渝粤教育] 陕西国防工业职业技术学院 Android开发 参考 资料
  11. 【数据分析认知课(一):数据分析思维观】——读后感
  12. 比较两个文本差异,直接显示两个文本的相同点与不同点
  13. python免安装版使用
  14. 保持初心,不负韶华||回顾2021,展望2022
  15. 多目标优化——帕累托最优Pareto
  16. 向量正交 与 函数正交
  17. 如何删除“我的电脑”、“此电脑”中坚果云图标
  18. 我国南极泰山站正式建成开站
  19. OSChina 周四乱弹 —— 放过巧克力熊吧,待久了都变抹茶熊了
  20. 预警神器来了,天翼大喇叭发出河道防汛强音

热门文章

  1. 辉煌优配|热门科技股“一波三折” 三大股指延续分化
  2. 信管专业毕业生的尴尬
  3. Filter映射和过滤器
  4. 美国国家网络安全综合纲领
  5. Bootstrap框架基础入门
  6. 故人西辞黄鹤楼,烟花三月下扬州
  7. 如何成为一名iOS开发高手
  8. 在javascript 用foreach遍历列表数据进行循环
  9. java虚拟机-简单概述(五月的仓颉)
  10. 转:做一个会听的人:移情、理解、再沟通