人体学接口设备 (HID)

news2024/11/22 6:13:43

参考链接

windows-hardware drivers hid | Microsoft Learnicon-default.png?t=N7T8https://learn.microsoft.com/pdf?url=https%3A%2F%2Flearn.microsoft.com%2Fzh-cn%2Fwindows-hardware%2Fdrivers%2Fhid%2Ftoc.json人体学接口设备 (HID) 简介 - Windows drivers | Microsoft Learnicon-default.png?t=N7T8https://learn.microsoft.com/zh-cn/windows-hardware/drivers/hid/

windows-hardware drivers hid | Microsoft Learnicon-default.png?t=N7T8https://learn.microsoft.com/pdf?url=https%3A%2F%2Flearn.microsoft.com%2Fzh-cn%2Fwindows-hardware%2Fdrivers%2Fhid%2Ftoc.json

特此记录

anlog

2023年8月30日

告知我们有关下载 PDF 体验的信息。 人体学接口设备 (HID) 简介 项目 • 2023/06/15 人体学接口设备 (HID) 是一个设备类定义,用于将 PS/2 样式的连接器替换为支持 HID 设 备(例如键盘、鼠标、游戏控制器等)的通用 USB 驱动程序。 在 HID 之前,设备只能对 鼠标和键盘使用严格定义的协议。 硬件创新要求使用现有协议重载数据,或使用其自己 的专用驱动程序创建非标准硬件。 HID 为这些“启动模式”设备提供了支持,同时通过可扩 展、标准化且易于编程的接口添加对硬件创新的支持。 目前,HID 设备包括各种设备,例如字母数字显示器、条码读取器、扬声器/耳机上的音 量控制、辅助显示器、传感器等。 许多硬件供应商还对其专用设备使用 HID。 HID 一开始为 USB,但设计为与总线无关。 它为低延迟、低带宽设备而设计,但可以灵 活地指定基础传输中的速率。 1996 年,基于 USB 的 HID 的规范被 USB-IF 批准。不久 之后,对其他传输的支持又获得批准。 有关当前支持的传输的详细信息,可参阅 Windows 中支持的 HID 传输。 此外,还允许通过自定义传输驱动程序进行特定于供应商 的第三方传输。 HID 包含两个基本概念:“报告描述符”和“报告”。 报告是在设备和软件客户端之间交换的 实际数据。 报告描述符描述设备支持的数据的格式和含义。 应用程序和 HID 设备通过报告来交换数据。 有三种报告类型: 报告类型 说明 输入报告 从 HID 设备发送到应用程序的数据,通常在控件的状态发生更改时发送。 输出报告 从应用程序发送到 HID 设备(例如键盘上的 LED)的数据。 功能报告 可以手动读取和写入的数据,通常与配置信息相关。 报告描述符中定义的每个顶级集合可能包含每个类型的零个或更多个报告。 USB-IF 工作组发布的 HID 用法表是描述允许哪些 HID 设备执行操作的报告描述符的组 成部分。 这些 HID 用法表包含一个对用法进行了描述的列表,描述报告描述符中所述的 特定项目的预期含义和用法。 例如,为鼠标左键定义了用法。 报告描述符可以定义应用 HID 概念 报表 用法表 程序在报告中的何处能够找到鼠标左键的当前状态。 用法表分为多个称为“用法页”的命 名空间。 每个用法页描述了一组相关的用法,有助于组织文档。 将用法页和用法组合起 来,就可以定义用法 ID,该 ID 可唯一标识用法表中的特定用法。 USB-IF HID 规范 请参阅 HID 体系结构 项目 • 2023/06/15 Windows 中的 HID 驱动程序堆栈的体系结构基于名为 hidclass.sys 的类驱动程序。 客户 端和传输微型驱动程序从用户模式或内核模式访问类驱动程序。 系统提供的 HID 类驱动程序是 HID 设备设置类的 WDM 函数驱动程序和总线驱动程序 (HIDClass) 。 HID 类驱动程序的可执行组件 hidclass.sys。 HID 类驱动程序是 HID 客户端 和各种传输之间的粘附点。 这允许 HID 客户端以独立于传输方式编写。 此抽象级别允许 客户端在引入新标准或第三方传输时继续 (,) 几乎不需要修改。 下面是体系结构表示形式。 上图包括以下内容: HID 客户端 – 标识 Windows 和第三方客户端及其接口。 HID 类驱动程序 HID 类驱动程序 - hidclass.sys 可执行文件。 HID 传输微型驱动程序 - 标识 Windows 和第三方传输及其接口。 下面是通用 HID 客户端和传输的设备堆栈关系图。 下面是另一个设备堆栈示意图,其中显示了 USB 上 HID 键盘和鼠标集合。 HID 客户端是与 HIDClass.sys 通信的驱动程序、服务或应用程序,通常表示特定类型的设 备 (,例如传感器、键盘、鼠标等) 。 它们通过硬件 ID 或特定的 HID 集合标识设备,并 通过以下指南与 HID 集合通信。 用户模式驱动程序和应用程序以及内核模式驱动程序执行以下操作来操作 HID 集合: 用户模式驱动程序和应用程序使用 HIDClass 支持例程 (HidD_Xxx) 获取有关 HID 集 合的信息。 内核模式驱动程序、用户模式驱动程序和应用程序使用 HID 分析支持例程 (HidP_Xxx) ,而内核模式驱动程序使用 HID 类驱动程序 IOCTL 来处理 HID 报告。 下表简化了上面列出的信息。 模式 驱动程序 应用程序 用户模式 HidD_Xxx HidP_Xxx 内核模式 HidD_Xxx 或 IOCTL_HID_xxx 空值 有关详细信息,请参阅 打开 HID 集合。 Windows 支持以下顶级集合: 使用情 况页 使用情 况 Windows 7 Windows 8 Windows 10 备注 访问模式 0x0001 0x0001 - 0x0002 是 是 是 鼠标类驱动程 序和映射器驱 动程序 排他 0x0001 0x0004 - 0x0005 是 是 是 游戏控制器 共享 0x0001 0x0006 - 0x0007 是 是 是 键盘/键盘类驱 动程序和映射 器驱动程序 排他 0x0001 0x000C 否 是 是 飞行模式开关 共享 0x0001 0x0080 是 是 是 系统控件 (电 源) 共享 HID 客户端 Windows 中支持的 HID 客户端 使用情 况页 使用情 况 Windows 7 Windows 8 Windows 10 备注 访问模式 0x000C 0x0001 是 是 是 (适用于 Windows 10 和 Windows 10 移 动版) 使用者控件 共享 (适用于 Windows 10和 Windows 10 移 动版) 0x000D 0x0001 是 是 是 外部笔设备 排他 0x000D 0x0002 是 是 是 集成笔设备 排他 0x000D 0x0004 是 是 是 触摸屏 排他 0x000D 0x0005 否 是 是 精密触摸板 (PTP) 排他 0x0020 *多个 否 是 是 传感器 共享 0x0084 0x0004 是 是 是 HID UPS 电池 共享 0x008C 0x0002 否 是 (Windows 8.1 及更 高版本) 是 条形码扫描仪 (hidscanner.dll) 共享 在上表中,输入 HID 客户端的访问模式是 独占 的,以防止其他 HID 客户端在不是该输入 的目标接收者时截获或接收全局输入状态。 出于安全原因,原始输入管理器 (RIM) 以独 占方式打开所有此类设备。 如果设备由 RIM 以 独占 模式打开,则用户仍然可以在不请求读取和写入权限的情况下打 开 HID 设备接口,并通过 HIDClass 支持例程 (HidD_GetXxx) 获取 HID 设备信息。 共享模式允许多个应用程序访问设备。 例如,多个应用程序可以访问条形码扫描仪来查 询设备功能和检索统计信息。 但是,从条形码扫描仪检索解码的数据是在 独占 模式下完 成的。 使用情况由 USB-IF 使用情况表 定义。 *多个:0x00中的传感器使用情况 - 0xFF出于不同目的细分。 例如,0x10指示生物识别传 感器;0x40指示光传感器。 这些分配不是连续的。 有关传感器用法的列表,请参阅 HID 的 USB-IF 设备类定义 。 有关 Windows 中支持的传感器使用情况的信息,请参阅 HID 传感器使用情况。 HID 类驱动程序旨在使用 HID 微型驱动程序访问硬件输入设备。 HID 微型驱动程序抽象 化它支持的输入设备的特定于设备的操作。 HID 微型驱动程序通过向 HID 类驱动程序注 册,将其操作绑定到 HID 类驱动程序。 HID 类驱动程序通过调用微型驱动程序的支持例 HID 传输驱动程序 程与 HID 微型驱动程序进行通信。 HID 微型驱动程序反过来又将通信发送到基础总线或 端口驱动程序的驱动程序堆栈。 有关支持的 HID 传输的列表,请参阅 此页 。 Windows 硬件实验室工具包中的 USB 通用 HID 测试 (HLK) 涵盖 HidUsb 和 HidClass 驱 动程序。 第三方 HID 微型驱动程序没有 HLK 测试。 Windows 中支持的 HID 传输方式 HID 应用程序编程接口 (API) 项目 • 2023/06/15 HID API 分为三类:设备发现和设置、数据移动和报表创建/解释。 这些 HID API 用于标识 HID 设备的属性并与该设备建立通信。 应用程序使用这些 API 来 标识顶级集合。 HidD_GetAttributes HidD_GetHidGuid HidD_GetIndexedString HidD_GetManufacturerString HidD_GetPhysicalDescriptor HidD_GetPreparsedData HidD_GetProductString HidD_GetSerialNumberString HidD_GetNumInputBuffers HidD_SetNumInputBuffers 这些 HID API 用于在应用程序和所选设备之间移动数据。 HidD_GetInputReport HidD_SetFeature HidD_SetOutputReport ReadFile WriteFile 自定义硬件的开发人员知道其设备发出的每个报告的大小和格式。 在这种情况下,应用 程序可以将输入和输出报表缓冲区强制转换为结构并使用数据。 旨在与公开常见功能的所有设备的 HID 应用程序的开发人员 (例如,必须检测何时按下播 放按钮的音乐应用程序,) 可能不知道 HID 报告的大小和格式。 此类别的应用程序了解 某些顶级集合和某些用法。 设备发现和设置 数据移动 报表创建和解释 若要解释从设备收到的报表或创建要发送的报表,应用程序必须利用报告描述符来确定特 定使用情况在报表中是否位于以及位置, (可能) 报表中的值单位。 在这些情况下,需要 HID 分析。 Windows 提供 HID 分析程序,供驱动程序和应用程序通过 API (HidP_*) 使 用,可用于发现设备支持的用法类型、在报表中确定此类用法的状态,或生成报表以更改 设备中的使用情况状态。 这些是 HID 分析程序 API。 HidP_GetButtonCaps HidP_GetButtons HidP_GetButtonsEx HidP_GetCaps HidP_GetData HidP_GetExtendedAttributes HidP_GetLinkCollectionNodes HidP_GetScaledUsageValue HidP_GetSpecificButtonCaps HidP_GetSpecificValueCaps HidP_GetUsages HidP_GetUsagesEx HidP_GetUsageValue HidP_GetUsageValueArray HidP_GetValueCaps HidP_InitializeReportForID HidP_IsSameUsageAndPage HidP_MaxDataListLength HidP_MaxUsageListLength HidP_SetButtons HidP_SetData HidP_SetScaledUsageValue HidP_SetUsages HidP_SetUsageValue HidP_SetUsageValueArray HidP_UnsetButtons HidP_UnsetUsages HidP_UsageAndPageListDifference HidP_UsageListDifference HID 客户端概述 项目 • 2023/06/14 人机接口设备 (HID) 客户端是使用 HID API 进行通信的驱动程序、服务或应用程序,通常 表示特定类型的设备,例如传感器、键盘或鼠标。 设备由硬件 ID 或特定的 HID 集合标 识,并通过 HID API 进行通信。 主题 说明 HID 用法 HID 用法 标识 HID 控件的预期用途以及控件实际度量的内容。 HID 集合 HID 集合是 HID 控件及其各自的 HID 用法的有意义的分组 打开 HID 集合 本部分介绍 HID 客户端如何与 HID 类驱动程序通信, (HIDClass) 来操作设备的 HID 集合。 处理 HID 报告 本部分介绍用户模式应用程序和内核模式驱动程序用于处理 HID 报告的机制 释放资源 HID 客户端的用户模式应用程序和内核模式驱动程序应始终释放不再需要的任何 资源。 安装 HID 客户 端 本部分介绍在 Microsoft Windows 中安装 HIDClass 设备的以下要求。 顶级集合的 HIDClass 硬件 ID 本部分指定 HID 类驱动程序为顶级集合生成的硬件 ID。 键盘和鼠标 HID 客户端驱 动程序 本主题讨论键盘和鼠标 HID 客户端驱动程序。 键盘和鼠标表示第一组 HID 客户 端,这些客户端已在 HID 使用情况表中标准化并在 Windows 操作系统中实现。 传感器 HID 类 驱动程序 从 Windows 8 开始,Windows 操作系统包括一个内置传感器 HID 类驱动程序 (SensorsHIDClassDriver.dll) ,它支持使用 HID 传输进行通信的 11 种传感器类 型。 飞行模式无线 管理 从 Windows 8 开始,Windows 操作系统通过 HID 为飞行模式无线电管理控件提 供支持。 显示器亮度控 制 从Windows 8开始,添加了标准化解决方案,允许键盘 (外部或嵌入笔记本电脑) ,通过 HID 控制笔记本电脑或平板电脑的屏幕亮度。 HID 用法 项目 • 2023/06/15 HID 用法 标识 HID 控件的预期用途以及控件实际度量的内容。 WDK 的 HID 文档中使用以下概念和术语: 使用情况页 用法 ID 扩展使用情况 使用范围 别名用法 有关 Windows 组件访问的用法的特定示例,请参阅 Windows 为系统使用打开的顶级集 合。 有关如何确定 HIDClass 设备支持的用法的详细信息,请参阅: 集合功能 按钮功能数组 值功能数组 解释 HID 报告 有关行业标准 HID 用法的详细信息,请参阅 USB 实施者论坛 网站上的通用串行总线 (USB) 规范 HID 使用情况表。 HID 用法组织到相关控件的 使用情况页 中。 特定控件用法由其使用页、 使用 ID、名称 和说明定义。 使用情况页值是 16 位无符号值。 使用情况页的示例包括: 页面 ID 页面名称 hidusage.h 常量 0x01 通用桌面控件 HID_USAGE_PAGE_GENERIC 0x05 游戏控件 HID_USAGE_PAGE_GAME 使用情况页 页面 ID 页面名称 hidusage.h 常量 0x08 LED HID_USAGE_PAGE_LED 0x09 Button HID_USAGE_PAGE_BUTTON 在使用情况页的上下文中,有效的使用情况标识符或 使用情况 ID 指示使用情况页中的使 用情况。 保留使用 ID 为零。 使用情况 ID 值是无符号 16 位值。 通用桌面控件使用情况页上列出的控件示例: 用法 ID 用法名称 hidusage.h 常量 0x01 指针 HID_USAGE_GENERIC_POINTER 0x02 鼠标 HID_USAGE_GENERIC_MOUSE 0x04 游戏杆 HID_USAGE_GENERIC_JOYSTICK 0x05 游戏板 HID_USAGE_GENERIC_GAMEPAD 0x06 Keyboard HID_USAGE_GENERIC_KEYBOARD 0x07 键盘 HID_USAGE_GENERIC_KEYPAD 0x08 多轴控制器 HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER 扩展用法是一个 32 位值,该值指定一个 16 位使用情况页值(以最有效两个字节为单 位)和一个 16 位使用情况 ID(以扩展使用值的最小有效两个字节为单位)。 使用范围是一个非独占的连续使用 ID 范围,所有这些 ID 都位于同一使用情况页上。 使 用范围由报表描述符中的使用量最小值和使用量最大项指定。 可以为 链接集合 或 HID 控件指定多个用法。 对于给定的集合或控件,一组此类用法是 彼此的别名,称为 别名用法。 分隔符项用于指定别名用法。 不能对使用范围 进行别名 化。 用法 ID 扩展使用情况 使用范围 别名用法 有关如何在顶级集合的功能数组中指定别名用法的信息,请参阅 按钮功能数组 和 值功能 数组。 HID 集合概述 项目 • 2023/06/15 HID 集合是 HID 控件及其各自的 HID 用法的有意义的分组。 如果控件在逻辑上相关或功能上相互依赖,则应组合在一起。 例如,键盘上的 SHIFT 键 和字母键不应属于单独的集合。 集合可以有嵌套的 子集合,也称为 链接集合。 报表描 述符定义一个或多个 顶级集合,与每个集合关联的报表项定义一个或多个 HID 报表。 Windows 扩展了 HID 集合的概念,包括以下内容: 顶级集合 由 Windows 打开以供系统使用的顶级集合 预先分析的数据 链接集合 收集功能 按钮功能数组 值功能数组 数据索引 顶级集合 项目 • 2023/06/15 顶级集合是针对特定软件使用者 (或功能使用者类型) 的功能分组。 例如,顶级集合可以 描述为键盘、鼠标、使用者控制、传感器、显示等。在 HID 规范中,这些顶级集合也称 为 应用程序集合。 HID 设备描述了每个顶级集合的用途,以便允许 HID 功能的使用者识 别他们可能感兴趣的顶级集合。 在 Windows 中,HID 设备设置类 (HIDClass) 为报表描述 符描述的每个顶级集合生成唯一的物理设备对象 (PDO) 。 Microsoft 将 顶级集合 定义为 不嵌套在另一个 集合中的 HID 集合。 无论其 HID 类型如何,未引入的集合始终是顶级集 合。 具体而言,顶级集合不必是 应用程序 集合,如 USB HID 标准版所定义。 一个报表描述符可以包含多个顶级集合。 HID 类驱动程序枚举输入设备的顶级集合,并 为每个顶级集合 (PDO) 创建物理设备对象。 用户模式应用程序或内核模式驱动程序可以 通过打开其 PDO 并使用 HIDClass 支持例程 和 HID 类驱动程序 IOCTL 来访问顶级集合。 下面介绍了顶级集合的内部结构和功能: HIDP_CAPS结构总结了顶级集合的功能。 链接集合 描述顶级集合中包含的嵌套子集合的组织。 按钮功能数组 和 值功能数组 描述了顶级集合支持的控件的功能。 由 Windows 打开供系统使用的顶级集合 项目 • 2023/06/15 Windows 将打开以下 顶级集合 供系统使用: “使用情况”页 用法 ID 设备类型 访问模式 0x0001 0x0001 - 0x0002 鼠标 排他 0x0001 0x0004 - 0x0005 游戏控制器 共享 0x0001 0x0006 - 0x0007 Keyboard 排他 0x0001 0x000C 飞行模式开关 共享 0x0001 0x0080 系统控件 (电源) 共享 0x000C 0x0001 使用者控件 共享 0x000D 0x0001 外部笔设备 排他 0x000D 0x0002 集成笔设备 排他 0x000D 0x0004 触摸屏 排他 0x000D 0x0005 精密触摸板 (PTP) 排他 0x0020 *多个 传感器 共享 0x0084 0x0004 HID UPS 电池 共享 0x008C 0x0002 条形码扫描仪 共享 *多个:0x00中的传感器使用情况 - 0xFF出于不同目的细分。 例如,0x10指示生物识别传 感器;0x40指示光传感器。 这些分配不是连续的。 有关传感器用法的列表,请参阅 HID 的 USB-IF 设备类定义 。 有关 Windows 中支持的传感器使用情况的信息,请参阅 HID 传感器使用情况。 预分析的数据 项目 • 2023/06/15 预先分析的数据 是与 顶级集合关联的报表描述符数据。 用户模式应用程序或内核模式驱 动程序使用预先分析的数据来提取有关特定 HID 控件的信息,而无需获取和解释设备的 整个报告描述符。 用户模式应用程序使用 HidD_GetPreparsedData 获取集合的预分析数 据,而内核模式驱动程序使用 IOCTL_HID_GET_COLLECTION_DESCRIPTOR 请求。 以下 HIDClass 支持例程 支持提取和设置按钮和值数据: HidP_GetButtons HidP_SetButtons HidP_UnsetButtons HidP_GetUsageValue HidP_SetUsageValue HidP_GetScaledUsageValue HidP_SetScaledUsageValue HidP_GetUsageValueArray HidP_SetUsageValueArray 链接集合 项目 • 2023/06/14 作为顶级集合中的嵌套子集合的链接集合。 顶级集合可以有零个或多个链接集合。 HidP_GetLinkCollectionNodes 返回顶级集合 的链接集合数组 ,其中包含有关顶级集合 的链接集合的信息。 链接集合数组描述顶级集合中包含的所有链接集合。 每个链接集合都由 HIDP_LINK_COLLECTION_NODE 结构表示。 数组的链接节点以一种在顶级集合中标识其 顺序和分层顺序的方式进行链接。 链接集合数组的第一个元素表示顶级集合,其余成员 表示顶级集合的链接集合。 通过跟踪链接连接数组中的节点,用户模式应用程序或内核模式驱动程序可以确定顶级集 合中所有链接集合的组织和使用情况。 此外,应用程序或驱动程序可以按其链接集合来 组织控件。 这是可能的,因为顶级集合的 按钮功能数组 和 值功能数组 标识包含功能数 组描述的每个 HID 用法 的链接集合。 下图显示了包含四个链接集合的顶级集合的示例。 如上图所示,链接集合按从上到下和从左到右的顺序 (ABCD) 链接在一起。 下表指示,对 于示例中的每个链接集合,顶级集合与其链接集合之间的链接。 链接节点 Parent 子女 First Child 下一个同级 A 顶级集合 B、C B 无 B A D D C C A 无 无 无 D B 无 无 无 链接集合数组 在链接集合数组中,以下定义保留: 父级:链接集合的 父 级是集合自上而下层次结构中紧邻其上方的集合。 链接集合 有一个父级。 链接节点的 Parent 成员指定其父级在链接集合数组中的索引。 子级:链接集合是其父项的 子 级。 父级可以有零个或多个子级。 链接节点的 NumberOfChildren 成员指定父节点具有的子级数。 兄弟姐妹:父母的子女是 兄弟姐妹。 下一个同级:兄弟姐妹按从左到右的顺序排序。 兄弟姐妹的 下一个兄弟 姐妹是紧 邻其右侧(如果有的话)在一组兄弟姐妹中。 链接集合节点的 NextSibling 成员指 定链接集合数组中下一个同级节点的索引。 如果链接集合节点没有下一个同级节 点, 则 NextSibling 设置为零。 第一个子级: 第一个子级 是一组同级中最左边的同级。 链接集合节点的 FirstChild 成员指定其链接集合数组中第一个子级的索引。 如果链接集合节点没有子节点, 则 FirstChild 设置为零。 应用程序或驱动程序可以确定父集合的所有子级,从父级的第一个子级开始,通过第一个 子级的同级排序,直到同级节点的 NextSibling 成员为零。 以下代码演示如何使用链接集合节点索引来查找链接集合 7 的第一个子级: C++ 可以在报表描述符中使用分隔符项来分隔一组 别名集合。 每个别名集合都由别名链接集 合节点表示。 一组完整且唯一的 n, n>=2,别名节点按以下方式链接在一起: 别名节点在链接集合数组中按连续顺序排列。 前 n-1 个节点的 IsAlias 成员设置为 TRUE。 紧跟此类序列 的第 n 个节点将其 IsAlias 成员设置为 FALSE。 此节点终止别名节点的序列。 与此节点关联的用法是 首选用法。 应用程序或驱动程序可以通过重复递增链接集合数组的数组索引来查找此类序列来确定哪 些集合具有别名。 HIDP_LINK_COLLECTION_NODE Collection[10] ; HIDP_LINK_COLLECTION_NODE Node1 ; Node1 = Collection[Collection[7].FirstChild]; 别名集合 按钮功能数组 和 值功能数组 针对它们描述的每个用法标识包含使用情况的链接集合。 如果链接集合为别名,则功能数组将指定首选用法。 收集功能 项目 • 2023/06/15 集合的功能由其使用情况、报表、链接集合和控件定义。 为了获取集合功能摘要,用户 模式应用程序或内核模式驱动程序调用 HidP_GetCaps 以获取 *HIDP_CAPS 结构。 此结 构包含以下有关集合 的链接集合、 按钮功能数组和 值功能数组的信息: 集合的 使用情况页 和 使用情况 ID 集合的输入、输出和功能报告的大小(以字节为单位), (请参阅 HID 概念简介) 集合的链接集合数组中的HIDP_LINK_COLLECTION_NODE结构数 对于每种报表类型,HidP_GetButtonCaps返回的按钮功能数组中的 HIDP_BUTTON_CAPS结构数 对于每种报表类型,返回的值功能数组中的 HIDP_VALUE_CAPS 结构数 HidP_GetValueCaps 对于每种报表类型,集合支持的按钮和值数,由 NumberXxxDataIndices 成员指 定。 按钮功能数组 项目 • 2023/06/14 按钮功能数组包含特定类型 HID 报表的顶级集合支持的按钮用法的相关信息。 有关集合 功能的信息包含在其 HIDP_CAPS 结构中。 用户模式应用程序或内核模式驱动程序使用以下 HIDClass 支持例程 之一来获取按钮功能 信息: HidP_GetButtonCaps 返回一个按钮功能数组,该数组描述指定报表类型中包含的 所有按钮用法。 HidP_GetSpecificButtonCaps 按调用方指定的使用情况页、使用情况 ID 和 链接集 合筛选它返回的按钮功能信息。 按钮功能数组包含 HIDP_BUTTON_CAPS 结构,其中每个结构都包含有关 HID 用法 或 使 用范围的以下信息: 使用情况或使用情况范围的使用情况页 包含按钮数据的报表的报表 ID 使用情况 ID 或使用情况范围 指示用法是否为别名用法的标志 包含使用情况或使用情况范围的链接集合 与用法或使用范围关联的字符串描述符和指定符 (请参阅指示符索引项和字符串索引 项) HID 分析程序分配给使用情况或使用情况范围的数据索引 通常,对于按钮功能数组描述的所有用法,以下条件均保留: 每个功能结构表示与变量main项或数组main项关联的单个用法或使用范围。 别名用法可与变量main项一起使用。 与数组项关联的用法不能为别名。 不能对使 用范围进行别名化。 HID 分析程序仅使用所需的最小用法数来为每个按钮分配使用情况。 分析程序按在 报表描述符中指定的顺序分配用法。 将放弃报表描述符中不需要的用法。 按钮功能 数组不包含有关已放弃用法的任何信息。 如果为变量项指定的用法数小于项中的按钮数,则功能数组仅包含一个功能结构, 用于描述一个按钮用法 (变量main项) 的报告描述符中指定的最后一个用法。 但是, 有关报表计数大于 1 的使用情况值的信息,请参阅 Usage Value Array 。 HID 分析程序将唯一的数据索引分配给功能数组中所述的每个用法。 以下主题讨论如何在按钮功能数组中组织和设置功能结构: 变量main项中的按钮用法 数组main项中的按钮用法 报表描述符中指定的每个 用法 或 使用范围 在按钮功能数组中由其自身的功能结构描 述。 功能结构的 IsAlias 成员用于指定一组 n 个别名用法,如下所示: 在添加到功能数组的第一个 n-1 功能结构中,IsAlias 设置为 TRUE。 在 n个功能结 构中,IsAlias 设置为 FALSE。 首选用法是序列中最后一个别名用法。 应用程序或驱动程序可以通过扫描此类序列来确定哪些按钮用法已别名化。 下表总结了三种别名用法的示例。 报表描述符中的别名使用顺序 功能数组中的使用顺序 IsAlias 成员值 用法 1 用法 3 TRUE 用法 2 用法 2 TRUE 用法 3 用法 1 FALSE 有关如何交叉引用使用情况和数据索引的信息,请参阅 数据索引。 报表描述符中指定的项main按钮数组的每个用法或用法范围都由按钮功能数组中自身的 功能结构描述。 将功能结构添加到功能数组的顺序与为main项指定用法的顺序相反。 HID 分析程序按照在报表描述符中指定用法的顺序,向与数组项关联的每个用法分配 数 据索引 。 例如,下表显示了报表描述符中指定的一组用法与功能数组中指定的用法和数 据索引之间的对应关系。 (在此表中, n 是分析程序分配给与数组项关联的第一个用法的 第一个数据索引。) 报表描述符中的使用顺 序 功能数组中的使用顺 序 DataIndex 或从 DataIndexMin 到 DataIndexMax 变量main项中的按钮用法 数组main项中的按钮用法 报表描述符中的使用顺 序 功能数组中的使用顺 序 DataIndex 或从 DataIndexMin 到 DataIndexMax 用法 1 使用范围 2 从 n+7 到 n+8 使用范围 1 (,4 个用 法) 用法 2 n+5 用法 2 使用范围 1 从 n+1 到 n+4 使用范围 2 (,2 个用 法) 用法 1 n 值功能数组 项目 • 2023/06/15 值功能数组包含有关特定类型 HID 报表的顶级集合支持的值用法的信息。 有关集合的值 功能数组的信息包含在其 HIDP_CAPS 结构中。 用户模式应用程序或内核模式驱动程序使用以下 HIDClass 支持例程 之一来获取按钮功能 信息: HidP_GetValueCaps 返回值功能数组,该数组描述调用方指定的报表类型中包含的 所有值。 HidP_GetSpecificValueCaps 筛选它按调用方指定的使用页、使用情况、链接集合和 报表类型返回的值功能信息。 值功能数组包含 HIDP_VALUE_CAPS 结构,其中每个结构描述有关 HID 用法 或 使用范围 的以下信息: 使用情况或使用情况范围的使用情况页 包含值的报表的报表 ID 使用情况 ID 或使用范围 指示用法是否为 别名用法 有关包含使用情况或使用情况范围 的链接集合 的信息 值的大小(以位为单位)和报表计数 (这是结构描述的单个值的数目) 每个值的属性,包括:它是否具有 null 值、其单位和指数,以及其逻辑和物理范围 有关与用法或用法范围关联的字符串描述符和指定符的信息 有关 HID 分析程序分配的使用情况或使用情况范围 的数据索引 的信息 一般情况下,以下条件适用于值功能数组描述的所有用法: 每个功能结构都表示与变量main项关联的使用情况、使用范围或使用情况值数组。 值不支持数组main项。 可以使用别名用法。 不能对使用范围进行别名化。 在值功能数组中,别名值与别名 按钮链接在一起的方式与按钮功能数组中链接在一起的方式相同。 请参阅 变量主项 中的按钮用法。 HID 分析程序仅使用所需的最低使用量来为每个值分配一个用法。 分析程序按在报 表描述符中指定的顺序分配用法。 将放弃报表描述符中不需要的用法。 值功能数组 不包含有关已放弃用法的任何信息。 HID 分析程序为功能数组中所述的每个用法分配唯一 的数据索引 。 有关如何将数据索引分配给值的说明,请参阅 数据索引。 使用情况值数组是在main项中指定的一组连续值,所有这些值都分配了相同的用法。 如 果为报表计数大于 1 的main项指定了一个用法,则会出现这种情况。 下图显示了包含五个数据项(每个 6 位长)的使用情况值数组的示例。 在前面的示例中,此类使用值数组的值功能结构将它的 IsRange 成员设置为 FALSE,其 NotRange.Usage 成员设置为 17,其 ReportCount 成员设置为 5, BitSize 成员设置为 6。 如果使用情况的报告计数为 1,请使用 HidP_GetUsageValue 提取使用情况值。 如果使 用情况的报告计数大于 1, HidP_GetUsageValue 仅返回使用情况值数组中的第一个数据 项。 若要提取使用情况值数组中的所有数据项,请使用 HidP_GetUsageValueArray。 使用情况值数组 数据索引 项目 • 2023/06/15 HID 分析程序分配 一个数据索引 ,用于唯一标识顶级集合的 按钮功能数组 和 值功能数 组中描述的每个用法。 从概念上讲,数据索引是从零开始的数组索引,用户模式应用程 序或内核模式驱动程序可以使用该索引来访问报表中的单个控制数据。 分析程序将一组 唯一的数据索引分配给每个顶级集合支持的每种报表类型。 功能按以下方式构造交叉引用用法和数据索引: 描述使用情况的每个功能结构都具有用于标识使用情况的 NotRange.Usage 成员 集,其 NotRange.DataIndex 成员设置为使用情况的相应数据索引。 描述使用范围的每个功能结构都有其 Range.UsageMin 和 Range.UsageMax 成员集 来标识使用范围,其 Range.DataIndexMin 和 Range.DataIndexMax 成员集用于标 识使用范围的相应数据索引范围。 (数据索引范围 指定数据索引的连续序列;数据索 引范围中的数据索引数等于相应使用范围内的使用情况数。) 有关如何使用数据索引的详细信息,请参阅 按数据索引提取和设置控制数据。 打开 HID 集合 项目 • 2023/06/14 本部分介绍 HID 客户端如何与 HID 类驱动程序通信, (HIDClass) 来操作设备的 HID 集 合。 HID 客户端可以在以下模式下运行: 使用模式应用程序/驱动程序 Kernel-Mode驱动程序 以下部分介绍了 HID 客户端如何使用上述列表中的任一模式与 HIDClass 通信。 本部分介绍用户模式应用程序和内核模式驱动程序如何操作 HID 集合。 通常,用户模式应用程序执行以下操作: ) 调用 设备安装函数 (SetupDiXxx 函数来查找和标识 HID 集合。 调用 CreateFile 以打开 HID 集合上的文件。 调用 **HidD_**Xxx HID 支持例程来获取 HID 集合的 预分析数据和 有关 HID 集合的 信息。 调用 ReadFile 以读取输入报告,调用 WriteFile 以发送输出报告。 调用 **HidP_**Xxx HID 支持例程来解释 HID 报告。 通常,内核模式驱动程序将执行以下操作: 查找和标识 HID 集合 如果驱动程序是函数或筛选器驱动程序,则它已附加到集合的设备堆栈。 但是,如 果驱动程序未附加到集合的设备堆栈,驱动程序可以使用即插即用通知。 使用 IRP_MJ_CREATE 请求打开 HID 集合 使用 IOCTL_HID_Xxx 请求获取 HID 集合的预分析数据和有关 HID 集合的信息 使用 IRP_MJ_READ 请求读取输入报告, 使用IRP_MJ_WRITE 请求发送输出报告 调用 **HidP_**Xxx HID 支持例程来解释 HID 报告 找到并打开 HID 集合 另请参阅 强制实施适用于 HID 集合的安全读取 获取预分析的数据 获取集合信息 处理 HID 报告 释放资源 找到并打开 HID 集合 项目 • 2023/06/15 本部分介绍用户模式应用程序和内核模式驱动程序如何查找和打开顶级 HID 集合。 Microsoft Windows 提供设备安装例程 (SetupDiXxx 函数) 查找和标识 HIDClass 设备。 Windows 提供其他 Win32 函数来初始化和连接到 HID 集合。 加载用户模式应用程序后,它会执行以下操作序列: 调用 HidD_GetHidGuid 以获取 HIDClass 设备的系统定义的 GUID。 调用 SetupDiGetClassDevs 以获取不透明设备信息集的句柄,该信息集描述系统中 当前安装的所有 HID 集合 支持的设备接口。 应用程序应在传递给 SetupDiGetClassDevs的 Flags 参数中指定DIGCF_PRESENT和 DIGCF_DEVICEINTERFACE。 重复调用 SetupDiEnumDeviceInterfaces 以检索所有可用的接口信息。 调用 SetupDiGetDeviceInterfaceDetail 将每个集合的接口信息格式化为 SP_INTERFACE_DEVICE_DETAIL_DATA结构。 此结构的 DevicePath 成员包含应用程 序用于 Win32 函数 CreateFile 的用户模式名称,以获取 HID 集合的文件句柄。 调用 CreateFile 以获取 HID 集合的文件句柄。 如果内核模式驱动程序是函数或筛选器驱动程序,则它已将设备对象附加到 HID 集合的 设备堆栈。 驱动程序只需使用创建请求来打开设备。 如果驱动程序不是函数或筛选器驱动程序,它通常使用即插即用通知来查找集合。 找到 集合后,驱动程序使用创建请求打开集合。 User-Mode 应用程序 Kernel-Mode驱动程序 HID 客户端驱动程序 项目 • 2023/06/15 如果系统提供的 HID 微型驱动程序不支持设备的端口或总线,则需要供应商提供的微型 驱动程序。 下图演示了通用 HIDClass 设备 (的驱动程序堆栈,该设备可能使用供应商提供的可选组 件和必需的组件) 。 Windows 生成驱动程序堆栈,如下所示: 传输堆栈为附加的每个 HID 设备创建一个物理设备对象 (PDO) ,并加载相应的 HID 传输驱动程序,后者又加载 HID 类驱动程序。 HID 类驱动程序为 TLC 创建 PDO。 对于具有多个 TLC 的复杂设备,HID 类驱动程 序为每个 TLC 创建 PDO,并确保与 TLC 关联的硬件 ID 包含表示每个设备对象的标 识符。 供应商提供的函数或筛选器驱动程序为 HID 集合创建 FDO 或筛选器 DO。 或者,供应商提供的应用程序可以使用 SetupDI* API 打开设备来标识设备,然后使 用 HID 支持的例程来与设备通信。 此类设备据说是在 RAW 模式下打开的。 如果系统提供的 微型驱动程序操作 不支持设备,则需要供应商提供的 HID 微型驱动程 序。 可以通过两种方式实现此微型驱动程序: HID 客户端驱动程序 应用程序直接访问 HID 如果供应商提供驱动程序 (而不是微型驱动程序) ,则该驱动程序: 必须符合 Windows 驱动程序的最低要求。 理想情况下,这应基于用户模式驱动程 序框架 (UMDF) 或内核模式驱动程序框架 (KMDF) 。 较不理想的解决方案是创建 WDM 函数驱动程序,如 Windows 驱动程序模型中所述。 通常支持供应商定义的设备接口 -- 请参阅设备接口类。 上层驱动程序或用户模式应 用程序使用自定义接口访问供应商驱动程序操作的设备。 自定义接口可能会添加功 能,或者可能简化 HID 类驱动程序的接口。 如果驱动程序不是函数驱动程序或筛选器驱动程序,则可以使用即插即用通知来查找 HID 集合。 找到集合后,驱动程序会打开集合,并以与函数或筛选器驱动程序相同的方式操 作它。 重要说明: 如果供应商提供的函数驱动程序为 HID 集合创建 FDO 或筛选器 DO,则它不应使用 FILE_OBJECT 的 FsContext 字段来存储特定于文件对象的数据。 FsContext 字段是为 HID 类驱动程序保留的。 如果堆栈中的另一个驱动程序需要存储特定于文件对象的 上下文数据,则应改用 FsContext2 字段。 如果有多个设备附加到 PDO,则没有内置机制来确定哪个设备可以使用 FsContext2 字段。 强制实施适用于 HID 集合的安全读取 项目 • 2023/06/15 本部分介绍用户模式应用程序或内核模式驱动程序如何对顶级 HID 集合强制实施安全读 取。 如果为集合启用了安全读取,则只有 (具有 SeTcbPrivilege 特权的“受信任”客户端) 才能从 集合的打开文件获取输入。 默认情况下,内核模式驱动程序具有 SeTcbPrivilege 特权, 但用户模式应用程序没有。 有关如何在用户模式下获取系统权限的信息,请参阅 Microsoft Windows SDK文档中有关授权的信息。 提供此机制主要是使“受信任的”用户模式系统组件可以防止没有 SeTcbPrivilege 特权的用 户模式应用程序在关键系统操作期间从集合获取输入。 例如,“受信任的”用户模式系统 组件可以防止没有 SeTcbPrivilege 特权的用户模式应用程序获取用户在登录操作期间提供 的机密信息。 “受信任的”客户端使用 IOCTL_HID_ENABLE_SECURE_READ 和 IOCTL_HID_DISABLE_SECURE_READ 请求来为集合启用和禁用安全读取。 如果没有 SeTcbPrivilege 特权的客户端使用这些请求,则请求不会更改集合的安全读取状态,并且 HID 类驱动程序将返回状态值STATUS_PRIVILEGE_NOT_HELD。 为集合启用和禁用安全读取的方式如下: HID 类驱动程序为集合的每个打开文件维护特定于文件的安全读取计数。 HID 类驱 动程序还维护集合的安全读取计数,即特定于文件的安全读取计数之和。 创建集合 时,集合的安全读取计数初始化为零,打开文件时,文件的安全读取计数初始化为 零。 当 HID 类驱动程序收到对文件的启用请求时,它将文件 (安全读取计数递增 1,集 合) 的安全读取计数递增 1。 当 HID 类驱动程序收到对文件的禁用请求时: 如果文件的安全读取计数大于零,则驱动程序会将文件的安全读取计数 (减 1,) 集合的安全读取计数减 1。 如果文件的安全读取计数等于零,则驱动程序不会更改安全读取计数。 如果集合的安全读取计数大于零,则 HID 类驱动程序对集合强制实施安全读取。 否 则,驱动程序不会对集合强制实施安全读取。 客户端应使用禁用请求来取消相应的启用请求。 但是,如果客户端不执行此操作, HID 类驱动程序在处理对文件的 IRP_MJ_CLOSE 请求时,会适当地递减集合的安全 读取计数。 当驱动程序处理关闭请求时,它会将集合的安全读取计数递减为正在关 闭的文件的安全读取计数。 获取预先分析的数据 项目 • 2023/06/15 本部分介绍用户模式应用程序和内核模式驱动程序如何获取 HID 集合的 预分析数据,这 是描述集合 HID 报表的不透明结构。 用户模式应用程序在调用需要预分析数据的任何 HIDClass 支持例程 之前,必须获取集合 的预分析数据。 只要应用程序在设备上具有打开的文件,应用程序就应保留对集合的预 分析数据的访问权限。 在 HID 集合上打开文件后,应用程序调用 HidD_GetPreparsedData 以在例程分配的缓冲 区中返回集合的预分析数据。 当应用程序不再需要访问集合时,应用程序应调用 HidD_FreePreparsedData 。 内核模式驱动程序打开 HID 集合后,驱动程序将按以下方式获取集合的 预分析数据 : 获取集合的预分析数据的长度 获取集合的预分析数据 为了确定预分析数据的长度,驱动程序使用 IOCTL_HID_GET_COLLECTION_INFORMATION 请求。 此请求返回 HID_COLLECTION_INFORMATION 结构。 此结构的 DescriptorSize 成员指定集合的预分 析数据的大小(以字节为单位)。 驱动程序必须分配至少具有此大小的非分页池的缓冲 区,以保存预分析的数据。 为预分析数据分配缓冲区后,驱动程序使用 IOCTL_HID_GET_COLLECTION_DESCRIPTOR 请求获取已准备的数据。 获取预先分析的数据后,驱动程序可以将其与 **HidP_**Xxx HID 支持例程一起使用,以 获取有关 HID 集合功能的信息,并从 HID 报表中提取控制数据。 User-Mode 应用程序 Kernel-Mode驱动程序 获取集合信息 项目 • 2023/06/15 本部分介绍如何获取用户模式应用程序和内核模式驱动程序用于操作 HID 集合的信息。 应用程序或驱动程序连接到 HID 集合后,它可以获取以下信息: 集合的功能。 按钮功能数组 和 值功能数组,描述集合支持的按钮和值的功能。 链接集合数组,描述其 链接集合的内部组织。 此信息包括集合的 HID 用法 以及集合支持的所有控件。 如果应用程序或驱动程序未使用 这些控件,则应立即关闭其与集合的连接。 获取此信息后,应用程序或驱动程序具有访问 HID 报表中的控制数据所需的信息。 “处理 HID 报告”主题 项目 • 2023/06/14 本部分介绍用户模式应用程序和内核模式驱动程序用于处理 HID 报表的机制。 应用程序或驱动程序连接到 HID 集合后,可以从该集合获取 HID 报表,或者将报表发送 到该集合。 有关如何处理 HID 报表的详细信息,请参阅以下主题: 初始化 HID 报告 获取 HID 报告 发送 HID 报告 解释 HID 报告 排查 HID 报告问题 初始化 HID 报告 项目 • 2023/06/15 本部分介绍用户模式应用程序和内核模式驱动程序在使用 HIDClass 支持例程或 HID 类驱 动程序 IOCTL 之前如何初始化 HID 报告。 若要初始化报表缓冲区,应用程序或驱动程序会为报表类型创建所需大小(以字节为单 位)的零初始化缓冲区。 HID 集合的HIDP_CAPS结构的 XxxReportByteLength 成员指定 输入、输出和功能报告所需的大小。 初始化报表缓冲区后,应用程序或驱动程序可以使 用 HidP_SetXxx 例程在报表中设置控制数据。 首次使用报表时, HidP_SetXxx 例程将报 表 ID 设置为与指定的 HID 用法关联的报表 ID。 如果应用程序或驱动程序随后尝试设置 与报表 ID 不兼容的用法, HidP_SetXxx 例程将返回 HIDP_STATUS_INCOMPATIBLE_REPORT_ID状态。 获取 HID 报告 项目 • 2023/06/15 本部分介绍用户模式应用程序和内核模式驱动程序如何从 HID 集合获取 HID 报告。 本主题讨论如何使用 ReadFile 或 HidD_GetXxx 例程的用户模式应用程序获取 HID 输入报 告或 HID 功能报告。 但是,应用程序应仅使用 HidD_GetXxx 例程来获取设备的当前状态。 如果应用程序尝试 使用 HidD_GetInputReport 持续获取输入报告,则报表可能会丢失。 此外,某些设备可 能不支持 HidD_GetInputReport,如果使用此例程,则无响应。 应用程序使用通过 CreateFile 获取的打开文件句柄打开集合上的文件。 当应用程序调用 ReadFile 时,它不必指定重叠的 I/O,因为 HID 客户端驱动程序 缓冲区在环形缓冲区中 报告。 但是,应用程序可以使用重叠 I/O 具有多个未完成的读取请求。 应用程序可以使用以下 HIDClass 支持例程 从 HID 集合中获取最新的输入报告和功能报 告: HidD_GetInputReport 从 HID 集合 (Windows XP 及更高版本) 返回输入报告。 HidD_GetFeature 从 HID 集合返回特征报告。 应用程序可以请求返回特定报表。 若要使用这些例程检索特定报表,应用程序会分配报 表输出缓冲区,对缓冲区进行零初始化,并将缓冲区中的第一个字节设置为特定的报表 ID。 有关详细信息,请参阅 初始化 HID 报表。 本主题讨论内核模式驱动程序应如何使用IRP_MJ_READ请求作为持续获取 HID 输入报告 main方法。 连续读取请求按从集合接收的顺序返回输入报告。 驱动程序还可以使用 IOCTL_HID_GET_Xxx 请求来获取输入和功能报告。 但是,驱动程序应仅使用这些 I/O 请 求来获取设备的当前状态。 如果驱动程序尝试使用 IOCTL_HID_GET_INPUT_REPORT 持续 按用户模式应用程序获取 HID 报告 使用 ReadFile 使用 HidD_GetXxx 例程 通过内核模式驱动程序获取 HID 报告 获取输入报告,则报表可能会丢失。 此外,某些设备可能不支持 IOCTL_HID_GET_INPUT_REPORT,如果使用此请求,将变得无响应。 非 WDM Windows 2000 驱动程序以及适用于 Windows XP 及更高版本的驱动程序可以使 用单个 IRP 来处理对设备的所有读取请求。 但是,Windows 2000 WDM 驱动程序必须为 每个读取请求分配一个新的 IRP。 有关如何使用和重用 IRP 的常规信息,请参阅 处理 IRP 和 重用 IRP。 如果驱动程序重用 IRP,IRP 的 IoCompletion 例程应以 STATUS_MORE_PROCESSING_REQUIRED ( 状态完成请求,而不是释放 IRP) 。 当驱动程 序不再需要 IRP 时,它应通过调用 IoCompleteRequest 和 IoFreeIrp 完成并释放 IRP。 例 如,驱动程序通常会在其 Unload 例程中或在删除设备后完成并释放 IRP。 如果驱动程序仅对一个读取请求使用 IRP,则 IRP 的 IoCompletion 例程应完成并释放 IRP,并返回 STATUS_SUCCESS。 驱动程序必须先从非分页内存池中分配零初始化的输入报告缓冲区,然后驱动程序才能请 求输入报告。 缓冲区的大小(以字节为单位)由 HID 集合的 HIDP_CAPS 结构的 InputReportByteLength 成员指定。 然后,驱动程序必须使用 MDL 来映射读取请求的输 入报告缓冲区。 驱动程序调用 IoAllocateMdl 为输入报告缓冲区分配 MDL,并将读取 IRP 的 Irp-MdlAddress> 成员设置为输入报告缓冲区的 MDL 地址。 当不再需要报表缓冲区 和 MDL 时,驱动程序应释放它们。 除了设置读取 IRP 的 MDL 地址外,驱动程序还必须设置下一个较低级别驱动程序的 I/O 堆栈位置。 驱动程序通过调用 IoGetNextIrpStackLocation 获取对下一个较低级别驱动程 序的 I/O 堆栈位置的访问权限。 驱动程序设置 I/O 堆栈位置的以下成员: Parameters.Read.Length 设置为读取缓冲区的大小(以字节为单位)。 此值必须大于或等于 HID 集合 HIDP_CAPS 结构的 InputReportByteLength 成员指定的值。 Parameters.Read.Key 设置为零。 Parameters.Read.ByteOffset.QuadPart 设置为零。 MajorFunction 设置为 IRP_MJ_READ。 FileObject 设置为表示 HID 集合上打开的文件的文件对象指针。 使用IRP_MJ_READ请求 驱动程序获取输入报告后,它可以访问控制数据,如 解释 HID 报告中所述。 驱动程序可以使用以下 I/O 请求从 HID 集合获取最新的输入和功能报告: IOCTL_HID_GET_INPUT_REPORT 从 HID 集合 (Windows XP 及更高版本) 返回输入报 告。 IOCTL_HID_GET_FEATURE 从 HID 集合返回特征报告。 驱动程序可以请求返回特定报表。 若要使用这些 I/O 请求检索特定报表,驱动程序首先 分配输出报告缓冲区,然后对缓冲区进行零初始化,并将缓冲区中的第一个字节设置为特 定的报表 ID。 有关详细信息,请参阅 解释 HID 报表。 使用IOCTL_HID_GET_Xxx请求 发送 HID 报告 项目 • 2023/06/15 本部分介绍用户模式应用程序和内核模式驱动程序如何将 HID 报表发送到 HID 集合。 用户模式应用程序应使用 WriteFile 作为其main方法,以便将输出报表持续发送到 HID 集 合。 应用程序还可以使用 HidD_SetXxx 例程将输出报表和特征报告发送到集合。 但是, 应用程序应仅使用这些例程来设置集合的当前状态。 某些设备可能不支持 HidD_SetOutputReport ,如果使用此例程,将变得无响应。 应用程序应使用写入请求将输出报表发送到 HID 集合。 用户模式应用程序创建输出报表 后,可以使用 WriteFile 将输出报表发送到集合。 应用程序可以使用以下 HIDClass 支持例程 将 HID 报表发送到 HID 集合: HidD_SetOutputReport 将输出报表发送到 (Windows XP 及更高版本的 HID 集合) 。 HidD_SetFeature 将特征报告发送到 HID 集合。 内核模式驱动程序应使用IRP_MJ_WRITE请求作为其main方法,以持续将输出报告发送到 HID 集合。 驱动程序还可以使用 IOCTL_HID_SET_Xxx 请求将输出报表和功能报表发送到 集合。 但是,驱动程序应仅使用这些 I/O 请求来设置集合的当前状态。 某些设备可能不 支持 IOCTL_HID_SET_OUTPUT_REPORT ,如果使用此请求,将变得无响应。 非 WDM Windows 2000 驱动程序和 Windows XP 及更高版本的驱动程序可以使用单个 IRP 处理发送到集合的所有写入请求。 但是,Windows 2000 WDM 驱动程序必须为每个 写入请求分配新的 IRP。 有关如何使用和重用 IRP 的详细信息,请参阅 处理 IRP 和 重复 使用 IRP。 按User-Mode应用程序发送 HID 报告 使用 WriteFile 使用HidD_SetXxx例程 按Kernel-Mode驱动程序发送 HID 报告 使用IRP_MJ_WRITE请求 如果驱动程序重用写入 IRP,则 IRP 的 IoCompletion 例程应以 STATUS_MORE_PROCESSING_REQUIRED ( 状态完成请求,而不是释放 IRP) 。 当驱动程 序不再需要 IRP 时,它应通过调用 IoCompleteRequest 和 IoFreeIrp 完成并释放 IRP。 例 如,驱动程序通常 可能会在卸载例 程中完成并释放 IRP,或者在删除设备后。 如果驱动程序仅对一个写入请求使用 IRP,则 IRP 的 IoCompletion 例程应完成并释放 IRP,并返回 STATUS_SUCCESS。 在发送输出报表之前,驱动程序必须先初始化并设置输出报表缓冲区,如 初始化 HID 报 表中所述。 然后,驱动程序必须使用 MDL 映射写入请求的输出报表缓冲区。 驱动程序 调用 IoAllocateMdl 为输出报表分配 MDL,并将写入 IRP 的 Irp-MdlAddress> 成员设置 为输出报表缓冲区的 MDL 地址。 不再需要报表缓冲区和 MDL 时,驱动程序必须释放它 们。 除了设置写入 IRP 的 MDL 地址外,驱动程序还必须设置下一个较低级别驱动程序的 I/O 堆栈位置。 驱动程序通过调用 IoGetNextIrpStackLocation 获取对下一个较低级别驱动程 序的 I/O 堆栈位置的访问权限。 驱动程序设置 I/O 堆栈位置的以下成员: Parameters.Write.Length 设置为输出报表的长度(以字节为单位)。 这应设置为 HID 集合的输出报表的长度,由 集合HIDP_CAPS结构的 OutputReportByteLength 成员指定。 Parameters.Write.Key 设置为零。 Parameters.Write.ByteOffset.QuadPart 设置为零。 MajorFunction 设置为 IRP_MJ_WRITE。 FileObject 设置为表示 HID 集合上打开的文件的文件对象指针。 驱动程序还可以使用以下 I/O 请求将输出和功能报告发送到 HID 集合: IOCTL_HID_SET_OUTPUT_REPORT 将输出报表发送到集合 (Windows XP 及更高版本) 。 IOCTL_HID_SET_FEATURE 将特征报告发送到集合。 使用IOCTL_HID_SET_Xxx请求 解释 HID 报告 项目 • 2023/06/15 本部分介绍用户模式应用程序和内核模式驱动程序如何使用 HidP_XxxHIDClass 支持例程 来解释 HID 报表中的控制数据。 若要从 HID 报表中提取值数据,应用程序或驱动程序可以使用以下 HID 支持例程之一: HidP_GetScaledUsageValue 返回带符号和缩放的值。 HidP_GetUsageValue 返回一个无符号格式的非缩放值,或者一个已缩放的值,该值 在正常范围内。 HidP_GetUsageValueArray 返回一个使用情况值数组。 若要使用 HidP_GetUsageValueArray 应用程序和驱动程序必须分配一个零初始化缓冲 区,该缓冲区足够大,可以保存使用值数组。 所需大小(以字节为单位)是使用情况值 数组HIDP_VALUE_CAPS结构的 BitSize 和 ReportCount 成员的乘积,向上舍入到最接近 的字节。 若要提取设置为 ON (1) 的按钮的 HID 用法,应用程序和驱动程序调用以下 HID 支持例程 之一: HidP_GetButtons (或 HidP_GetUsages) 返回指定使用页上设置为 ON 的所有按钮的 使用 ID。 HidP_GetButtonsEx (或 HidP_GetUsagesEx) 返回设置为 ON 的所有按钮的使用情况 页和使用情况 ID。 这些例程返回当前设置为 ON 的所有按钮的所有使用情况信息数组。 隐式地,这些例程 未返回其用法的按钮设置为 OFF (零) 。 若要调用这些例程,应用程序和驱动程序必须首先分配并零初始化用于返回按钮用法数组 的缓冲区。 应用程序或驱动程序调用 HidP_MaxUsageListLength 来确定报表中指定使用 情况页中的按钮用法数。 如果应用程序或驱动程序将使用情况页指定为零,则例程将返 回报表中所有按钮用法的数目。 所需的缓冲区大小(以字节为单位)如下所示: 通过指定值数据的使用情况提取值数据 提取设置为 ON 的按钮用法 (for HidP_GetButtons) 返回的值 HidP_MaxUsageListLength次 size 为 (USAGE) (for HidP_GetButtonsEx) 返回的值 HidP_MaxUsageListLength倍大小为 (USAGE_AND_PAGE) 在应用程序或驱动程序使用这些例程获取有关哪些按钮当前设置为 ON 的信息后,它可 以通过调用以下 HIDClass 支持例程之一来确定按钮的当前状态与以前状态之间的差异。 这些例程返回两个使用信息数组之间的差异: HidP_UsageListDifference HidP_UsageAndPageListDifference 若要使用数据索引提取和设置 HID 报表中的控制数据,应用程序或驱动程序可以使用以 下 HIDClass 支持例程: HidP_GetData HidP_SetData 这些例程对于提供“增值”服务的应用程序或驱动程序特别有用。 例如,为 HIDClass 设备 支持的所有控件提供自定义接口的 。 Microsoft DirectInput 就是一个示例。 通过调用这些例程,应用程序或驱动程序可以最有效地获取和设置报表中的所有值。 例 如,若要按 其 HID 用法 获取所有值数据,必须为每个用法调用 HidP_GetUsageValue 。 但是,若要按数据索引获取所有值数据,只需调用 HidP_GetData 一次。 应用程序或驱动程序使用集合的 按钮功能数组 和 值功能数组 中指定的数据索引来标识 HID 用法。 应用程序或驱动程序可以通过调用以下 HID 支持例程之一在正确初始化的 HID 报表中设 置值: HidP_SetScaledUsageValue 在报表中设置有符号和缩放的值。 HidP_SetUsageValue 设置报表中的值。 HidP_SetUsageValueArray 在报表中设置使用情况值数组。 按数据索引提取和设置控制数据 通过指定值数据的用法来设置值数据 通过指定按钮的用法来设置按钮状态 应用程序或驱动程序可以通过调用以下 HIDClass 支持例程之一,在正确初始化的 HID 报 表中设置按钮的状态: HidP_SetButtons (或 HidP_SetUsages) 将一组指定的按钮设置为 ON (1) 。 HidP_UnsetButtons (或 HidP_UnsetUsages) 将一组指定的按钮设置为 OFF (零) 。 若要使用数据索引提取和设置 HID 报表中的控制数据,应用程序或驱动程序可以使用以 下 HIDClass 支持例程: HidP_GetData HidP_SetData 这些例程对于提供“增值”服务的应用程序或驱动程序特别有用。 例如,为 HIDClass 设备 支持的所有控件提供自定义接口的 。 Microsoft DirectInput 就是一个示例。 通过调用这些例程,应用程序或驱动程序可以最有效地获取和设置报表中的所有值。 例 如,若要按其 HID 用法获取所有值数据,必须为每个用法调用 HidP_GetUsageValue 。 但是,若要按数据索引获取所有值数据,只需调用 HidP_GetData 一次。 应用程序或驱动程序使用集合的 按钮功能数组 和 值功能数组 中指定的数据索引来标识 HID 用法。 初始化 HID 报告 按数据索引提取和设置 HID 控制数据 另请参阅 HID 报表疑难解答 项目 • 2023/06/15 本文介绍用户模式应用程序和内核模式驱动程序在尝试提取或设置 HID 用法时可能遇到 的最常见问题。 当应用程序或驱动程序从 HID 集合接收 HID 报表时,它可以是集合包含的任何报表 (, 因为集合可以按任何顺序) 返回报表。 HidP_GetXxx 例程返回以下状态值,这些值指示报 告 ID 错误: HIDP_STATUS_INCOMPATIBLE_REPORT_ID 请求的使用情况位于 HID 集合支持的报表中,但不在应用程序或驱动程序指定的报表 中。 HIDP_STATUS_USAGE_NOT_FOUND 请求的使用情况不在顶级集合支持的任何报表中。 例如,下图显示了包含两个报表的 HID 集合。 根据此示例,假设应用程序或驱动程序收到了来自集合的报告,并调用 HidP_GetUsageValue 提取“值 X”的当前值。如果报表的 ID 为 7,则例程返回 HIDP_STATUS_INCOMPATIBLE_REPORT_ID,这表示设备支持值 X,但值 X 不在报表中。 另一方面,如果应用程序或驱动程序请求值“值 Z”,则例程将返回 HIDP_STATUS_USAGE_NOT_FOUND,这表示值 Z 不在集合支持的任何报表中。 当应用程序或驱动程序使用 HidP_SetXxx 例程在报表中设置使用情况时,例程还可以返 回相同的两个状态值。 HIDP_STATUS_USAGE_NOT_FOUND的含义与 HidP_GetXxx 例程 相同。 但是,HIDP_STATUS_INCOMPATIBLE_REPORT_ID的含义不同。 此状态值指示报表 以前已使用报表 ID 进行配置,并且调用方指定的用法不属于该报表 ID。 以上图为例, 在应用程序或驱动程序使用 HidP_SetUsages 在零初始化的报表中设置“Button 2”后,报 HID 报告 ID 错误 表将配置为 7 的报表 ID。 如果应用程序或驱动程序随后尝试使用 HidP_SetUsageValue 在同一报表中设置“值 X”,则例程将返回HIDP_STATUS_INCOMPATIBLE_REPORT_ID。 如果 **HidP_**Xxx 例程返回HIDP_STATUS_INCOMPATIBLE_REPORT_ID,则调用方应执行 以下操作之一: 如果调用方正在设置用法,则应分配一个长度正确的新报表,对其进行零初始化, 然后再次调用例程。 成功设置报表中的所有用法后,调用方可以将报表发送到集 合。 如果调用方正在提取使用情况,则应使用从集合获取的不同报表调用例程。 当 HID 客户端驱动程序从 HID 集合获取输入报表时,报表将存储在 HID 类驱动程序维护 的环形缓冲区中。 此机制可降低应用程序或驱动程序错过所需的输入报告的可能性。 默认情况下,HID 类驱动程序维护一个包含 32 个报告的输入报表环缓冲区。 如果集合将 数据传输到 HID 类驱动程序的速度比用户模式应用程序或内核模式驱动程序从缓冲区中 检索数据的速度快,则输入报告将因缓冲区溢出而丢失。 为了降低缓冲区溢出的可能 性,应用程序或驱动程序可以重新配置缓冲区的大小(以报告数为单位)。 驱动程序使 用IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS请求和 IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS请求检索和更改缓冲区的大小。 应用程序通 过调用 HidD_GetNumInputBuffers 和 HidD_SetNumInputBuffers 来执行相同的操作。 已删除的 HID 报表 释放资源 项目 • 2023/06/14 HID 客户端的用户模式应用程序和内核模式驱动程序应始终释放不再需要的任何资源。 例如,用户模式应用程序必须在完成 HIDClass 设备的初始化和连接操作后,使用从 SetupDiGetClassDevs 获取的设备列表句柄调用 SetupDiDestroyDeviceInfoList。 调用 SetupDiDestroyDeviceInfoList 失败会导致内存泄漏。 安装 HID 客户端 项目 • 2023/06/15 本部分介绍在 Microsoft Windows 中安装 HIDClass 设备的以下要求。 供应商必须将硬件 ID 用于顶级集合,这些硬件 ID 在 HIDClass 硬件 ID 中指定为 Top-Level集合的供应商硬件 ID 格式。 供应商提供的父输入设备的驱动程序 (安装在 HIDClass 设备的驱动程序堆栈中的 HID 类驱动程序下,) 必须提供 HID 类驱动程序用于为顶级集合生成硬件 ID 的硬件 信息。 (请注意,系统为 HIDClass 设备提供的驱动程序会自动执行此操作。) 在 Windows Vista 和更高版本的 Windows 中,供应商可以为 USB HID 设备启用选 择性挂起功能。 此功能在 通用串行总线规范 修订版 2.0 中定义。有关 Windows 如 何支持 USB 选择性挂起功能的详细信息,请参阅 USB 选择性挂起。 安装 HIDClass 设备没有其他特定于 HIDClass 的要求。 有关如何安装设备的详细信息, 请参阅 设备安装概述。 顶级集合的 HIDClass 硬件 ID 项目 • 2023/06/15 本部分指定 HID 类驱动程序为顶级集合生成的硬件 ID。 供应商必须使用指定为 供应商硬件 ID 格式 的格式来标识顶级集合。 所有其他 设备 ID 格式仅保留供内部使用。 HID 类驱动程序为开发节点生成的硬件 ID 取决于以下各项: 1. 基础传输支持的函数数 2. 报表描述符中的顶级集合数 根据这些因素,有 4 类硬件 ID 类型 单个 TLC 多个 TLC Single-Function Case 1 Case 2 多功能 案例 3 案例 4 使用此硬件 ID 格式的条件: 1. 基础传输支持的函数数 = 1 && 2. TLC 数 = 1 硬件 ID 格式: HID\Vid_v (4) &Pid_d (4) &Rev_r (4) HID\Vid_v (4) &Pid_d (4) HID_DEVICE_UP:p (4) _U:u (4) HID_DEVICE 使用此硬件 ID 格式的条件: 1. 基础传输支持的函数数 = 1 && 2. TLC > 1 的数目 硬件 ID 格式: 案例 1:具有单个 TLC 的单函数设备 案例 2:具有多个 TLC 的单函数设备 HID\Vid_v (4) &Pid_d (4) &Rev_r (4) &Colb (2) HID\Vid_v (4) &Pid_d (4) &Colb (2) HID_DEVICE_UP:p (4) _U:u (4) [仅适用于 WINDOWS INF] HID_DEVICE [仅适用于 WINDOWS INF] 使用此硬件 ID 格式的条件: 1. 基础传输 > 1 支持的函数数 && 2. TLC 数 = 1 硬件 ID 格式: HID\Vid_v (4) &Pid_d (4) &Rev_r (4) &MI_z (2) HID\Vid_v (4) &Pid_d (4) &MI_z (2) HID_DEVICE_UP:p (4) _U:u (4) [仅适用于 WINDOWS INF] HID_DEVICE [仅适用于 WINDOWS INF] 使用此硬件 ID 格式的条件: 1. 基础传输 > 1 支持的函数数 && 2. TLC > 1 的数目 硬件 ID 格式: HID\Vid_v (4) &Pid_d (4) &Rev_r (4) &MI_z (2) &Colb (2) HID\Vid_v (4) &Pid_d (4) &MI_z (2) &Colb (2) HID_DEVICE_UP:p (4) _U:u (4) [仅适用于 WINDOWS INF] HID_DEVICE [仅适用于 WINDOWS INF] 以下是仅供内部使用的硬件 ID (,windows 使用) 提供默认系统功能。 设备类型 使用情况页 使用情况 硬件 ID 指针 0x01 0x01 HID_DEVICE_SYSTEM_MOUSE 鼠标 0x01 0x02 HID_DEVICE_SYSTEM_MOUSE 案例 3:具有单个 TLC 的多功能设备 案例 4:具有多个 TLC 的多功能设备 特殊用途硬件 ID 设备类型 使用情况页 使用情况 硬件 ID 游戏杆 0x01 0x04 HID_DEVICE_SYSTEM_GAME 游戏板 0x01 0x05 HID_DEVICE_SYSTEM_GAME Keyboard 0x01 0x06 HID_DEVICE_SYSTEM_KEYBOARD 键盘 0x01 0x07 HID_DEVICE_SYSTEM_KEYBOARD 系统控件 0x01 0x80 HID_DEVICE_SYSTEM_CONTROL 使用者音频控件 0x0C 0x01 HID_DEVICE_SYSTEM_CONSUMER 重要说明: HIDClass 没有生成的兼容 ID 供应商第三方 INF 只能与硬件 ID 匹配 包含 HID_DEVICE_SYSTEM_* 的硬件 ID 是操作系统打开供其使用的“特殊”设备。 供 应商提供的 INF 不能匹配这些特殊硬件 ID。 供应商提供的第三方 HID 传输微型驱动程序必须提供下面列出的字段,以确保 HIDClass 可以生成适当的硬件 ID。 图例: 字段 包含 十六进制值 含义 v (4) 四个十六进制数字 0x0000-0xFFFF 供应商 ID d (4) 四个十六进制数字 0x0000-0xFFFF 产品 ID r (4) 四个十六进制数字 0x0000-0xFFFF 修订号 z (2) 两个十六进制数字 0x00-0xFF 接口号 (仅用于复合 USB 设备。) b (2) 两个十六进制数字 0x00-0xFF 集合编号 (仅用于多 TLC 设备。) p (4) 四个十六进制数字 0x0000-0xFFFF TLC 的使用页码 u (4) 四个十六进制数字 0x0000-0xFFFF 用法 TLC 数 键盘和鼠标 HID 客户端驱动程序 项目 • 2023/06/15 本主题讨论键盘和鼠标 HID 客户端驱动程序。 键盘和鼠标表示在 HID 使用情况表中标准 化并在 Windows 操作系统中实现的第一组 HID 客户端。 键盘和鼠标 HID 客户端驱动程序以 HID 映射器驱动程序的形式实现。 HID 映射器驱动程 序是内核模式 WDM 筛选器驱动程序,它为非 HID 类驱动程序与 HID 类驱动程序之间的 I/O 请求提供双向接口。 映射器驱动程序将一个的 I/O 请求和数据协议映射到另一个。 Windows 为 HID 键盘和 HID 鼠标设备提供系统提供的 HID 映射器驱动程序。 下图演示了适用于 USB 键盘、鼠标和触摸板设备的系统提供的驱动程序堆栈。 7 备注 本主题适用于为键盘和鼠标 HID 客户端创建驱动程序的开发人员。 如果要修复鼠标 或键盘,请参阅: Windows 中的鼠标、触摸板和键盘问题 对无法正常工作的无线鼠标进行故障排除 体系结构和概述 上图包括以下组件: KBDHID.sys:适用于键盘的 HID 客户端映射器驱动程序。 将 HID 用法转换为扫描 代码,以便与现有键盘类驱动程序进行交互。 MOUHID.sys:用于鼠标/触摸板的 HID 客户端映射器驱动程序。 将 HID 用法转换 为鼠标命令, (X/Y、按钮、滚轮) 来与现有键盘类驱动程序进行交互。 KBDCLASS.sys: 键盘类驱动程序 以安全的方式维护系统上所有键盘和键盘的功 能。 MOUCLASS.sys: 鼠标类驱动程序 维护系统上所有鼠标/触摸板的功能。 驱动程序 支持绝对和相对指向设备。 这不是触摸屏的驱动程序,因为它由 Windows 中的其 他驱动程序管理。 HIDCLASS.sys: HID 类驱动程序。 HID 类驱动程序是KBDHID.sys和MOUHID.sys HID 客户端与各种传输 (USB、蓝牙等) 之间的粘附。 系统按如下所示生成驱动程序堆栈: 传输堆栈为附加的每个 HID 设备创建一个物理设备对象 (PDO) ,并加载相应的 HID 传输驱动程序,后者又加载 HID 类驱动程序。 HID 类驱动程序为每个键盘或鼠标 TLC 创建 PDO。 (超过 1 个 TLC) 的复杂 HID 设 备将作为 HID 类驱动程序创建的多个 PDO 公开。 例如,具有集成鼠标的键盘可能 具有一个用于标准键盘控件的集合,而鼠标的集合可能具有不同的集合。 键盘或鼠标 hid 客户端映射器驱动程序加载到相应的 FDO 上。 HID 映射器驱动程序为键盘和鼠标创建 FDO,并加载类驱动程序。 符合支持的 HID 用法和顶级集合的键盘和鼠标不需要供应商驱动程序。 供应商可以选择在 HID 堆栈中提供筛选器驱动程序,以更改/增强这些特定 TLC 的 功能。 供应商应创建特定于供应商的单独 TLC,以在其 hid 客户端和设备之间交换供应商 专有数据。 除非关键,否则请避免使用筛选器驱动程序。 系统将打开所有键盘和鼠标集合供其独占使用。 系统阻止禁用/启用键盘。 系统支持水平/垂直滚轮,具有平滑滚动功能。 Microsoft 为 IHV 编写驱动程序提供了以下指南: 1. 允许驱动程序开发人员以筛选器驱动程序或新的 HID 客户端驱动程序的形式添加其 他驱动程序。 条件如下所述: a. 筛选器驱动程序:驱动程序开发人员应确保其增值驱动程序是筛选器驱动程序, 并且不会替换 (或用于代替输入堆栈中) 现有 Windows HID 驱动程序。 在以下情况下,允许使用筛选器驱动程序: 作为 kbdhid/mouhid 的上部筛选器 作为 kbdclass/mouclass 的上部筛选器 不建议将筛选器驱动程序用作 HIDCLASS 和 HID Transport 微型驱动程序之 间的筛选器 b. 函数驱动程序:或者,供应商可以创建函数驱动程序 (而不是筛选器驱动程序) , 但仅针对供应商特定的 HID PDO (用户模式服务(如有必要)) 。 在以下情况下,允许使用函数驱动程序: 仅在特定供应商的硬件上加载 c. 传输驱动程序:Windows 团队不建议创建其他 HID 传输微型驱动程序,因为它 们是需要写入/维护的复杂驱动程序。 如果合作伙伴正在创建新的 HID Transport 微型驱动程序(尤其是在 SoC 系统上),我们建议进行详细的体系结构评审,以 了解推理并确保正确开发驱动程序。 2. 驱动程序开发人员应利用驱动程序框架 (KMDF 或 UMDF) ,而不依赖 WDM 来获取 其筛选器驱动程序。 重要说明: 驱动程序指南 3. 驱动程序开发人员应减少其服务和驱动程序堆栈之间的内核用户转换次数。 4. 驱动程序开发人员应确保能够通过键盘和触摸板功能唤醒系统, (最终用户 (设备管 理器) 或电脑制造商) 进行调整。 此外,在 SoC 系统上,当系统处于工作 S0 状态 时,这些设备必须能够将自身从低功率状态唤醒。 5. 驱动程序开发人员应确保其硬件进行高效电源管理。 当设备处于空闲状态时,设备可以进入其最低功率状态。 当系统处于低功耗状态时,设备处于最低功率状态, (例如,待机 (S3) 或连接 的待机) 。 键盘布局完全描述了 Microsoft Windows 2000 及更高版本的键盘输入特征。 例如,键盘 布局指定语言、键盘类型和版本、修饰符、扫描代码等。 有关键盘布局的信息,请参阅以下内容: Windows 驱动程序开发工具包中的键盘头文件 kdb.h (DDK) ,其中记录了有关键盘 布局的一般信息。 示例键盘 布局。 若要可视化特定键盘的布局,请参阅 Windows 键盘布局。 有关键盘布局的其他详细信息,请访问控制面板\时钟、语言和区域\语言。 下表确定了 Windows 操作系统的不同客户端版本支持的功能。 功能 Windows XP Windows Vista Windows 7 Windows 8 及更 高版本 按钮 1-5 支持的 (P/2 & HID) 支持的 (PS/2 & HID) 支持的 (PS/2 & HID) 支持的 (PS/2 & HID) 垂直滚轮 支持的 (PS/2 & HID) 支持的 (PS/2 & HID) 支持的 (PS/2 & HID) 支持的 (PS/2 & HID) 水平滚轮 不支持 仅) 支持 (HID 仅) 支持 (HID 仅) 支持 (HID 水平和垂直) (平滑滚 轮支持 不支持 部分支持 仅支持 (HID) 仅支持 (HID) 键盘布局 鼠标上支持的按钮和方向盘 Windows 用于激活新的 4&5 按钮 + 滚轮模式的方法是用于在 IntelliMouse 兼容鼠标中激 活第三个按钮和滚轮的方法的扩展: 首先,将鼠标设置为 3 按钮滚轮模式,这是通过将报告速率连续设置为 200 个报 告/秒,然后设置为 100 个报告/秒,然后设置为 80 个报告/秒,然后从鼠标读取 ID 来完成。 完成此序列时,鼠标应报告 ID 为 3。 接下来,将鼠标设置为 5 按钮滚轮模式,这是通过将报告速率连续设置为 200 个报 告/秒,然后再次设置为 200 个报告/秒,然后设置为 80 个报告/秒,然后从鼠标读 取 ID 来完成。 完成此序列后,5 按钮滚轮鼠标应报告 ID 为 4 (而与 IntelliMouse 兼 容的 3 按钮滚轮鼠标仍报告 ID 为 3) 。 请注意,这仅适用于 PS/2 小鼠,不适用于 HID 小鼠, (HID 鼠标必须在其报告描述符) 中 报告准确的使用情况。 Byte D7 D6 D5 D4 D3 D2 D1 D0 评论 1 Yover Xover Ysign Xsign 标记 M R L X/Y 溢出和符号、按钮 2 X7 X6 X5 X4 X3 X2 X1 X0 X 数据字节 3 Y7 Y6 是5 Y4 Y3 是2 是1 Y0 Y 数据字节 Byte D7 D6 D5 D4 D3 D2 D1 D0 评论 1 0 0 Ysign Xsign 1 M R L X/Y 符号和 R/L/M 按钮 2 X7 X6 X5 X4 X3 X2 X1 X0 X 数据字节 3 Y7 Y6 是5 Y4 Y3 是2 是1 Y0 Y 数据字节 4 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 Z/wheel 数据字节 激活 PS/2 鼠标上的按钮 4-5 和滚轮 标准 PS/2 兼容鼠标数据包格式 (2 个按钮) 7 备注 Windows 鼠标驱动程序不会检查溢出位。 发生溢出时,鼠标应仅发送最大有符号位 移值。 标准 PS/2 兼容鼠标数据包格式 (3 个按钮 + 垂直轮) Byte D7 D6 D5 D4 D3 D2 D1 D0 评论 1 0 0 Ysign Xsign 1 M R L X/Y 符号和 R/L/M 按钮 2 X7 X6 X5 X4 X3 X2 X1 X0 X 数据字节 3 Y7 Y6 是5 Y4 Y3 是2 是1 Y0 Y 数据字节 4 0 0 B5 B4 Z3 Z2 Z1 Z0 Z/wheel 数据和按钮 4 和 5 以下设备不需要供应商驱动程序: 符合 HID 标准的设备。 由系统提供的非 HIDClass 驱动程序操作的键盘、鼠标或游戏端口设备。 Kbfiltr 旨在与 Kbdclass(键盘设备的系统类驱动程序)和 I8042prt(PS/2 样式键盘的功 能驱动程序)一起使用。 Kbfiltr 演示如何筛选 I/O 请求,以及如何添加用于修改 Kbdclass 和 I8042prt 操作的回调例程。 有关 Kbfiltr 操作的详细信息,请参阅以下内容: ntddkbd.h WDK 头文件。 示例 Kbfiltr 源代码。 标准 PS/2 兼容鼠标数据包格式 (5 个按钮 + 垂直轮) ) 重要 请注意,5 按钮滚轮鼠标的 Z/wheel 数据已减少到 4 位,而不是 IntelliMouse 兼容 3 按钮滚轮模式中使用的 8 位。 这种减少的原因是轮子通常不能在任何给定的中断期 间生成超出 +7/-8 范围的值。 当鼠标处于 5 按钮滚轮模式时,Windows 鼠标驱动程 序将签署扩展四个 Z/wheel 数据位,当鼠标在 3 按钮滚轮模式下运行时,将签署完 整的 Z/wheel 数据字节。 上的按钮 4 & 5 映射到WM_APPCOMMAND消息,并对应于App_Back和 App_Forward。 不需要供应商驱动程序的设备 Kbfiltr 示例 Kbfiltr IOCTLs IOCTL_INTERNAL_I8042_HOOK_KEYBOARD请求执行以下操作: 将初始化回调例程添加到 I8042prt 键盘初始化例程。 将 ISR 回调例程添加到 I8042prt 键盘 ISR。 初始化和 ISR 回调是可选的,由 PS/2 样式键盘设备的上层筛选器驱动程序提供。 I8042prt 收到 IOCTL_INTERNAL_KEYBOARD_CONNECT 请求后,它会将同步 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD 请求发送到键盘设备堆栈顶部。 Kbfiltr 收到挂钩键盘请求后,Kbfiltr 按以下方式筛选请求: 保存传递给 Kbfiltr 的上层信息,其中包括上层设备对象的上下文、指向初始化回调 的指针和指向 ISR 回调的指针。 将上层信息替换为自己的信息。 保存 I8042prt 的上下文和指向 Kbfiltr ISR 回调可以使用的回调的指针。 IOCTL_INTERNAL_KEYBOARD_CONNECT请求将 Kbdclass 服务连接到键盘设备。 Kbdclass 在打开键盘设备之前,会将此请求发送到键盘设备堆栈。 在 Kbfiltr 收到键盘连接请求后,Kbfiltr 按以下方式筛选连接请求: 保存 Kbdclass CONNECT_DATA (Kbdclass) 结构的副本,该结构由 Kbdclass 传递给 筛选器驱动程序。 将自己的连接信息替换为类驱动程序连接信息。 在设备堆栈中向下发送 IOCTL_INTERNAL_KEYBOARD_CONNECT 请求。 如果请求不成功,Kbfiltr 会以适当的错误状态完成请求。 Kbfiltr 为筛选器服务回调例程提供了一个模板,该例程可以补充 KeyboardClassServiceCallback(Kbdclass 类服务回调例程)的操作。 筛选器服务回调可 以筛选从设备输入缓冲区传输到类数据队列的输入数据。 IOCTL_INTERNAL_KEYBOARD_DISCONNECT请求已完成,状态为 STATUS_NOT_IMPLEMENTED。 请注意,即插即用管理器可以添加或删除即插即用键盘。 对于所有其他设备控制请求,Kbfiltr 会跳过当前 IRP 堆栈,并在设备堆栈中向下发送请 求,而无需进一步处理。 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD IOCTL_INTERNAL_KEYBOARD_CONNECT IOCTL_INTERNAL_KEYBOARD_DISCONNECT 请参阅 PI8042_KEYBOARD_INITIALIZATION_ROUTINE 如果键盘的默认初始化 I8042prt 足够,则不需要 KbFilter_InitializationRoutine 。 I8042prt 在初始化键盘时调用 KbFilter_InitializationRoutine 。 默认键盘初始化包括以下 操作: 重置键盘 设置类型速率和延迟 将发光二元 (LED) C++ Kbfiltr 实现的回调例程 KbFilter_InitializationRoutine /* Parameters DeviceObject [in] Pointer to the device object that is the context for this callback. SynchFuncContext [in] Pointer to the context for the routines pointed to by ReadPort and Writeport. ReadPort [in] Pointer to the system-supplied PI8042_SYNCH_READ_PORT callback that reads from the port. WritePort [in] Pointer to the system-supplied PI8042_SYNCH_WRITE_PORT callback that writes to the port. TurnTranslationOn [out] Specifies, if TRUE, to turn translation on. Otherwise, translation is turned off. Return value KbFilter_InitializationRoutine returns an appropriate NTSTATUS code. */ NTSTATUS KbFilter_InitializationRoutine( In PDEVICE_OBJECT DeviceObject, In PVOID SynchFuncContext, In PI8042_SYNCH_READ_PORT ReadPort, In PI8042_SYNCH_WRITE_PORT WritePort, Out PBOOLEAN TurnTranslationOn ); 请参阅 PI8042_KEYBOARD_ISR。 如果 I8042prt 的默认操作足够,则不需要此回调。 I8042prt 键盘 ISR 在验证中断并读取扫描代码后调用 KbFilter_IsrHook 。 KbFilter_IsrHook 在 I8042prt 键盘的 IRQL 的内核模式下运行。 C++ KbFilter_IsrHook /* Parameters DeviceObject [in] Pointer to the filter device object of the driver that supplies this callback. CurrentInput [in] Pointer to the input KEYBOARD_INPUT_DATA structure that is being constructed by the ISR. CurrentOutput [in] Pointer to an OUTPUT_PACKET structure that specifies the bytes that are being written to the hardware device. StatusByte [in, out] Specifies the status byte that is read from I/O port 60 when an interrupt occurs. DataByte [in] Specifies the data byte that is read from I/O port 64 when an interrupt occurs. ContinueProcessing [out] Specifies, if TRUE, to continue processing in the I8042prt keyboard ISR after this callback returns; otherwise, processing is not continued. ScanState [in] Pointer to a KEYBOARD_SCAN_STATE structure that specifies the keyboard scan state. Return value KbFilter_IsrHook returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE. */ KbFilter_IsrHook KbFilter_IsrHook( In PDEVICE_OBJECT DeviceObject, In PKEYBOARD_INPUT_DATA CurrentInput, In POUTPUT_PACKET CurrentOutput, Inout UCHAR StatusByte, In PUCHAR DataByte, Out PBOOLEAN ContinueProcessing, 请参阅 PSERVICE_CALLBACK_ROUTINE。 函数驱动程序的 ISR 调度完成例程 调用 KbFilter_ServiceCallback,然后调用键盘类驱动 程序的 PSERVICE_CALLBACK_ROUTINE 实现。 供应商可以实现筛选器服务回调,以修改 从设备的输入缓冲区传输到类数据队列的输入数据。 例如,回调可以删除、转换或插入 数据。 C++ Moufiltr 设计用于 Mouclass(用于 Windows 2000 及更高版本的鼠标设备的系统类驱动 程序)和 I8042prt(用于 Windows 2000 及更高版本的 PS/2 样式鼠标的功能驱动程 In PKEYBOARD_SCAN_STATE ScanState ); KbFilter_ServiceCallback /* Parameters DeviceObject [in] Pointer to the class device object. InputDataStart [in] Pointer to the first keyboard input data packet in the input data buffer of the port device. InputDataEnd [in] Pointer to the keyboard input data packet that immediately follows the last data packet in the input data buffer of the port device. InputDataConsumed [in, out] Pointer to the number of keyboard input data packets that are transferred by the routine. Return value None */ VOID KbFilter_ServiceCallback( In PDEVICE_OBJECT DeviceObject, In PKEYBOARD_INPUT_DATA InputDataStart, In PKEYBOARD_INPUT_DATA InputDataEnd, Inout PULONG InputDataConsumed ); Moufiltr 示例 序)。 Moufiltr 演示如何筛选 I/O 请求并添加用于修改 Mouclass 和 I8042prt 操作的回调 例程。 有关 Moufiltr 操作的详细信息,请参阅以下内容: ntddmou.h WDK 头文件。 示例 Moufiltr 源代码。 IOCTL_INTERNAL_I8042_HOOK_MOUSE请求将 ISR 回调例程添加到 I8042prt 鼠标 ISR。 ISR 回调是可选的,由高级鼠标筛选器驱动程序提供。 I8042prt 在收到 IOCTL_INTERNAL_MOUSE_CONNECT 请求后发送此请求。 I8042prt 将 同步 IOCTL_INTERNAL_I8042_HOOK_MOUSE 请求发送到鼠标设备堆栈的顶部。 Moufiltr 收到挂钩鼠标请求后,按以下方式筛选请求: 保存传递给 Moufiltr 的上层信息,其中包括高级设备对象的上下文和指向 ISR 回调 的指针。 将上层信息替换为其自己的信息。 保存 I8042prt 的上下文和指向 Moufiltr ISR 回调可以使用的回调的指针。 IOCTL_INTERNAL_MOUSE_CONNECT请求将 Mouclass 服务连接到鼠标设备。 IOCTL_INTERNAL_MOUSE_DISCONNECT请求由 Moufiltr 完成,错误状态为 STATUS_NOT_IMPLEMENTED。 对于所有其他请求,Moufiltr 会跳过当前 IRP 堆栈,并将请求向下发送到设备堆栈,而无 需进一步处理。 Moufiltr 控制代码 IOCTL_INTERNAL_I8042_HOOK_MOUSE Moufiltr 回调例程 IOCTL_INTERNAL_MOUSE_CONNECT IOCTL_INTERNAL_MOUSE_DISCONNECT 回调例程 请参阅 PI8042_MOUSE_ISR。 C++ MouFilter_IsrHook /* Parameters DeviceObject Pointer to the filter device object of the driver that supplies this callback. CurrentInput Pointer to the input MOUSE_INPUT_DATA structure being constructed by the ISR. CurrentOutput Pointer to the OUTPUT_PACKET structure that specifies the bytes being written to the hardware device. StatusByte Specifies a status byte that is read from I/O port 60 when the interrupt occurs. DataByte Specifies a data byte that is read from I/O port 64 when the interrupt occurs. ContinueProcessing Specifies, if TRUE, that the I8042prt mouse ISR continues processing after this callback returns. Otherwise, processing is not continued. MouseState Pointer to a MOUSE_STATE enumeration value, which identifies the state of mouse input. ResetSubState Pointer to MOUSE_RESET_SUBSTATE enumeration value, which identifies the mouse reset substate. See the Remarks section. Return value MouFilter_IsrHook returns TRUE if the interrupt service routine should continue; otherwise it returns FALSE. */ BOOLEAN MouFilter_IsrHook( PDEVICE_OBJECT DeviceObject, PMOUSE_INPUT_DATA CurrentInput, POUTPUT_PACKET CurrentOutput, UCHAR StatusByte, PUCHAR DataByte, PBOOLEAN ContinueProcessing, PMOUSE_STATE MouseState, 如果 I8042prt 的默认操作足够,则不需要 MouFilter_IsrHook 回调。 I8042prt 鼠标 ISR 在验证中断后调用 MouFilter_IsrHook 。 为了重置鼠标,I8042prt 会经历一系列操作子状态,其中每个子状态都由 MOUSE_RESET_SUBSTATE枚举值标识。 有关 I8042prt 如何重置鼠标以及相应的鼠标重置 子状态的详细信息,请参阅 ntdd8042.h 中MOUSE_RESET_SUBSTATE的文档。 MouFilter_IsrHook 在 I8042prt 鼠标 ISR 的 IRQL 的内核模式下运行。 请参阅 PSERVICE_CALLBACK_ROUTINE C++ I8042prt 的 ISR DPC 调用 MouFilter_ServiceCallback,然后调用 MouseClassServiceCallback。 可以将筛选器服务回调配置为修改从设备的输入缓冲区传 PMOUSE_RESET_SUBSTATE ResetSubState ); MouFilter_ServiceCallback /* Parameters DeviceObject [in] Pointer to the class device object. InputDataStart [in] Pointer to the first mouse input data packet in the input data buffer of the port device. InputDataEnd [in] Pointer to the mouse input data packet immediately following the last data packet in the port device's input data buffer. InputDataConsumed [in, out] Pointer to the number of mouse input data packets that are transferred by the routine. Return value None */ VOID MouFilter_ServiceCallback( _In_ PDEVICE_OBJECT DeviceObject, _In_ PMOUSE_INPUT_DATA InputDataStart, _In_ PMOUSE_INPUT_DATA InputDataEnd, _Inout_ PULONG InputDataConsumed ); 输到类数据队列的输入数据。 例如,回调可以删除、转换或插入数据。 传感器 HID 类驱动程序 项目 • 2023/06/15 从 Windows 8 开始,Windows 操作系统包括一个内置传感器 HID 类驱动程序 (SensorsHIDClassDriver.dll) ,它支持使用 HID 传输进行通信的 11 种传感器类型。 下面是支持的传感器列表: 加速计 3D 环境光 环境温度 气压 指南针 3D 设备方向 陀螺仪 3D 湿度 测斜仪 3D 状态 邻近帮助 下图描绘了从两个传感器应用程序到驱动程序堆栈,最后到硬件本身的来回数据流。 除了前面列表中介绍的 11 个传感器外,类驱动程序还支持 Custom 类。 此类允许传感器 制造商集成上一个列表中未找到的设备:例如,一氧化碳传感器。 自定义传感器将自身 作为具有唯一属性的自定义设备呈现给传感器 API。 如果要为兼容传感器创建固件,则需要基本了解类驱动程序支持的 I/O 模型。 传感器将功能报告或输入报告发送到 HID 类驱动程序。 将发送功能报告以响应来自 驱动程序的请求。 此报表包含属性数据,包括传感器的更改敏感度设置、报告间隔 和报告状态。 输入报告是按请求发送的,也可以异步发送以响应事件。 此报表包含 实际的传感器数据。 例如,对于加速计,报表包含沿 x 轴、y 轴和 z 轴) 的 G 力。 HID 类驱动程序将功能报告发送到传感器。 例如,当应用程序请求新的更改敏感度 或报告间隔时,驱动程序会将这些值打包到功能报表中,并使用此报告将请求发送 到传感器的固件。 下图演示了 I/O 模型: 支持自定义传感器 体系结构和概述 如果传感器支持类驱动程序原生的七个类别之一,则其固件需要支持特定功能和输入报 告。 功能报告包括传感器的当前报告状态、状态、更改敏感度和报告间隔 (,以及) 的其 他可能属性。 输入报告包含传感器读数:对于开关为 True 或 False,对于加速计为 G 力 值,对于环境光传感器为 LUX。 示例报告描述符 下面的代码示例显示了加速计的 HID 功能报告。 请注意此报表的自我描述性。 它包括最 小值和最大值以及单个字段的计数和大小。 syntax 下面的代码示例演示同一设备的 HID 输入报告。 同样,请注意此报表中字段的自我描述 性。 syntax 示例加速计功能报告 //feature reports (xmit/receive) HID_USAGE_PAGE_SENSOR, HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_8(0xFF), //LOGICAL_MAXIMUM (255) HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), HID_FEATURE(Data_Var_Abs), HID_USAGE_SENSOR_PROPERTY_SENSOR_STATUS, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_8(0xFF), //LOGICAL_MAXIMUM (255) HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), HID_FEATURE(Data_Var_Abs), HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_16(0xFF,0xFF), //LOGICAL_MAXIMUM (65535) HID_REPORT_SIZE(16), HID_REPORT_COUNT(1), HID_USAGE_SENSOR_UNITS_G, HID_UNIT_EXPONENT(0xE), HID_FEATURE(Data_Var_Abs), HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_32(0xFF,0xFF,0xFF,0xFF), //LOGICAL_MAXIMUM (4294967295) HID_REPORT_SIZE(32), HID_REPORT_COUNT(1), HID_USAGE_SENSOR_UNITS_MILLISECOND, HID_UNIT_EXPONENT(0), HID_FEATURE(Data_Var_Abs), 示例加速计输入报告 //input reports (transmit) HID_USAGE_PAGE_SENSOR, HID_USAGE_SENSOR_STATE, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_8(0xFF), //LOGICAL_MAXIMUM (255) HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), HID_INPUT(Data_Var_Abs), HID_USAGE_SENSOR_EVENT, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_8(0xFF), //LOGICAL_MAXIMUM (255) HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), HID_INPUT(Data_Var_Abs), HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS, HID_LOGICAL_MIN_16(0x01,0x80), // LOGICAL_MINIMUM (-32767) HID_LOGICAL_MAX_16(0xFF,0x7F), // LOGICAL_MAXIMUM (32767) HID_REPORT_SIZE(16), HID_REPORT_COUNT(1), HID_USAGE_SENSOR_UNITS_G, HID_UNIT_EXPONENT(0xE), HID_INPUT(Data_Var_Abs), HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS, HID_LOGICAL_MIN_16(0x01,0x80), // LOGICAL_MINIMUM (-32767) HID_LOGICAL_MAX_16(0xFF,0x7F), // LOGICAL_MAXIMUM (32767) HID_REPORT_SIZE(16), HID_REPORT_COUNT(1), HID_USAGE_SENSOR_UNITS_G, HID_UNIT_EXPONENT(0xE), HID_INPUT(Data_Var_Abs), HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS, HID_LOGICAL_MIN_16(0x01,0x80), // LOGICAL_MINIMUM (-32767) HID_LOGICAL_MAX_16(0xFF,0x7F), // LOGICAL_MAXIMUM (32767) HID_REPORT_SIZE(16), HID_REPORT_COUNT(3), HID_USAGE_SENSOR_UNITS_G, HID_UNIT_EXPONENT(0xE), HID_INPUT(Data_Var_Abs), HID_USAGE_SENSOR_DATA_MOTION_INTENSITY, HID_LOGICAL_MIN_8(0x00), //LOGICAL_MINIMUM (0) HID_LOGICAL_MAX_8(0xFF), //LOGICAL_MAXIMUM (255) HID_REPORT_SIZE(8), HID_REPORT_COUNT(1), HID_INPUT(Data_Var_Abs), 飞行模式无线管理 项目 • 2023/06/14 从Windows 8开始,Windows 操作系统通过 HID 为飞行模式无线电管理控件提供支持。 飞行模式的目的是允许电脑制造商提供按钮或开关 (,并可能提供 LED 来指示状态) ,使 最终用户能够在一次拍摄中打开/关闭所有无线控件。 这主要使需要打开/关闭飞行模式 的用户能够以编程方式执行此操作,允许操作系统 () 识别交换机的状态, (b) 通过软件控 制各种无线无线电。 Windows 支持通用桌面使用情况页上的以下 HID 用法。 用法 ID 用法名称 使用情况类型 0x000C 无线无线电控制器 CollectionApplication (CA) 0x00C6 无线单选按钮 开/关控制 (OOC) 0x00C7 无线无线电 LED 开/关控制 (OOC) 0x00C8 无线无线电滑块开关 开/关控制 (OOC) 下面是提供无线电管理/飞行模式支持的 HID 客户端的体系结构图。 体系结构和概述 ShellHW 检测服务 (SHSVCD.dll) 是在用户模式下运行的 HID 客户端驱动程序/服务,并为 无线电管理设备提供支持。 它监视是否存在类型的 HID 顶级集合 USAGE_PAGE (通用桌面) 05 01 USAGE (无线无线电控制) 09 0C 以下部分提供了电脑制造商必须利用的示例报告描述符。 请注意,如果顶级集合是已具 有另一个顶级集合的报表描述符的一部分,则必须包含报表 ID, () 的示例中未显示。 以下部分为电脑制造商提供了其他信息,并确定最适合其系统设计的报告描述符示例: 无状态按钮通常用于键盘使用者控制按钮, (独立或与许多移动系统上的函数按钮结 合使用, (例如 Fn+F5) ) 。 滑块开关通常用于具有物理滑块开/关开关的移动系统 (例如,具有 on 飞行模式打 开/关闭开关) 的笔记本电脑。 LED 通常用作独立飞机的更多指示器,或与无状态按钮或滑块开关结合使用。 窗口 用户不需要在移动外形规格系统上使用此 LED,因为 UI 中围绕飞行模式有视觉指 示。 无状态按钮(不带 LED) syntax 带 LED 的无状态按钮 syntax 示例报表描述符 USAGE_PAGE (Generic Desktop) 05 01 USAGE (Wireless Radio Controls) 09 0C COLLECTION (Application) A1 01 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 USAGE (Wireless Radio Button) 09 C6 REPORT_COUNT (1) 95 01 REPORT_SIZE (1) 75 01 INPUT (Data,Var,Rel) 81 06 REPORT_SIZE (7) 75 07 INPUT (Cnst,Var,Abs) 81 03 END_COLLECTION C0 USAGE_PAGE (Generic Desktop) 05 01 USAGE (Wireless Radio Controls) 09 0C COLLECTION (Application) A1 01 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 不带 LED) 的滑块开关 ( syntax 带 LED 的滑块开关 syntax USAGE (Wireless Radio Button) 09 C6 REPORT_COUNT (1) 95 01 REPORT_SIZE (1) 75 01 INPUT (Data,Var,Rel) 81 06 REPORT_SIZE (7) 75 07 INPUT (Cnst,Var,Abs) 81 03 USAGE (Wireless Radio LED) 09 C7 REPORT_SIZE (1) 75 01 OUTPUT (Data,Var,Rel) 91 02 REPORT_SIZE (7) 75 07 OUTPUT (Cnst,Var,Abs) 91 03 END_COLLECTION C0 USAGE_PAGE (Generic Desktop) 05 01 USAGE (Wireless Radio Controls) 09 0C COLLECTION (Application) A1 01 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 USAGE (Wireless Radio Slider Switch) 09 C8 REPORT_COUNT (1) 95 01 REPORT_SIZE (1) 75 01 INPUT (Data,Var,Abs) 81 02 REPORT_SIZE (7) 75 07 INPUT (Cnst,Var,Abs) 81 03 END_COLLECTION C0 USAGE_PAGE (Generic Desktop) 05 01 USAGE (Wireless Radio Controls) 09 0C COLLECTION (Application) A1 01 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 USAGE (Wireless Radio Slider Switch) 09 C8 REPORT_COUNT (1) 95 01 REPORT_SIZE (1) 75 01 INPUT (Data,Var,Abs) 81 02 REPORT_SIZE (7) 75 07 INPUT (Cnst,Var,Abs) 81 03 USAGE (Wireless Radio LED) 09 C7 REPORT_SIZE (1) 75 01 OUTPUT (Data,Var,Rel) 91 02 REPORT_SIZE (7) 75 07 OUTPUT (Cnst,Var,Abs) 91 03 END_COLLECTION C0 仅 LED (无按钮或滑块) syntax 提示 #1:使用单选管理器 BUTTON 时,电脑制造商应在释放按钮时而不是按下按钮时发 送一份 HID 报告。 这是因为切换按钮通常是相对输入,而不是绝对输入。 提示 #2:飞行模式无线电管理 HID 用法仅适用于 (电池供电) 的移动系统,并且需要 Windows 8或更高版本的 Windows。 提示 #3:有关飞行模式单选管理按钮的详细信息,请参阅键盘增强功能以Windows 8白 皮书。 提示 #4:有关按钮的详细信息,并确保实现正确的硬件,请查看Windows 8系统徽标要 求。 USAGE_PAGE (Generic Desktop) 05 01 USAGE (Wireless Radio Controls) 09 0C COLLECTION (Application) A1 01 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 USAGE (Wireless Radio LED) 09 C7 REPORT_COUNT (1) 95 01 REPORT_SIZE (1) 75 01 OUTPUT (Data,Var,Rel) 91 02 REPORT_SIZE (7) 75 07 OUTPUT (Cnst,Var,Abs) 91 03 END_COLLECTION C0 排查常见错误 显示器亮度控制 项目 • 2023/06/15 从Windows 8开始,添加了标准化解决方案,允许键盘 (外部或嵌入笔记本电脑) ,通过 HID 控制笔记本电脑或平板电脑的屏幕亮度。 HID 委员会最近批准的 HID 审查请求 41 中介绍了此解决方案。 Windows 8作为使用者控件顶级集合的一部分,提供对屏幕亮度增加/降低的支持。 Windows 8支持下表中列出的 HID 用法: 用法 ID 用法名称 使用情况类型 0x006F 亮度增量 重新触发控制 (RTC) 0x0070 亮度递减 重新触发控制 (RTC) 注意这些 HID 用法仅在 (电池供电) 的移动系统上运行,需要Windows 8。 以下部分提供电脑制造商必须利用的示例报告描述符。 请注意,如果顶级集合是已具有 另一个顶级集合的报表描述符的一部分,则必须包含报表 ID, (以下) 示例中未显示。 syntax 重要说明 当用户按下某个键时,将生成一个输入报告来标识该键。 释放密钥时,将发出使用 情况值为 0 的输入报告。 体系结构和概述 示例报表描述符 Usage Page (Consumer) Usage (Consumer Control) Collection (Application) Logical Minimum (0x00) Logical Maximum (0x3FF) Usage Minimum (0x00) Usage Maximum (0x3FF) Report Size (16) Report Count (1) Input (Data, Array, Absolute) End Collection 一次只有一个使用情况处于活动状态并发送。 使用者控件不允许同时按下多个按 钮。 发送新用法时,假定释放了上一个密钥的用法。 亮度上升/降低是重触发键,其重复率由 Windows 处理。 当用户按下这些密钥时, 硬件不应继续重新发送使用情况。 硬件应仅在按下按钮时发送输入报告,在释放键 时发送另一个输入报告。 提示 #1:亮度递增/递减 HID 使用情况仅在 (电池供电) 且需要Windows 8的移动系统上 运行。 提示 #2:如果系统连接到外部监视器,则亮度递增/递减将不起作用,因为旧监视器传输 不支持向它们/从它们传送 HID 消息的功能。 排查常见错误 HID 传输概述 项目 • 2023/06/15 Transport 内置微型驱动程 序 版本 备注 USB Hidusb.sys Windows 7 及 更高版本。 在可追溯到 Windows 2000 的 Windows 操作系统 上提供对 USB HID 1.11+ 的支持。 Bluetooth Hidbth.sys Windows 7 及 更高版本。 在可追溯到 Windows Vista 的 Windows 操作系统 上提供对蓝牙 HID 1.1+ 的支持。 蓝牙 LE HidBthLE.dll Windows 8 和 更高版本。 Windows 8引入了对通过蓝牙 LE 的 HID 的支持。 I²C Hidi2c.sys Windows 8 和 更高版本。 Windows 8引入了对 I2C 的 HID 的支持。 GPIO Hidinterrupt.sys Windows 10 及更高版本。 Windows 10引入了对常规用途 I/O (GPIO) 按钮的 支持。 SPI HidSpi.sys Windows 10 及更高版本。 Windows 11引入了对串行外设接口的 HID 的支 持, (SPI) 。 Microsoft 建议将随附的驱动程序用于上表中列出的传输。 如果设备需要 USB、蓝牙、蓝牙 LE 或 I²C 以外的传输,建议使用 传输微型驱动程序 中所 述的微型端口驱动程序。 报表描述符长度 传输微型驱动程序以 HID_DESCRIPTOR 结构将报表描述符提交到 Hidclass。 无论 传输协议定义用于向其设备传输 HID 报表描述符的大小如何,在 Hidclass 和 HID 微 型驱动程序之间的通信期间,实际的报表描述符大小都会受到限制。 报表描述符中的 TLC Hidclass/Hidparse 驱动程序对知道报表描述符中的 TLC 数。 HID 微型端口驱动程序 没有该信息。 每个 TLC 至少有 2 个字节用于启动集合,1 个字节用于结束集合。 输入/输出/功能报告长度 Windows 中支持的 HID 传输 HID 传输限制 Hidclass/Hidparse 驱动程序对定义 HID 输入、输出和功能报告的长度。 限制为 8 KB (减去 1 位) 。 即使 HID 微型驱动程序可以请求传输超过 8 KB 的报表,也只会成 功传输小于 8 KB 的报表。 内置微型驱动程序 报表描述符长度 一个报表描述符中的 TLC 输入/输出/功能报告长度 Hidclass/Hidparse 65535 字节 21845 8 KB - 1 位 Hidusb 65535 字节 空值 64 KB Hidbth 65535 字节 空值 64 KB HidBthLE 65535 字节 空值 64 KB Hidi2c 65535 字节 空值 64 KB Hidspi 65535 字节 空值 64 KB Windows 硬件实验室工具包中的 USB 通用 HID 测试 (HLK) 涵盖 HidUsb 和 HidClass 驱动 程序。 第三方 HID 微型驱动程序没有 HLK 测试。 另请参阅 ACPI 按钮设备 项目 • 2023/06/15 通用按钮设备是一种标准设备,用于通过硬件中断报告按钮事件,并将这些中断映射到人 机接口设备 (HID) 规范中定义的特定用法。 为了向操作系统表达按钮的功能,需要两条信息: HID 控件的用法 控件所属的 HID 集合的用法 使用情况是使用情况页和使用情况 ID 的组合。 例如,“调高音量”按钮标识为“ (使用量”页 0x0C、“使用者控制”集合中的“使用情况 ID”0xE9) (“使用情况”页0x0C、使用情况 ID 0x01) 。 通用按钮设备的 ACPI 设备 ID 为 ACPI0011。 Windows 加载 Microsoft 提供的内置驱动程 序,Hidinterrupt.sys该设备。 有关通用按钮设备的详细信息,请访问 统一可扩展固件接口 规范网站,并下载 ACPI 规范版本 6.0 PDF 文档。 然后使用左侧窗格导航到 第 9.19 节。 描述 ACPI 源语言 (ASL) 运行Windows 10 核心 OS 的设备按钮的示例。 ASL 适用于 Windows 10 Core OS 版本的示例 ACPI 按钮设备 // Sample Buttons in ACPI Source Language for Windows 10. Device(BTNS) { Name(_HID, "ACPI0011") Name(_CRS, ResourceTemplate() { GpioInt(Edge, ActiveBoth,...) {pin} // Index 0: Power Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 1: Volume Up Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 2: Volume Down Button GpioInt(Edge, ActiveHigh,...) {pin} // Index 3: Camera Auto-focus Button GpioInt(Edge, ActiveLow,...) {pin} // Index 4: Camera Shutter Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 5: Back Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 6: Windows/Home Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 7: Search Button }) Name(_DSD, Package(2) { //UUID for HID Button Descriptors: ToUUID("FA6BD625-9CE8-470D-A2C7-B3CA36C4282E"), //Data structure for this UUID: Package(9) { Package(5) { 0, // This is a Collection 1, // Unique ID for this Collection 0, // This is a Top-Level Collection 0x01, // Usage Page ("Generic Desktop Page") 0x0D // Usage ("Portable Device Control") }, Package(5) { 1, // This is a Control 0, // Interrupt index in _CRS for Power Button 1, // Unique ID of Parent Collection 0x01, // Usage Page ("Generic Desktop Page") 0x81 // Usage ("System Power Down") }, Package(5) { 1, // This is a Control 1, // Interrupt index in _CRS for Volume Up Button 1, // Unique ID of Parent Collection 0x0C, // Usage Page ("Consumer Page") 0xE9 // Usage ("Volume Increment") }, Package(5) { 1, // This is a Control 2, // Interrupt index in _CRS for Volume Down Button 1, // Unique ID of Parent Collection 0x0C, // Usage Page ("Consumer Page") 0xEA // Usage ("Volume Decrement") }, Package(5) { 1, // This is a Control 3, // Interrupt index in _CRS for Camera Auto-focus Button 1, // Unique ID of Parent Collection 0x90, // Usage Page ("Camera Control Page") 0x20 // Usage ("Camera Auto-focus") }, Package(5) { 1, // This is a Control 4, // Interrupt index in _CRS for Camera Shutter Button 1, // Unique ID of Parent Collection 0x90, // Usage Page ("Camera Control Page") 0x21 // Usage ("Camera Shutter") }, Package(5) { 1, // This is a Control 5, // Interrupt index in _CRS for Back Button 1, // Unique ID of Parent Collection 0x0C, // Usage Page ("Consumer Page") 0x224 // Usage ("AC Back") }, Package(5) { 描述 ACPI 源语言 (ASL) 中运行Windows 10桌面版 (家庭版、专业版、企业版和教育版) 的按钮的示例。 ASL 1, // This is a Control 6, // Interrupt index in _CRS for Windows/Home Button 1, // Unique ID of Parent Collection 0x07, // Usage Page ("Keyboard Page") 0xE3 // Usage ("Keyboard Left GUI") }, Package(5) { 1, // This is a Control 7, // Interrupt index in _CRS for Search Button 1, // Unique ID of Parent Collection 0x0C, // Usage Page ("Consumer Page") 0x221 // Usage ("AC Search") } } }) } 适用于运行桌面版Windows 10设备的 ACPI 中的 示例按钮 Device(BTNS) { Name(_HID, "ACPI0011") Name(_CRS, ResourceTemplate() { GpioInt(Edge, ActiveBoth,...) {pin} // Index 0: Power Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 1: Volume Up Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 2: Volume Down Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 3: Windows/Home Button GpioInt(Edge, ActiveBoth,...) {pin} // Index 4: Rotation Lock Button }) Name(_DSD, Package(2) { //UUID for HID Button Descriptors: ToUUID("FA6BD625-9CE8-470D-A2C7-B3CA36C4282E"), //Data structure for this UUID: Package(6) { Package(5) { 0, // This is a Collection 1, // Unique ID for this Collection 0, // This is a Top-Level Collection 0x01, // Usage Page ("Generic Desktop Page") 0x0D // Usage ("Portable Device Control") }, Package(5) { 1, // This is a Control 0, // Interrupt index in _CRS for Power Button 1, // Unique ID of Parent Collection 0x01, // Usage Page ("Generic Desktop Page") 0x81 // Usage ("System Power Down") }, Package(5) { 1, // This is a Control 1, // Interrupt index in _CRS for Volume Up Button 1, // Unique ID of Parent Collection 0x0C, // Usage Page ("Consumer Page") 0xE9 // Usage ("Volume Increment") }, Package(5) { 1, // This is a Control 2, // Interrupt index in _CRS for Volume Down Button 1, // Unique ID of Parent Collection 0x0C, // Usage Page ("Consumer Page") 0xEA // Usage ("Volume Decrement") }, Package(5) { 1, // This is a Control 3, // Interrupt index in _CRS for Windows/Home Button 1, // Unique ID of Parent Collection 0x07, // Usage Page ("Keyboard Page") 0xE3 // Usage ("Keyboard Left GUI") }, Package(5) { 1, // This is a Control 4, // Interrupt index in _CRS for Rotation Lock Button 1, // Unique ID of Parent Collection 0x01, // Usage Page ("Generic Desktop Page") 0xCA // Usage ("System Display Rotation Lock Slider Switch") } } }) } HID 按钮驱动程序 项目 • 2023/06/15 对 GPIO 按钮使用 Microsoft 提供的按钮驱动程序;否则,实现将 HID 数据注入操作系统的 驱动程序。 (电源、Windows、音量和旋转锁) 按钮通常用于在物理键盘对用户不可用时发生的任务, 其外形规格如可转换或平板电脑。 按钮通过提供 HID 按钮报告描述符向操作系统声明自 己为 HID 设备。 这允许系统以标准化的方式解释这些按钮的用途和事件。 当按钮状态更 改时,该事件将映射到 HID 用法。 HID 传输微型驱动程序将这些事件报告给高级驱动程 序,这些驱动程序然后在用户模式或内核模式下将详细信息发送到 HID 客户端。 对于物理通用 I/O (GPIO) 按钮,HID 传输微型驱动程序是 Microsoft 提供的内置驱动程 序,它基于在定义的 GPIO 硬件资源上收到的中断报告事件。 内置驱动程序无法为未连接到中断线的按钮提供服务。 对于此类按钮,需要编写一个驱 动程序,该驱动程序将按钮公开为 HID 按钮,并将状态更改报告给 HID 类驱动程序 (Microsoft 提供的) 。 驱动程序可以是 HID 源驱动程序或 HID 传输驱动程序。 下面是一些常规指针,可帮助你确定在创建 HID 按钮时应遵循的实现。 支持 HID 按钮的指南 如果要实现 GPIO 按钮,请描述系统 ACPI 中的按钮,以便 Windows 可以加载内置驱动 程序(Hidinterrupt.sys)作为向操作系统报告事件的按钮驱动程序。 ACPI 按钮设备 使用 Microsoft 提供的内置按钮驱动程序 按钮行为 Windows 10 Core Edition 的示例按钮 ACPI Microsoft 鼓励你尽可能使用内置 transport-minidrivers。 如果要实现非 GPIO 按钮,例如需要由另一个软件组件注入的 HID 格式数据流,则可以 选择编写内核模式驱动程序。 从 Windows 10 开始,可以通过调用与虚拟 HID 框架 (VHF) 通信的编程接口来编写 HID 源驱动程序,并从 HID 类驱动程序获取和设置 HID 报 告。 如何编写与虚拟 HID 框架交互的 HID 源驱动程序 (VHF) 虚拟 HID 框架参考 或者,可以编写早期版本的 Windows 支持的内核模式 HID 传输微型驱动程序。 但是, 我们不建议使用此方法,因为编写不当的 KMDF HID 传输微型驱动程序可能会让系统崩 溃。 传输微型驱动程序 HID 微型驱动程序 IOCTL 如果要实现非 GPIO 按钮,则可以在用户模式下编写 HID 传输微型驱动程序,而不是使 用前面的编写 HID 源驱动程序的模型。 这些驱动程序比内核模式驱动程序更易于开发, 并且此驱动程序中的错误不会在整个系统中检查 bug。 创建 UMDF HID 微型驱动程序 UMDF HID 微型驱动程序 IOCTL” 在内核模式下编写 HID 源驱动程序 编写 UMDF HID 微型驱动程序 从 Windows 10 开始,HID 驱动程序编程接口是基于 OneCoreUAP 的 Windows 版本的一 部分。 通过使用这组通用接口,可以使用 虚拟 HID 框架 或 传输微型驱动程序 接口编写 按钮驱动程序。 这些驱动程序将在桌面版Windows 10 (家庭版、专业版、企业版和教育 版) Windows 10 移动版以及其他Windows 10版本上运行。 有关分步指南,请参阅使用通用 Windows 驱动程序入门。 人机接口设备 适用于 HID 的通用 Windows 驱动程序按钮 相关主题 使用虚拟 HID 框架 (VHF) 编写 HID 源驱 动程序 项目 • 2023/06/15 该主题解释了如何: (KMDF 编写Kernel-Mode驱动程序框架,) HID 源驱动程序向 Windows 提交 HID 读 取报告。 将 VHF 驱动程序作为较低筛选器加载到虚拟 HID 设备堆栈中的 HID 源驱动程序。 了解如何编写向操作系统报告 HID 数据的 HID 源驱动程序。 HID 输入设备(如键盘、鼠标、笔、触摸或按钮)向操作系统发送各种报告,以便它可以 了解设备的用途并采取必要的操作。 报表采用 HID 集合 和 HID 用法的形式。 设备通过 各种传输方式发送这些报告,其中一些报告受 Windows 支持,例如 I2C 上的 HID 和 USB 上的 HID。 在某些情况下,Windows 可能不支持传输,或者报表可能无法直接映射到实 际硬件。 它可以是 HID 格式的数据流,由另一个软件组件为虚拟硬件发送,例如,对于 非 GPIO 按钮或传感器。 例如,假设手机的加速计数据作为游戏控制器以无线方式发送 到电脑。 在另一个示例中,计算机可以使用 UIBC 协议从 Miracast 设备接收远程输入。 在以前版本的 Windows 中,若要支持新的传输 (实际硬件或软件) ,必须编写 HID 传输微 型驱动程序 并将其绑定到 Microsoft 提供的内置类驱动程序,Hidclass.sys。 类/微型驱动 程序对向高级驱动程序和用户模式应用程序提供 HID 集合,例如 顶级集合 。 在该模型 中,挑战在于编写微型驱动程序,这可以是一项复杂的任务。 从 Windows 10 开始,新的虚拟 HID 框架 (VHF) 无需编写传输微型驱动程序。 相反,可 以使用 KMDF 或 WDM 编程接口编写 HID 源驱动程序。 该框架由 Microsoft 提供的静态 库组成,该库公开驱动程序使用的编程元素。 它还包括 Microsoft 提供的内置驱动程 序,该驱动程序枚举一个或多个子设备,并继续生成和管理虚拟 HID 树。 本主题介绍框架的体系结构、虚拟 HID 设备树和配置方案。 在此图中,设备树显示驱动程序及其关联的设备对象。 7 备注 在此版本中,VHF 仅在内核模式下支持 HID 源驱动程序。 虚拟 HID 设备树 HID 源驱动程序链接到 Vhfkm.lib,并在其生成项目中包括 Vhf.h。 可以使用 Windows 驱 动程序模型 (WDM) 或Kernel-Mode驱动程序框架 (KMDF) (属于 Windows 驱动程序框架 (WDF) )编写驱动程序 。 驱动程序可以作为筛选器驱动程序或函数驱动程序加载到设备 堆栈中。 静态库包含在适用于Windows 10的 Windows 驱动程序工具包 (WDK) 中。 库公开 HID 源 驱动程序使用的编程接口,例如例程和回调函数。 当驱动程序调用函数时,静态库会将 请求转发到处理该请求的 VHF 驱动程序。 Microsoft 提供的内置驱动程序。 此驱动程序必须作为较低筛选器驱动程序加载到 HID 源 设备堆栈中的驱动程序下方。 VHF 驱动程序动态枚举子设备, (PDO) 为 HID 源驱动程序 指定的一个或多个 HID 设备创建物理设备对象。 它还实现枚举子设备的 HID 传输微型驱 动程序功能。 HID 源驱动程序 (驱动程序) VHF 静态库 (vhfkm.lib) VHF 驱动程序 (Vhf.sys) HID 类驱动程序对 (Hidclass.sys,Mshidkmdf.sys) Hidclass/Mshidkmdf 对枚举 顶级集合 (TLC) 类似于它枚举真实 HID 设备的这些集合的方 式。 HID 客户端可以继续请求和使用 TLC,就像真正的 HID 设备一样。 此驱动程序对作 为函数驱动程序安装在设备堆栈中。 查询和使用 HID 设备堆栈报告的 TLC。 此过程介绍如何编写向操作系统报告头戴显示设备按钮的简单 HID 源驱动程序。 在这种 情况下,实现此代码的驱动程序可以是现有的 KMDF 音频驱动程序,该驱动程序已修改 为使用 VHF 充当 HID 源报告头戴显示设备按钮。 1. 包括 WDK for Windows 10 中包含的 Vhf.h。 2. 链接到 WDK 中包含的 vhfkm.lib。 3. 创建设备要向操作系统报告的 HID 报告描述符。 在此示例中,HID 报告描述符描述 头戴显示设备按钮。 报告指定 HID 输入报告,大小为 8 位 (1 字节) 。 前三位用于 头戴显示设备中间、调高音量和调低音量按钮。 其余位未使用。 C++ 7 备注 在某些情况下,HID 客户端可能需要标识 HID 数据的源。 例如,系统具有内置传感 器,并从相同类型的远程传感器接收数据。 系统可能希望选择一个传感器来更可 靠。 为了区分连接到系统的两个传感器,HID 客户端会查询 TLC 的容器 ID。 在这种 情况下,HID 源驱动程序可以提供容器 ID,VHF 将其报告为虚拟 HID 设备的容器 ID。 HID 客户端 (应用程序) 标头和库要求 UCHAR HeadSetReportDescriptor[] = { 0x05, 0x01, // USAGE_PAGE (Generic Desktop Controls) 0x09, 0x0D, // USAGE (Portable Device Buttons) 0xA1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x05, 0x09, // USAGE_PAGE (Button Page) 0x09, 0x01, // USAGE (Button 1 - HeadSet : middle button) 0x09, 0x02, // USAGE (Button 2 - HeadSet : volume up button) 0x09, 0x03, // USAGE (Button 3 - HeadSet : volume down button) 0x15, 0x00, // LOGICAL_MINIMUM (0) 通过调用 VHF_CONFIG_INIT 宏,然后调用 VhfCreate 方法初始化 VHF_CONFIG 结构。 在 WdfDeviceCreate 调用之后,驱动程序必须在 PASSIVE_LEVEL 调用 VhfCreate,通常 在驱动程序的 EvtDriverDeviceAdd 回调函数中调用。 在 VhfCreate 调用中,驱动程序可以指定某些配置选项,例如必须异步处理的操作或设 置设备信息 (供应商/产品 ID) 。 例如,应用程序请求 TLC。 当 HID 类驱动程序对收到该请求时,该对将确定请求的类 型,并创建适当的 HID 微型驱动程序 IOCTL 请求并将其转发到 VHF。 收到 IOCTL 请求 后,VHF 可以处理请求、依赖 HID 源驱动程序来处理请求,或者使用 STATUS_NOT_SUPPORTED完成请求。 VHF 处理以下 IOCTL: IOCTL_HID_GET_STRING IOCTL_HID_GET_DEVICE_ATTRIBUTES IOCTL_HID_GET_DEVICE_DESCRIPTOR IOCTL_HID_GET_REPORT_DESCRIPTOR 如果请求为 GetFeature、 SetFeature、 WriteReport 或 GetInputReport,并且 HID 源 驱动程序注册了相应的回调函数,则 VHF 将调用回调函数。 在该函数中,HID 源驱动程 序可以获取或设置 HID 虚拟设备的 HID 数据。 如果驱动程序未注册回调,VHF 会以状态 STATUS_NOT_SUPPORTED完成请求。 VHF 为以下 IOCTL 调用 HID 源驱动程序实现的事件回调函数: IOCTL_HID_READ_REPORT 如果驱动程序要在提交缓冲区以获取 HID 输入报告时处理缓冲策略,则必须实现 EvtVhfReadyForNextReadReport 并在 EvtVhfAsyncOperationGetInputReport 成 员中指定指针。 有关详细信息,请参阅 提交 HID 输入报告。 IOCTL_HID_GET_FEATURE 或 IOCTL_HID_SET_FEATURE 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x03, // REPORT_COUNT (3) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x05, // REPORT_COUNT (5) 0x81, 0x03, // INPUT (Cnst,Var,Abs) 0xC0, // END_COLLECTION }; 创建虚拟 HID 设备 如果驱动程序想要异步获取或设置 HID 功能报告,驱动程序必须实现 EvtVhfAsyncOperation 函数,并在 VHF_CONFIG 的 EvtVhfAsyncOperationGetFeature 或 EvtVhfAsyncOperationSetFeature 成员中指 定一个指向 get 或 set 实现函数的指针。 IOCTL_HID_GET_INPUT_REPORT 如果驱动程序想要异步获取 HID 输入报告,驱动程序必须实现 EvtVhfAsyncOperation 函数,并在 VHF_CONFIG 的 EvtVhfAsyncOperationGetInputReport 成员中指定指向函数的指针。 IOCTL_HID_WRITE_REPORT 如果驱动程序想要异步获取写入 HID 输入报告,则驱动程序必须实现 EvtVhfAsyncOperation 函数,并在 VHF_CONFIG 的 EvtVhfAsyncOperationWriteReport 成员中指定指向函数的指针。 对于任何其他 HID 微型驱动程序 IOCTL,VHF 使用 STATUS_NOT_SUPPORTED 完成请 求。 通过调用 VhfDelete 删除虚拟 HID 设备。 如果驱动程序为虚拟 HID 设备分配了资源,则 需要 EvtVhfCleanup 回调。 驱动程序必须实现 EvtVhfCleanup 函数,并在 VHF_CONFIG 的 EvtVhfCleanup 成员中指定指向该函数的指针。 在 VhfDelete 调用完成之前调用 EvtVhfCleanup 。 有关详细信息,请参阅 删除虚拟 HID 设备。 C++ 7 备注 异步操作完成后,驱动程序必须调用 VhfAsyncOperationComplete 来设置操作的结 果。 可以从事件回调调用 方法,也可以在从回调返回后稍后调用方法。 NTSTATUS VhfSourceCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit ) { WDF_OBJECT_ATTRIBUTES deviceAttributes; PDEVICE_CONTEXT deviceContext; VHF_CONFIG vhfConfig; WDFDEVICE device; NTSTATUS status; PAGED_CODE(); 通过调用 VhfReadReportSubmit 提交 HID 输入报告。 通常,HID 设备通过中断发送输入报告来发送有关状态更改的信息。 例如,当按钮的状 态发生更改时,头戴显示设备可能会发送报告。 在这种情况下,将调用驱动程序的中断 服务例程 (ISR) 。 在该例程中,驱动程序可能会计划延迟过程调用 (DPC) 处理输入报告并 将其提交到 VHF,后者将信息发送到操作系统。 默认情况下,VHF 缓冲报表,HID 源驱 动程序可以在输入报告时开始提交 HID 输入报告。 这样就无需 HID 源驱动程序实现复杂 的同步。 HID 源驱动程序可以通过为挂起的报表实现缓冲策略来提交输入报告。 为了避免重复缓 冲,HID 源驱动程序可以实现 EvtVhfReadyForNextReadReport 回调函数,并跟踪 VHF WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); deviceAttributes.EvtCleanupCallback = VhfSourceDeviceCleanup; status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); if (NT_SUCCESS(status)) { deviceContext = DeviceGetContext(device); VHF_CONFIG_INIT(&vhfConfig, WdfDeviceWdmGetDeviceObject(device), sizeof(VhfHeadSetReportDescriptor), VhfHeadSetReportDescriptor); status = VhfCreate(&vhfConfig, &deviceContext->VhfHandle); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "VhfCreate failed %!STATUS!", status); goto Error; } status = VhfStart(deviceContext->VhfHandle); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "VhfStart failed %!STATUS!", status); goto Error; } } Error: return status; } 提交 HID 输入报告 是否调用了此回调。 如果以前调用过,HID 源驱动程序可以调用 VhfReadReportSubmit 来提交报告。 它必须等待 EvtVhfReadyForNextReadReport 被调用,然后才能再次调用 VhfReadReportSubmit 。 C++ 通过调用 VhfDelete 删除虚拟 HID 设备。 可以通过指定 Wait 参数同步或异步调用 VhfDelete。 对于同步调用,必须在 PASSIVE_LEVEL调用 方法,例如从设备对象的 EvtCleanupCallback 调用。 VhfDelete 在 删除虚拟 HID 设备后返回。 如果驱动程序以异步方式调用 VhfDelete ,它将立即返回 , 并且 VHF 在删除操作完成后调用 EvtVhfCleanup 。 可以在最大DISPATCH_LEVEL调用 方 法。 在这种情况下,驱动程序必须在之前调用 VhfCreate 时注册并实现了 EvtVhfCleanup 回调函数。 下面是 HID 源驱动程序想要删除虚拟 HID 设备时的事件序列: 1. HID 源驱动程序停止对 VHF 的调用。 2. HID 源调用 VhfDelete , 将 Wait 设置为 FALSE。 3. VHF 停止调用 HID 源驱动程序实现的回调函数。 4. VHF 开始向 PnP 管理器报告设备缺失。 此时,VhfDelete 调用可能会返回。 VOID MY_SubmitReadReport( PMY_CONTEXT Context, BUTTON_TYPE ButtonType, BUTTON_STATE ButtonState ) { PDEVICE_CONTEXT deviceContext = (PDEVICE_CONTEXT)(Context); if (ButtonState == ButtonStateUp) { deviceContext->VhfHidReport.ReportBuffer[0] &= ~(0x01 VhfHidReport.ReportBuffer[0] |= (0x01 VhfHandle, &deviceContext- >VhfHidReport); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,"VhfReadReportSubmit failed %!STATUS!", status); } } 删除虚拟 HID 设备 5. 当设备报告为缺失设备时,如果 HID 源驱动程序注册了其实现,VHF 将调用 EvtVhfCleanup 。 6. EvtVhfCleanup 返回后,VHF 将执行其清理。 C++ 在安装 HID 源驱动程序的 INF 文件中,请确保使用 AddReg 指令将 Vhf.sys 声明为 HID 源驱动程序的较低筛选器驱动程序。 C++ 人机接口设备 虚拟 HID 框架回调函数 虚拟 HID 框架方法 虚拟 HID 框架结构 VOID VhfSourceDeviceCleanup( _In_ WDFOBJECT DeviceObject ) { PDEVICE_CONTEXT deviceContext; PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, "%!FUNC! Entry"); deviceContext = DeviceGetContext(DeviceObject); if (deviceContext->VhfHandle != WDF_NO_HANDLE) { VhfDelete(deviceContext->VhfHandle, TRUE); } } 安装 HID 源驱动程序 [HIDVHF_Inst.NT.HW] AddReg = HIDVHF_Inst.NT.AddReg [HIDVHF_Inst.NT.AddReg] HKR,,"LowerFilters",0x00010000,"vhf" 相关主题 “传输微型驱动程序”概述 项目 • 2023/06/14 本部分包含需要创建自己的 HID 微型驱动程序的供应商的详细信息。 如果你的设备需要 USB、蓝牙、蓝牙 LE、I²C、GPIO 作为传输,请使用 Microsoft 提供的内置驱动程序。 若 要查看内置传输微型驱动程序的列表,请参阅 HID 传输。 对于其他传输,需要编写传输微型驱动程序。 HID 微型驱动程序可以使用以下框架之一编写: 1. UMDF - 用户模式驱动程序框架 2. KMDF – 内核模式驱动程序框架 3. WDM - 旧版 Windows 驱动程序模型 注意 Microsoft 鼓励硬件供应商尽可能使用内置传输微型驱动程序。 但是,如果你的设 备需要不受支持的传输,Microsoft 建议使用 Windows 驱动程序框架 (UMDF 或 KMDF) 作为微型驱动程序的驱动程序模型。 仅当 Windows 驱动程序框架不支持特定传输时,才 应创建 WDM 微型驱动程序。 Microsoft 建议开发人员使用 UMDF 框架作为起点。 仅当某个功能对 UMDF 不可用时, 才考虑编写 KMDF 驱动程序。 有关两个驱动程序框架中功能比较的信息,请参阅将 UMDF 2 功能与 KMDF 进行比较。 对于 HID 传输微型驱动程序,KMDF 模型具有以下注意事项: 优点:KMDF 支持在所有支持 WDF 的 Windows 平台中可用。 对于所有键盘和鼠标 筛选器驱动程序是必需的。 挑战:编写不当的 KMDF HID 传输微型驱动程序可能会崩溃系统。 下面是 UMDF 模型的特定于 HID 的注意事项: 优点:UMDF 更易于开发和推荐用于大多数垂直设备类。 此驱动程序中的错误不会 检查整个系统出现 bug。 有关详细信息,请参阅 编写 UMDF 驱动程序的优点。 挑战:Windows 8之前的 Windows 版本不支持 UMDF HID 传输微型驱动程序。 UMDF 驱动程序可以从内核模式驱动程序接收 I/O 请求。 这些转换可能会对性能产 生轻微的影响。 UMDF 入门 另请参阅 将微型驱动程序绑定到 HID 类 项目 • 2023/06/15 本部分介绍系统提供的 HID 类驱动程序和 HID 微型驱动程序的操作,它们支持 HIDClass 设备设置类中的设备。 HID 类驱动程序提供接口,高级驱动程序和用户模式应用程序使用该接口访问输入设备支 持的 HID 集合。 HID 类驱动程序使用 HID 微型驱动程序访问输入设备的硬件。 HID 微型 驱动程序将输入设备连接到的总线端口的操作抽象化。 HID 类驱动程序是链接到 HID 微 型驱动程序的导出驱动程序。 HID 微型驱动程序通过调用 HidRegisterMinidriver 将自己 的操作绑定到 HID 类驱动程序,以将自己注册到 HID 类驱动程序。 HID 类驱动程序和 HID 微型驱动程序的组合操作充当输入设备的 WDM 函数驱动程序和 子设备的总线驱动程序, (HID 集合) 输入设备支持。 此设计使 HID 类驱动程序能够运行 连接到 USB 总线以外的端口或总线的 USB HID 设备和非 USB 输入设备。 基础父设备的 操作详细信息对高级驱动程序或用户模式应用程序是透明的。 微型驱动程序和 HID 类驱动程序 项目 • 2023/03/08 本文介绍微型驱动程序和 HID 类驱动程序。 有关详细信息,请参阅 创建 WDF HID 微型驱动程序。 HID 类驱动程序执行以下操作: 提供和管理内核模式驱动程序和用户模式应用程序用于访问输入设备支持的 HID 集 合 的上层接口。 HID 类驱动程序以透明方式管理和路由上层驱动程序与应用程序与支持 HID 集合的 基础输入设备之间的所有通信。 它管理不同输入设备和输入队列使用的不同数据协 议,这些协议支持同一 HID 集合上的多个打开文件。 HID 集合的上层接口包括 HID 类驱动程序 IOCTLs、 HIDClass 支持例程和 HIDClass 结构。 通过调用微型驱动程序的标准驱动程序例程与 HID 微型驱动程序通信。 为低级别总线或端口驱动程序枚举的 HIDClass 输入设备创建功能设备对象 (FDO) 。 例如,HID 类驱动程序创建和管理 FDO 的操作,该 FDO 表示系统提供的 USB 驱动 程序堆栈枚举的 USB HID 设备。 为基础输入设备支持的 (HID 集合) 子设备提供总线驱动程序的功能。 HID 类驱动程序为输入设备支持的每个 HID 集合创建物理设备对象 (PDO) ,并管理 集合的操作。 HID 微型驱动程序通过调用 HidRegisterMinidriver 向 HID 类驱动程序注册自身,将其操 作绑定到 HID 类驱动程序。 注册操作: 将入口点的副本保存在 HID 类驱动程序的设备扩展中, (指针) 到 HID 微型驱动程序 的标准驱动程序例程。 HID 微型驱动程序在驱动程序对象中设置其入口点,微型驱动程序作为 其 DRIVER_INITIALIZE 例程的输入。 HID 微型驱动程序在向 HID 类驱动程序注册之前 HID 类驱动程序的操作功能 将微型驱动程序绑定到 HIDClass 设置这些入口点。 将微型驱动程序驱动程序对象中的入口点重置为 HID 类驱动程序提供的标准驱动程 序例程的入口点。 HID 类驱动程序提供以下标准驱动程序例程: DRIVER_ADD_DEVICE 和 DRIVER_UNLOAD 例程 为以下 I/O 请求调度例程: IRP_MJ_CREATE IRP_MJ_CLOSE IRP_MJ_DEVICE_CONTROL IRP_MJ_INTERNAL_DEVICE_CONTROL IRP_MJ_PNP IRP_MJ_SYSTEM_CONTROL 注册过程还会为 HID mind River 设备扩展分配内存。 虽然内存由 HID 类驱动程序分配, 但只有 HID 微型驱动程序使用此设备扩展。 HID 类驱动程序通过调用 HID 微型驱动程序的 DRIVER_ADD_DEVICE、 DRIVER_UNLOAD和调度例程来与 HID 微型驱动程序通信,如下所示: 调用 HID 类驱动程序的 AddDevice 例程以创建功能设备对象 (FDO) 时,HID 类驱动程序 将创建 FDO、初始化它并调用 HID 微型驱动程序 AddDevice 例程。 HID 微型驱动程序 AddDevice 例程执行内部设备特定的初始化,如果成功,则返回STATUS_SUCCESS。 如 果 HID 微型驱动程序 AddDevice 例程未成功,则 HID 类驱动程序会删除 FDO 并返回 HID 微型驱动程序 AddDevice 例程返回的状态。 调用 HID 类驱动程序 Unload 例程时,HID 类驱动程序将完成释放与 FDO 关联的所有资 源,并调用 HID 微型驱动程序的 Unload 例程。 与 HID 微型驱动程序通信 调用 AddDevice 例程 调用 Unload 例程 若要操作设备,HID 类驱动程序主要调用 HID 微型驱动程序调度例程,以获取内部设备 控制请求。 当 I/O 管理器将请求发送到 HID 类驱动程序时,HID 类驱动程序将处理请求,并调用 HID 微型驱动程序的相应调度例程。 HID 类驱动程序不会向 HID 微型驱动程序发送以下请求:创建、关闭或设备控制。 HID 传输微型驱动程序抽象化输入设备附加到的硬件总线或端口的操作。 可以使用以下框架之一生成 HID 微型驱动程序: UMDF – 用户模式驱动程序框架 KDMF – 内核模式驱动程序框架 WDF - Windows 驱动程序框架 WDM – Windows 驱动程序模型 (旧版) Microsoft 建议使用基于框架的解决方案 (KMDF 或 UMDF) 。 有关每个驱动程序模型的详 细信息,请访问以下部分: 基于 KMDF 的 HID 微型驱动程序,请参阅创建基于框架的 HID 微型驱动程序 基于 UMDF 的 HID 微型驱动程序,请参阅 创建 WDF HID 微型驱动程序 以下部分介绍如何注册基于 WDM 的 HID 微型驱动程序,但其中大部分都与基于 KMDF 的框架驱动程序相关。 所有 HID 微型驱动程序都必须注册到 HID 类驱动程序,HID 类驱 动程序通过调用微型驱动程序的标准驱动程序例程与微型驱动程序通信。 有关 HID 微型驱动程序在其标准驱动程序例程中必须支持的功能的详细信息,请参阅以 下部分: 注册 HID 微型驱动程序 HID 微型驱动程序扩展 使用HID_DEVICE_EXTENSION结构 标准微型驱动程序例程 有关 HID 类驱动程序的详细信息,请参阅 HID 微型驱动程序的操作。 调用 Dispatch 例程 HID 微型驱动程序的操作 注册 HID 微型驱动程序 HID 微型驱动程序在其 DRIVER_INITIALIZE 例程中完成所有其他驱动程序初始化后,HID 微型驱动程序通过调用 HidRegisterMinidriver 将其操作绑定到 HID 类驱动程序。 当 HID 微型驱动程序注册到 HID 类驱动程序时,它将使用 HID_MINIDRIVER_REGISTRATION 结构。 结构指定: HID 修订 HID 微型驱动程序驱动程序对象 HID 微型驱动程序设备扩展的大小 设备是否轮询 HID 微型驱动程序设备扩展特定于设备,仅由 HID 微型驱动程序使用。 当类驱动程序为 功能设备对象创建其设备扩展时,HID 类驱动程序为微型驱动程序设备扩展分配内存, (FDO) 。 HID 微型驱动程序在将微型驱动程序注册到 HID 类驱动程序时指定其设备扩展 的大小。 大小由HID_MINIDRIVER_REGISTRATION结构的 DeviceExtensionSize 成员指 定。 HID 微型驱动程序必须使用 HID_DEVICE_EXTENSION 结构作为 HID 类驱动程序为功能设 备对象创建的设备扩展的布局, (FDO) 。 HID 类驱动程序在初始化 FDO 时设置此结构的 成员。 HID 微型驱动程序不得更改此结构中的信息。 HID_DEVICE_EXTENSION结构包含以下成员: PhysicalDeviceObject 是指向表示基础输入设备的 PDO) 物理设备 (对象的指针。 NextDeviceObject 是指向 FDO 下设备堆栈顶部的指针。 MiniDeviceExtension 是指向 HID 微型驱动程序设备扩展的指针。 给定指向输入设备的 FDO 的指针,以下GET_MINIDRIVER_DEVICE_EXTENSION宏返回指 向 HID 微型驱动程序扩展的指针: C++ PDEVICE_EXTENSION是指向 HID 微型驱动程序声明的设备特定设备扩展的指针。 HID 微型驱动程序扩展 使用HID_DEVICE_EXTENSION结构 #define GET_MINIDRIVER_DEVICE_EXTENSION(DO) ((PDEVICE_EXTENSION) (((PHID_DEVICE_EXTENSION)(DO)->DeviceExtension)->MiniDeviceExtension)) 同样,HID 微型驱动程序可以获取指向输入设备的 PDO 和输入设备 FDO 下方设备堆栈 顶部的指针。 当 HID 微型驱动程序在设备堆栈下发送 IRP 时,它应使用 NextDeviceObject 作为目标设 备对象。 HID 微型驱动程序必须提供以下标准驱动程序支持例程: HID 微型驱动程序 DriverEntry 例程 HID 微型驱动程序 AddDevice 例程 HID 微型驱动程序卸载例程 HID 微型驱动程序还必须支持 HID 微型驱动程序提供的调度例程中所述的调度例程。 HID 微型驱动程序中的 DRIVER_INITIALIZE 例程执行以下操作: 为 (HID 类驱动程序的链接对和 HID 微型驱动程序) 创建驱动程序对象。 在 HID 微型驱动程序对象中设置所需的驱动程序入口点。 调用 HidRegisterMinidriver ,将 HID 微型驱动程序注册到 HID 类驱动程序。 仅由 HID 微型驱动程序使用的设备特定配置。 HID 类驱动程序处理为基础输入设备创建和初始化功能设备对象 (FDO) 。 HID 类驱动程 序还从上层接口到基础设备及其子设备的角度操作 FDO, (HID 集合) 。 HID 类驱动程序 DRIVER_ADD_DEVICE 例程调用 HID 微型驱动程序 AddDevice 例程,以 便微型驱动程序可以执行特定于设备的内部初始化。 传递给 HID 微型驱动程序 DRIVER_ADD_DEVICE 例程的参数是微型驱动程序对象和 FDO。 HID 类驱动程序将 FDO 传递给微型驱动程序 AddDevice 例程,而不是基础输入设 备的物理设备对象。 HID 微型驱动程序 DRIVER_ADD_DEVICE 例程从 FDO 获取指向微型驱动程序设备扩展的 指针。 通常,HID 微型驱动程序 DRIVER_ADD_DEVICE 例程执行以下操作: 标准微型驱动程序例程 DriverEntry 例程 AddDevice 例程 初始化微型驱动程序设备扩展。 设备扩展仅供微型驱动程序使用。 返回STATUS_SUCCESS。 如果微型驱动程序返回错误状态,HID 类驱动程序将删除 FDO 并将错误状态返回到即插即用管理器。 HID 类驱动程序的 Unload 例程调用 HID 微型驱动程序 DRIVER_UNLOAD 例程。 HID 微 型驱动程序释放微型驱动程序分配的任何内部资源。 HID 微型驱动程序必须提供以下调度例程:创建、关闭、内部设备控制、系统控制、即插 即用和电源管理。 除了内部设备控制请求外,大多数调度例程都提供最少的功能。 当 HID 类驱动程序调用这些调度例程时,它将传递微型驱动程序对象和功能设备对象 (FDO) 。 根据 WDM 要求,HID 类驱动程序和 HID 微型驱动程序提供用于创建请求的调度例程。 但是,无法打开 FDO。 HID 类驱动程序返回STATUS_UNSUCCESSFUL。 HID 微型驱动程序只需要提供存根。 从不调用创建调度例程。 根据 WDM 要求,HID 类驱动程序和 HID 微型驱动程序必须提供关闭请求的调度例程。 但是,无法打开 FDO。 HID 类驱动程序返回STATUS_INVALID_PARAMETER_1。 HID 微型驱动程序只需要提供存根。 从不调用关闭调度例程。 HID 微型驱动程序不需要设备控制请求的调度例程。 HID 类驱动程序不会将设备控制请 求传递给微型驱动程序。 HID 微型驱动程序必须为支持 HID 微型驱动程序 IOCTL 中所述的请求的内部设备控制请 求提供调度例程。 卸载例程 调度例程 IRP_MJ_CREATE IRP_MJ_CLOSE IRP_MJ_DEVICE_CONTROL IRP_MJ_INTERNAL_DEVICE_CONTROL HID 类驱动程序主要使用内部设备控制请求来访问基础输入设备。 HID 微型驱动程序以特定于设备的方式处理这些请求。 HID 微型驱动程序必须为系统控制请求提供调度例程。 但是,仅需要 HID 微型驱动程序 才能将系统控制请求传递到设备堆栈,如下所示: 跳过当前 IRP 堆栈位置 将请求发送到 FDO 的设备堆栈 HID 微型驱动程序必须为即插即用请求提供调度例程。 HID 类驱动程序执行与 FDO 关联的所有即插即用处理。 当 HID 类驱动程序处理即插即用 请求时,它会调用 HID 微型驱动程序的即插即用调度例程。 HID 微型驱动程序即插即用调度例程: 处理将请求发送到 FDO 的设备堆栈,并在备份设备堆栈的方式上完成请求,适合每 种类型的请求。 与某些请求关联的特定于设备的处理是否更新有关 FDO 状态的信息。 例如,微型驱动程序可能会更新 FDO (的即插即用状态,无论是启动、停止还是正 在删除) 。 HID 微型驱动程序必须为电源请求提供调度例程。 但是,HID 类驱动程序处理 FDO 的电 源处理。 符合 WDM 要求,HID 微型驱动程序以这种方式将电源请求发送到 FDO 的设备堆栈: 跳过当前 IRP 堆栈位置 启动下一个电源 IRP 将电源 IRP 发送到 FDO 的设备堆栈 通常,HID 微型驱动程序在设备堆栈上传递电源请求,而无需额外处理。 IRP_MJ_SYSTEM_CONTROL IRP_MJ_PNP IRP_MJ_POWER 在 Windows 早期版本上运行的平板电脑 的微型驱动程序要求 项目 • 2023/06/15 本部分涉及Windows 8之前的操作系统,并介绍供应商提供的 HID 微型驱动程序的一般 要求,适用于安装在平板电脑电脑版系统上的笔设备和按钮设备。 本部分重点介绍触控笔和按钮设备。 笔设备与平板电脑的液晶显示器集成,用于捕获笔触笔的运动。 按钮设备补充了笔设备,并用于捕获按钮输入。 有关平板电脑的详细信息,请参阅 Windows XP Tablet PC Edition 网站 有关平板电脑的详细信息,请参阅 Windows XP Tablet PC Edition 网站。 有关支持平板电脑的系统提供的软件的详细信息,请参阅Microsoft Windows SDK中的平 板电脑电脑文档。 触控笔和按钮设备属于 HIDClass 设备设置类。 这些设备由系统提供的 HID 客户端驱动程 序操作,该驱动程序链接到 HID 微型驱动程序。 如果没有支持设备硬件接口的系统提供 的 HID 微型驱动程序,则需要供应商提供的 HID 微型驱动程序。 设备使用系统提供的平 板电脑 API 从用户模式运行,Windows SDK 文档中介绍了这一点。 平板电脑笔设备必须: 提供一个顶级集合,其使用情况页为数字化器,其用法为 Pen (请参阅 HID 用法) 。 如果 Tablet PC 不包含内置鼠标,则 Tablet PC 笔设备必须提供其使用页为“通用桌 面”且其用法为“鼠标”的顶级集合。 Mouse 集合的目的是启用系统鼠标光标。 但 是,鼠标集合不得生成输入报告。 只应将 Pen 集合中的输入用于光标移动。 (如果 平板电脑的操作系统在未安装鼠标设备的情况下启动,则系统不会显示鼠标光标, 也不会将笔集合作为鼠标设备进行处理。) 仅报告原始数据。 驱动程序不得补偿线性、笔倾斜、显示旋转或缩放。 这些转换由 平板电脑 API 处理。 但是,驱动程序必须确保笔坐标系使用与 API 所用的原点和方 向相同的原点和方向。 例如,驱动程序必须确保原点位于横向显示器的左上角,x 坐标从左到右增加,y 坐标从上到下增加。 如果设备是 USB 设备,则平板电脑笔设备必须支持 USB 选择性挂起功能。 电脑笔设备的要求 平板电脑按钮设备补充了平板电脑上的笔输入。 按钮设备支持一个或多个按钮。 安装在 平板电脑上的按钮设备必须: 如Microsoft Windows SDK文档) 中所述,为安全注意序列 (SAS) (提供一个专用按 钮。 按下按钮时生成一个事件,在释放该按钮时生成另一个事件。 报告每个按钮的不同按钮事件,而不考虑同时按下或释放的按钮数。 提供一个顶级集合,其使用情况页为通用桌面,其用法为键盘 (请参阅 HID 用法) 。 键盘集合仅用于报告 SAS 按钮事件。 按下 SAS 按钮时,必须报告以下用法:左控 制、左 Alt 和删除。 提供一个顶级集合,其使用情况页为“通用桌面”,其用法为“平板电脑系统控件”。 使用按钮数组报告按钮事件,其用法页为 Button,使用值范围为 1 到按钮数。 电脑按钮设备的要求 基于 USB 的 HID 概述 项目 • 2023/06/15 USB 是 Windows 中第一个受支持的 HID 传输。 相应的内置驱动程序是在 Windows 2000 中引入的,此后已在所有操作系统中可用。 此驱动程序已得到增强,包括从触摸板和键 盘到传感器和供应商特定设备类型的新 HID 设备。 通过 USB 的 HID 也经过优化,以利 用选择性挂起。 (此功能需要供应商通过 Microsoft 操作系统描述符提供 INF 或支持) 最近更新的 HID over USB 还包括: 支持 USB 1.1、USB 2.0 和 USB 3.0。 HID over USB 驱动程序在 Windows 的所有客户端 SKU 上可用,并且包含在 WinPE 中。 HID USB 主页 HID USB 规范 HID 用途表 另请参阅 体系结构和概述 项目 • 2023/06/14 本部分介绍支持通过 USB 传输的 HID 的设备的驱动程序堆栈。 基于 USB 的 HID 驱动程序堆栈由 Microsoft 提供的以下组件组成。 下图描绘了堆栈和这 些组件。 Windows 8提供基于 WDF 的 HID 微型端口驱动程序,该驱动程序实现 1.1+ 版的 HID over USB 协议规范。 此驱动程序名为 HIDUSB.SYS。 Windows 基于 USB 设备类兼容 ID 匹配项加载此驱动程序。 即插即用支持 项目 • 2023/06/15 本部分介绍通用串行总线上的枚举过程。 当设备插入到基于 Windows 的计算机时,Windows USB 堆栈会枚举该设备,从设备中 提取详细信息,包括设备) 接口描述符 (或描述符,然后为设备生成一组硬件 ID 和兼容 ID。 有关 USB 硬件 ID 的完整列表,请参阅设备安装下的“设备标识字符串”部分。 以下部分中的示例演示了两种方案: 单接口 USB 设备的 USB ID 多接口 (复合) USB 设备的 USB ID 示例 1:单接口 HID USB 设备 此示例演示如何为运行 Windows 2000 或 Windows XP 的系统上的单接口 USB 设备生成 硬件 ID 和兼容 ID。 当设备最初由 USB 堆栈枚举时,USBHUB 驱动程序将从设备描述符中提取 idVendor、 idProduct 和 bcdDevice 。 这三个字段合并为生成 USB 硬件 ID。 请注意,供应商、设 备和修订号始终以十六进制格式存储。 为设备生成兼容 ID 更为复杂。 类代码、子类代码和协议代码由接口描述符的 bInterfaceClass、 bInterfaceSubClass 和 bInterfaceProtocol 确定。 这些值采用两位数 的十六进制格式。 注意 如果要提供 INF,硬件标识符应与下表左列中的 粗体 标识符匹配。 (应避免使用右 侧列中列出的兼容标识符。) 硬件标识符:兼容标识符 USB\Vid_xxxx&Pid_yyyy&Rev_zzzz:USB\Class_aa&SubClass_bb&Prot_cc USB\Vid_xxxx&Pid_yyyy:USB\Class_aa&SubClass_bb :USB\Class_aa 示例 2:多接口/功能 HID USB 设备 (复合设备) 具有多个功能的 USB 设备称为复合设备。 此示例演示如何为 Windows 上的复合 USB 设 备生成硬件 ID 和兼容 ID。 当新的 USB 复合设备插入运行 Windows 的计算机系统时, USBHUB 驱动程序 (PDO) 创建物理设备对象,并通知操作系统其子设备集已更改。 在中 心驱动程序中查询与新 PDO 关联的硬件 ID 后,系统会搜索相应的 INF 文件以查找标识 符的匹配项。 如果供应商选择只为整个设备加载一个驱动程序, (即,不使用复合设备驱 动程序) ,并在具有该驱动程序的软件中多路复用所有接口,则供应商应指定硬件 ID 匹 配项,以防止操作系统 (USB\COMPOSITE) 选取较低级别的匹配项。 注意 如果要提供 INF,硬件标识符应与下表左列中的 粗体 标识符匹配。 (应避免使用右 侧列中列出的兼容标识符。) 硬件标识符:兼容标识符 USB\Vid_xxxx&Pid_yyyy&Rev_zzzz:USB\Class_aa&SubClass_bb&Prot_cc USB\Vid_xxxx&Pid_yyyy:USB\Class_aa&SubClass_bb :USB\Class_aa :USB\COMPOSITE 但是,如果未找到硬件匹配项,Windows 即插即用将使用 USB\COMPOSITE 标识符 (USBCCGP) 加载 USB 通用父驱动程序。 然后,泛型父驱动程序创建一组单独的 PDO, (每个接口) 为复合设备的每个接口创建一组单独的硬件 ID。 以下部分显示子 PDO 的硬件 ID 的格式。 若要为每个接口的 PDO 生成一组硬件 ID,USBCCGP 驱动程序会将接口号追加 (该接口号 是一个从零开始的十六进制值,) 硬件 ID 的末尾。 类代码、子类代码和协议代码分别由接口描述符的 bInterfaceClass、 bInterfaceSubClass 和 bInterfaceProtocol 字段确定。 这些值采用两位数的十六进制格 式。 注意 如果要提供 INF 来加载驱动程序或提供友好的设备名称,则硬件标识符应与下表左 列中的 粗体 标识符匹配。 (应避免使用右侧列中列出的兼容标识符。) 硬件标识符:兼容标识符 USB\Vid_xxxx&Pid_yyyy&Rev_zzzz&MI_ww:USB\Class_aa&SubClass_bb&Prot_cc USB\Vid_xxxx&Pid_yyyy&MI_ww:USB\Class_aa&SubClass_bb :USB\Class_aa 通过 USB 进行 HID 电源管理 项目 • 2023/06/15 基于 USB 的 HID 采用 USB 挂起来对设备进行电源管理。 电源主要在以下两种配置中管理: 1. 案例 1:系统处于电源管理状态 (例如 S3) 但设备已准备好唤醒系统。 例如,一个 HID USB 键盘,用于在按下键时从 S3 唤醒桌面。 注意: HID 设备不会自动将系统 从低功耗状态唤醒。 只有特定的 HID 设备 (例如顶级键盘和鼠标集合) 执行此操 作。 如果最终用户希望解除设备唤醒系统的武装,则用户可以通过设备管理器中的 “属性/电源管理”选项卡指定此项。 2. 案例 #2:系统处于运行状态 (例如 S0) 但设备已空闲 (无用户交互) 。 例如,当没有 人使用或触摸 HID USB 鼠标时,选择性地挂起它。 基于 USB 的 HID 设备的选择性挂起 项目 • 2023/06/15 通用串行总线规范的修订版 2.0 指定了 USB 选择性挂起功能。 通过使用此功能, Windows 操作系统可以有选择地挂起空闲的 USB 设备。 这使 Windows 能够有效地管理 整个系统的电源要求。 有关 Windows 如何支持 USB 选择性挂起功能的详细信息,请参 阅 USB 选择性挂起。 (此资源可能在某些语言和国家/地区不可用。) 默认情况下,WINDOWS 禁用 USB 选择性挂起,以提供一致的用户体验,并避免选择性 挂起造成的恢复延迟。 支持选择性挂起的 HID 设备必须设计为: 从选择性暂停恢复时,保留第一次输入、触摸、移动或按键。 从移动时选择性挂起唤醒。 如果适用,) 维护无线链接 (。 保持任何活动状态 LED(例如 NUM 锁定或 CAPS 锁定)的电源。 从选择性挂起恢复,用户不会察觉到任何延迟。 Windows 8支持为 HID USB 设备启用选择性挂起的两种方法。 这些限制如下: 1. Microsoft OS 描述符 [首选]:Microsoft OS 描述符的扩展属性描述符可用于编写必 要的注册表项 () ,以支持 USB HID 选择性挂起。 2. 供应商提供的 INF:硬件制造商可以提供 INF 文件 (,该文件与 HID 开发节点) 的 USB 硬件 ID 上匹配,以安装相应的注册表项。 Microsoft 建议硬件供应商和电脑制造商使用第一个选项来启用 USB HID 选择性挂起。 此选项的优点是: 硬件供应商和电脑制造商不必安装其他 INF 文件。 新的Windows 8安装上会自动填充必要的注册表设置。 在升级到 Windows 8 时,将保留必要的注册表设置。 用户不能丢失 (或通过卸载 INF 来禁用) 选择性挂起功能。 但是,希望仍使用 INF 方法的硬件供应商和电脑制造商可以使用以下示例。 下面是一个 示例 INF 文件,演示如何在 Windows 中为 HID 设备启用此 USB 功能: INF ; Vendor INF File for USB HID devices ; ; A sample INF for a stand-alone USB HID device that supports ; selective suspend [Version] 其中: 1. INF 版本部分应设置 CLASSGUID 和 DriverVer 指令,如下所示: Signature ="$WINDOWS NT$" Class =HIDClass ClassGuid ={745a17a0-74d3-11d0-b6fe-00a0c90f57da} Provider =%VendorName% DriverVer =09/19/2008,6.0.0.0 CatalogFile =VendorXYZ.cat PnpLockdown =1 ; ================= Class section ===================== [ControlFlags] ExcludeFromSelect=* [SourceDisksNames] 1 = %DiskName%,,,"" ;***************************************** ; Install Section ;***************************************** [Manufacturer] %VendorName% = VendorXYZDevice,NTx86,NTamd64,NTarm [VendorXYZDevice.NTx86] %VendorXYZ.DeviceDesc% = VendorXYZDevice_Install, USB\VID_045E&PID_00B4 [VendorXYZDevice.NTamd64] %VendorXYZ.DeviceDesc% = VendorXYZDevice_Install, USB\VID_045E&PID_00B4 [VendorXYZDevice.NTarm] %VendorXYZ.DeviceDesc% = VendorXYZDevice_Install, USB\VID_045E&PID_00B4 [VendorXYZDevice_Install.NT] include = input.inf needs = HID_SelSus_Inst.NT [VendorXYZDevice_Install.NT.HW] include = input.inf needs = HID_SelSus_Inst.NT.HW [VendorXYZDevice_Install.NT.Services] include = input.inf needs = HID_SelSus_Inst.NT.Services [Strings] VendorName = "Vendor XYZ" DiskName = "Vendor XYZ Installation Disk" VendorXYZ.DeviceDesc = "VendorXYZ Device" CLASSGUID 指令必须为 HID 设备指定 Microsoft 类 GUID。 此 GUID 的值为 {745a17a0-74d3-11d0-b6fe-00a0c90f57da}。 DriverVer 指令的值必须比 Input.inf 中的 DriverVer 指令指定的值具有更新的 日期和更大的版本号。 2. VendorXYZDevice* 部分指定供应商 HID 设备的硬件标识符 (ID) 。 硬件 ID 由供应 商标识符 (VID) 和产品标识符 (PID) 组成。 设备的每个硬件 ID 必须具有供应商和设 备独有的 VID/PID 值。 这可确保相同的硬件 ID 不对应于多个名称和设置 3. VendorXYZDevice_Install.NT 和 VendorXYZDevice_Install.NT.HW 部分是 INF DDInstall 节。 在此示例中,这些部分包含 INF Include 和 Needs 指令。 Include 指令引用系统提供的 Input.inf 文件,该文件包含为供应商的 HID 设备启用 USB 选择性挂起功能所需的 INF 部分。 Needs 指令指示在设备安装过程中应处理 Input.inf 中的哪些部分。 在这种情况下, 选择“HID_SelSus_Inst”部分,而不是不支持选择性挂起的默认HID_Inst部分。 4. VendorXYZDevice_Install.NT.Services 部分是 INF DDInstall.HW 部分。 在此示例 中, 节还包含 INF Include 和 Needs 指令的相同值。 基于 I2C 的 HID 简介 项目 • 2023/06/14 为了Windows 8,Microsoft 创建了一个新的 HID 微型端口驱动程序,允许设备通过 Inter-Integrated线路 (I²C) 总线进行通信。 新的 HID 微型端口解决方案将 HID 协议扩展到 USB 和蓝牙之外,以支持 I²C 设备。 I²C 是一种简单但高效的协议,在手机和嵌入式平台中使用了十多年。 名为 HIDI2C.sys 的内 置 KMDF 驱动程序Windows 8支持此协议。 内置驱动程序中通过 HID 对 I²C 的组合支持使硬件制造商能够在 Windows 上快速运行其 设备,而无需创建驱动程序。 为了确保在具有多个 ACPI 资源的系统上正确行为,必须首先显示以下两个资源: HID I²C 连接 设备中断 定义这些资源后,可能会遵循其他类型的其他 ACPI 资源。 重要说明: 目前,HID I²C 驱动程序面向支持简单外围总线 (SPB) 和 GPIO 的 SoC 系统。 将 来,Microsoft 可能会在非 SoC 系统上支持此驱动程序。 HID I²C 驱动程序经过优化,可支持所有 HID 客户端。 HID I²C 驱动程序使设备和系统制造商能够减少它们必须开发的驱动程序总数,以支 持键盘、触摸板、触摸屏、传感器等常见设备类型。 HID I²C 驱动程序在 Windows 的所有客户端 SKU 上可用,并包含在 WinPE 中。 基于 I²C 传输的 HID 的体系结构和概述 项目 • 2023/06/14 本部分介绍通过 I²C 传输支持 HID 的设备驱动程序堆栈。 HID I²C 驱动程序堆栈由 Microsoft 提供的现有组件和新组件以及 I²C 芯片制造商提供的 组件组成。 下图描绘了堆栈和这些组件。 Windows 8为低功耗的简单总线提供了一个接口,以便与操作系统有效通信。 此接口称 为简单外围总线 (SPB) ,它支持 Inter-Integrated Circuit (I²C) 和串行外设接口 (SPI) 等总 线。 有关 SPB 的其他详细信息,请参阅简单外围总线主题。 体系结构和概述 Windows 8提供基于 KMDF 的 HID 微型端口驱动程序,该驱动程序实现基于 I²C 的 HID 协议规范版本 1.0。 此驱动程序名为 HIDI2C.sys。 Windows 基于兼容的 ID 匹配项加载此 驱动程序,该匹配项由高级配置和电源接口 (ACPI) 公开。 该驱动程序确保使用 HID IOCTL 的应用与利用 HID IOCTL 和 API 集的软件的应用程序级别兼容性。 设备会在需要 注意或具有数据时断言主机。 但是,在断言发生之前,必须存在 GPIO 连接。 注意 HIDI2C.sys设备驱动程序仅支持 I²C 总线。 它在 Windows 8 中不支持 SPI、SMBUS 或其他低功率总线。 I²C 控制器驱动程序公开串行外围总线 (SPB) IOCTL 接口以执行读取和写入操作。 此驱动 程序提供实际控制器内部函数 (例如 I²C) 。 SPB 类扩展代表控制器驱动程序处理与资源中 心的所有交互,并实现管理同时目标所需的队列。 注意 HID I²C 驱动程序无法在没有与 SPB 平台兼容的 I²C 总线的系统上运行。 请与系统 制造商联系,以确定设备系统上的 I²C 总线是否与 SPB 平台兼容。 常规用途输入/输出 (GPIO) 控制器通过 GPIO 从设备传送中断。 这通常是一个简单的从属 组件,它使用 GPIO 引脚向 Windows 发出新数据或其他事件的信号。 GPIO 还可以通过 I²C 通道以外的方法控制设备。 SoC 平台上的连接通常是不可发现的,因为 SoC 上使用的总线上的设备枚举没有标准。 因此,必须在高级配置和电源接口 (ACPI) 中静态定义这些设备。 此外,组件通常具有跨 越多个总线的多个依赖项,而不是严格的分支树结构。 资源中心是管理所有设备和总线控制器之间的连接的代理。 HIDI²C 驱动程序使用资源中 心将设备打开的请求重新路由到相应的控制器驱动程序。 有关资源中心的详细信息,请 参阅 SPB 连接设备的连接 ID 主题。 I²C 控制器驱动程序 GPIO 控制器驱动程序 资源中心 I2C 的即插即用支持 项目 • 2023/06/14 本文介绍通过 I²C 传输支持 HID 的设备的即插即用支持。 Windows 基于硬件标识符与 INF 之间的兼容标识符匹配项加载 HID I²C 类驱动程序。 标 识符由高级配置和电源接口 (ACPI) 生成。 硬件标识符是为 ACPI 中的 I²C 设备节点生成 的。 除唯一硬件标识符外,所有 HID I²C 兼容设备都必须公开兼容性标识符。 ACPI 5.0 规范包括对 HID 类设备的支持。 HID I²C 的 ACPI 定义如下所示。 字段 值 ACPI 对象 格式 注释 兼容 ID PNP0C50 _Cid ACPI0C50 或 PNP0C50 格式的字 符串 CompatibleID 硬件 ID 供应商特定 _藏 VVVVdddd (格式的 字符串,例如 NVDA0001) VendorID + DeviceID 子系 统 供应商特定 _子 VVVVsss 格式的字符 串 (例如 INTL1234) SubVendorID + SubSystemID 硬件 修订 版 供应商特定 _Hrv 0xRR (2 字节修订) RevisionID 当前 资源 设置 供应商特定 _Crs 字节流 必须包括 I2CSerialBus 和 I2C 控 制器和 GPIO 中断转换的 GPIO_INT。 设备 特定 方法 GUID {3CDFF6F7-4267- 4555-AD05- B30A3D8938DE} _Dsm 包 定义包含 HID 描述符地址的结 构。 每个 HID I²C 设备都必须提供以下必填字段: 兼容 ID 硬件 ID 硬件修订版 当前资源设置 驱动程序加载 设备特定方法 有关其他信息,请参阅高级配置和电源接口 (ACPI) 5.0 规范。 下面提供了随机 HID I²C 设备的硬件 ID 和兼容 ID 的示例。 这些详细信息基于示例设 备,该设备将自身报告为 HID,其中包含一个类“特定于供应商”的顶级集合。 高级配置和电源接口 (ACPI) 生成以下硬件 ID 和兼容 ID 以加载 HID I²C 传输驱动程序: 硬件标识符:兼容标识符 ACPI\Vid_xxxx&&Pid_yyyy Rev_zzzz;:ACPI\PNP0C50 ACPI\Vid_xxxxPid_yyyy;: ACPI\xxxxyyyyy;: 在前面的示例中,硬件 ID 是使用从示例设备的 _HID ACPI 方法中提取的值生成的。 兼容 ID 是使用从示例设备的 _CID ACPI 方法中提取的值生成的。 对于版本 1.0,I2C 上的 HID 的兼容 ID 必须始终为 PNP0C50。 注意 如果提供 INF,应仅使用上表左侧列中的硬件标识符。 (不要在右侧列中使用兼容标 识符。) HIDClass.sys 组件生成的 HID 客户端设备节点的硬件 ID 如下所示: 硬件标识符:兼容标识符 HID\VEN_MSFT&&DEV_0010 REV_0002&Col01;:不适用 -HID\VEN_MSFT&&DEV_0010 Col01 HID\MSFT0010&Col01;: N/A -HID\*MSFT0010Col01:不适用 -HID_DEVICE_UP:FF00_U:0001;: 不适用 -HID_DEVICE:不适用 硬件 ID 由 HIDClass.sys 生成,对于所有传输都是相同的。 此标识符基于从 ACPI) 提取 HIDI2C.sys (传递给HIDClass.sys的值。 加载 HID I²C 设备驱动程序 (HIDI2C.Sys ) 后,它开始通过 I²C 总线与设备通信。 驱动程序 执行的第一个操作是设备枚举序列。 设备枚举序列 以下列表提供了枚举序列。 请注意,此列表的顺序在 Windows 的未来版本中可能会更 改。 1. 从系统 BIOS 检索 HID I²C 设备的 ACPI 源语言 (ASL) 代码。 2. 从设备检索 HID 描述符。 写入 HID 描述符地址 读取 HID 描述符 3. 向设备发出SET_POWER。 写入SET_POWER命令 4. 向设备发出 RESET (主机发起的重置) 。 写入 RESET 命令 设备断言 GPIO 中断 从输入寄存器 (0x00 0x00) 读取值 5. 从设备检索报表描述符。 编写报表描述符地址 读取报表描述符 如果主机未能使用 DEVICE 成功完成任何步骤 1-5,则 HIDI²C 驱动程序可能会加载 错误 代码 10 的错误值。 其中任何命令中都没有内置重试逻辑。 注意: 可以并行执行步骤 4 和 5,以便在 I²C 上优化时间。 由于报表描述符 () 静态, (b) 相当长,因此,Windows 8可能会在 4 上等待设备响应时发出 5 的请求。 HIDI2C.SYS驱动程序支持以下命令: 命令 用途 何时使用 重置 Windows 支持 主机发起的重 置。 Windows 将在以下情况下发出此命令 - 设备初始化 - 禁用/启用 - 卸载/重新安装 获 取/Set_Report Windows 支持 Get/Set_Report 命令。 在以下情况下,当 HID 客户端驱动程序发出获取/设置功能报告 请求时,当 HID 客户端驱动程序发出同步输入/输出报告时, Windows 将发出此命令 支持的 HID I²C 命令 命令 用途 何时使用 Set_Power Windows 支持 Set_Power 命 令 在以下情况下,当系统转换为低功耗 S3/连接待机状态时,当系 统关闭时,Windows 将发出此命令。 通过 I2C 进行 HID 电源管理 项目 • 2023/06/15 本部分介绍通过 I C 传输支持 HID 的设备电源管理。 Windows 8引入了标记为“始终连接”Always On的新电源模型。 此模型允许板和电脑针对 电源和性能进行优化。 同时,Windows 8 针对未使用电脑时的功耗进行高度优化。 例 如,当有意关闭屏幕或由于没有用户活动而关闭屏幕时,它会节省电量。 由于 HID 设备是 Windows 中的主要设备类,因此它们必须遵循此新的电源模型。 下面是设备在连接待机电源状态期间应如何行为的简短摘要。 输入源 指示处于连接 待机状态的用 户状态 处于连接 待机状态 时已处理 系统转换为连接 待机状态时的设 备状态 数字化器 否 不得处理 D3 鼠标 是 必须处 理,将退 出连接待 机 D0 Keyboard 是 必须处 理,将退 出连接待 机 D0 旋转锁 否 不得处理 D3 通用桌面控件 - 调高音量 - 调低音量 - 频道调低 - 频道向上 - 快进 - 跟踪前进 - 回溯 - 播放 - 暂停 - 记录 - 跟踪停止 否 必须处理 D0 有关连接待机的详细信息,请参阅 了解连接待机 视频。 2 电源管理和优化 连接待机 支持 HID I 2C 设备中的连接待机 I C 总线上的设备由高级配置和电源接口 (ACPI) 枚举。 作为 HID-I C 协议规范的一部分, SET_POWER 命令支持 HIDI C 设备的电源管理。 此命令指示设备转换和退出其低功耗模 式。 收件箱 HIDI C 微型端口驱动程序从 HIDClass 传递 D-IRP。 这允许 ACPI 反过来管理设备 的电源。 2 2 2 2 排查常见错误 项目 • 2023/06/15 本文介绍硬件供应商和驱动程序开发人员在调试其 I²C 固件或驱动程序软件时可能会遇到 的常见问题。 如果 I²C 控制器驱动程序已加载,但设备未显示在 Windows 设备管理器中,请参阅以下 内容: 如果主机或设备的 ACPI 源语言 (ASL) 代码无效,则通常会出现上述问题。 若要确定问 题是否是由于无法匹配 INF,请参阅 setupapi.dev.log 文件。 另一个指示问题是由于不匹 配造成的,是 Windows 设备管理器中的错误代码 10。 若要解决此问题,请确保满足以下条件: _CID值必须为 PNP0C50。 BIOS 中的 I²C 控制器和设备特征必须准确。 BIOS 中设备) 的 HID 描述符地址 (必须准确。 必须正确标识 GPIO 中断并将其标记为 “独占”、“级别”、“ActiveLow”。 有关更多详细信息,请参阅 HID I2C 协议规范 的第 13 部分。 如果主机未能从设备检索正确的报告描述符,请确保满足以下条件: 枚举序列必须完成运行,然后才能检索报表描述符。 HID 描述符中的字节偏移量 4 和 6 必须有效。 (特别注意 length.) 如果已从设备检索到正确的报告描述符已验证,但似乎仍存在相关问题,请确保以下内容 正确: wReportDescLength 字段是准确的。 HID 报表的格式正确。 (若要验证这一点,请测试备用总线,例如 USB.) 本部分重点介绍硬件供应商和驱动程序开发人员提出的常见问题。 Windows 8收件箱 HIDI²C 驱动程序是否适用于通过 I²C 连接的 HID 设备 HIDI²C 驱动程序未加载 报表描述符无效 常见问题解答 是的,只要固件符合此 HID I²C 协议规范,它将正常工作 键盘) 和 OS 驱动程序等 (设备之间通信的数据结构是什么? 根据 HID 标准,数据结构采用由报表描述符定义的输入报表的形式。 设备本身 而不是 HIDI²C 定义输入报告结构。 只需像使用 USB 键盘一样报告键盘使用情 况,然后根据 HID I²C 规范提供描述符和相应的输入报告 如果同时缓冲多个报表,设备应执行什么操作? 如果正在缓冲多个报告,设备应保持中断断言状态,直到读取 (确认) 最后一个报 告。 只要在给定的读取操作后要报告更多数据,设备就应使用级别触发器 GPIO 设置使行保持断言状态。 在 USB 和 I²C 连接的情况下,我们应获取相同的 DevicePath 是否准确? 否,USB 和 I²C 之间的设备路径不会相同。 差异很小,但值得注意。 有关详细 信息,请参阅 Windows 驱动程序工具包 (WDK) 中的硬件 ID 部分。 HIDI²C 设备利用 Windows 收件箱 HIDI²C 驱动程序所需的 I²C 传输限制是多少? 所有 I²C 控制器都需要支持最多 4 KB 的传输。 HID 报表描述符的最大长度为 4 KB。 事件跟踪 项目 • 2023/06/14 可以使用事件跟踪 for Windows (ETW) 或 Windows 软件跟踪预处理器 (WPP) 来跟踪 I²C 设备驱动程序上的 HID 中的操作。 有关 ETW 的详细信息,请参阅 Windows 开发参考中 的 事件跟踪 主题。 有关 WPP 的详细信息,请参阅 WPP 软件跟踪 和 运行中跟踪记录器 (用于记录跟踪的 IFR) 。 默认为所有驱动程序启用的 inflight Trace Recorder (IFR) ,可用于查看从 HIDI²C 驱动程 序到内核调试器的跟踪输出。 以下命令显示 HIDI²C 的 WPP 跟踪消息。 syntax inflight Trace Recorder (IFR) 将这些跟踪消息存储在固定大小的圆形缓冲区中。 因此,输 出可能不包含整个跟踪日志。 若要获取更详细、更可控的跟踪,可以使用 logman.exe 捕获跟踪。 以下命令捕获 HIDI²C 的 WPP 跟踪: syntax 可以使用 HIDI²C 的 PDB 或 TMF 文件将生成的跟踪日志文件分析为文本。 使用飞行跟踪记录器 (IFR) !rcdrkd.rcdrlogdump hidi2c 使用 logman.exe Logman create trace -n HIDI2C_WPP -o HIDI2C_WPP.etl -nb 128 640 -bs 128 Logman update trace -n HIDI2C_WPP -p {E742C27D-29B1-4E4B-94EE-074D3AD72836} 0x7FFFFFFF 255 Logman start –n HIDI2C_WPP Logman stop -n HIDI2C_WPP Logman delete -n HIDI2C_WPP 启用 ETW 跟踪 HIDI²C 驱动程序记录特定事件的 ETW 事件。 这些事件记录在事件查看器日志中。 还可以使用以下logman.exe命令查看这些事件: syntax 生成的跟踪日志可以使用 Xperf 或 Windows 性能分析器 (WPA) 等工具进行分析。 Logman create trace -n HIDI2C_ETW -o HIDI2C_ETW.etl -nb 128 640 -bs 128 Logman update trace -n HIDI2C_ETW -p Microsoft-Windows-SPB-HIDI2C Logman start –n HIDI2C_ETW Logman stop -n HIDI2C_ETW Logman delete -n HIDI2C_ETW 基于 SPI 的 HID 简介 项目 • 2023/06/14 Microsoft 创建了一个 HID 微型端口驱动程序,允许设备通过串行外设接口 (SPI) 总线进 行通信。 SPI 提供以下功能: 比 I2C 更快 - 带宽更多,时钟速率更高 低延迟 在硬件中实现的简单且经济 适用于集成到平台中且不可移动的设备 本文介绍如何通过简单的外围总线传输使用人机接口设备 (HID) 类设备,并立即关注 SPI。 HID 类主要由人类用来控制计算机系统操作的设备组成。 HID 类设备的典型示例包 括: 键盘和指针设备,如标准鼠标设备、轨迹球和游戏杆 前面板控件,如旋钮、开关、按钮和滑块 可在电话、遥控器、游戏或模拟设备等设备上找到的控件,例如数据手套、方向 盘、键盘和方向盘踏板 可能不需要人工交互但以与 HID 类设备类似的格式提供数据的设备,例如,条形码 阅读器、温度计或其他形式的传感器 HID 协议最初面向人机接口设备。 但是,HID 协议对于需要对外部接口执行低延迟输入输出操作的任何应用程序以及该设备描述自身的能力都非常有用。 典型的 HID 类设备包 括指示器、专用显示器、音频反馈以及力或触觉反馈。 HID 协议是一种非对称协议,用于标识主机和设备的角色。 协议将定义一种格式 (描述 符) ,以便设备向主机描述其功能。 主机了解与设备的通信格式后,它会对设备进行程 序,以便将数据发送回主机。 HID 协议还标识向设备发送数据的方法,以及用于标识设 备当前状态的状态检查。 可以使用 HIDSPICx 类扩展将 添加到包含的 HIDSPI Windows 驱动程序的功能。 有关详 细信息,请参阅 HIDSPICx API。 完整的 HID over SPI 协议规范 可从 Microsoft 下载中心下载。 类扩展 HID over SPI 规范 HIDSPICx API 基于 USB 的 HID 基于 I2C 的 HID 另请参阅 基于 SPI 的 HID 传输的体系结构和概述 项目 • 2023/06/15 本部分介绍通过 SPI 传输支持 HID 的设备驱动程序堆栈。 HID SPI 驱动程序堆栈由 Microsoft 提供的现有和新组件以及 SPI 芯片制造商提供的组件 组成。 下图描绘了堆栈和这些组件。 Windows 为低功耗的简单总线提供了一个接口,以便与操作系统有效通信。 此接口称为 简单外围总线 (SPB) ,它支持 Inter-Integrated Circuit (I²C) 和串行外设接口 (SPI) 等总 线。 有关 SPB 的其他详细信息,请参阅 简单外围总线 (SPB) 主题。 体系结构和概述 Windows 提供基于 KMDF 的 HID 微型端口驱动程序,该驱动程序实现 1.0 版 HID over SPI 协议规范。 此驱动程序名为 HIDSPI.sys。 Windows 基于兼容的 ID 匹配加载此驱动程 序,该匹配项由高级配置和电源接口 (ACPI) 公开。 系统集成商可以使用扩展 INF 基于其 外围设备的硬件 ID 加载此驱动程序。 驱动程序可确保使用 HID IOCTL 应用程序级别的应 用与利用 HID IOCTL 和 API 集的软件兼容。 向驱动程序提供 GPIO 连接,使设备能够在 需要注意或具有数据时断言中断。 SPI 控制器驱动程序公开串行外围总线 (SPB) IOCTL 接口来执行读取和写入操作。 此驱动 程序提供实际控制器内部函数 (,例如 SPI) 。 SPB 类扩展代表控制器驱动程序处理与资源 中心的所有交互,并实现管理同时目标所需的队列。 常规用途输入/输出 (GPIO) 控制器通过 GPIO 从设备传送中断。 这通常是一个简单的从属 组件,它使用 GPIO 引脚向 Windows 发出新数据或其他事件的信号。 GPIO 还可以通过 SPI 通道以外的方法控制设备。 SoC 平台上的连接通常不可发现,因为 SoC 上使用的总线上的设备枚举没有标准。 因 此,必须在高级配置和电源接口 (ACPI) 中静态定义这些设备。 此外,组件通常具有跨越 多个总线的多个依赖项,而不是严格的分支树结构。 资源中心是一个代理,用于管理所有设备和总线控制器之间的连接。 HIDSPI 驱动程序使 用资源中心将设备打开的请求重新路由到相应的控制器驱动程序。 有关资源中心的详细 信息,请参阅 SPB 连接设备的连接 ID 主题。 7 备注 HIDSPI.sys设备驱动程序仅支持 SPI 总线。 它在 Windows 中不支持 I²C、SMBUS 或 其他低功耗总线。 SPI 控制器驱动程序 7 备注 HID SPI 驱动程序在没有与 SPB 平台兼容的 SPI 总线的系统上不起作用。 请联系系 统制造商,确定设备系统上的 SPI 总线是否与 SPB 平台兼容。 GPIO 控制器驱动程序 资源中心 对于需要更高性能或集成的实现,系统制造商可以开发用于处理 HIDSPI 事务的自定义芯 片。 为此,HIDSPICx 类扩展随 Windows 一起提供。 HIDSPICx 允许在不使用 SpbCx 的 情况下开发自定义 HIDSPI HWA 控制器驱动程序。 对于 HWA 设备,供应商提供一个客户端驱动程序,负责实现类扩展定义的接口,并与类 扩展通信。 HIDSPI 类扩展 (HIDSPICx) 基于 SPI 的 HID 的即插即用支持 项目 • 2023/06/14 本文介绍通过 SPI 传输支持 HID 的设备的即插即用支持。 Windows 基于硬件标识符和 INF 之间的兼容标识符匹配项加载 HID SPI 类驱动程序。 标 识符由高级配置和电源接口 (ACPI) 生成。 硬件标识符是为 ACPI 中的 SPI 设备节点生成 的。 除了唯一的硬件标识符外,所有 HID SPI 兼容设备都必须公开兼容性标识符。 ACPI 5.0 规范包括对 HID 类设备的支持。 HID SPI 的 ACPI 定义如下所示。 字段 值 ACPI 对象 格式 注释 硬件 ID 供应商特定 _藏 采用 VVVVdddd (格 式的字符串,例如 MSFT0011) VendorID + DeviceID 兼容 ID PNP0C51 _Cid ACPIxxxx 或 PNPxxxx 格式的字符串 CompatibleID 子系统 供应商特定 _子 采用 VVVVss (格式的 字符串,例如 MSFQ1234) SubVendorID + SubSystemID 硬件修 订版 供应商特定 _Hrv 0xRRRR (2 字节修订) 硬件修订号 当前资 源设置 供应商特定 _Crs 字节流 - 用于访问设备的 SpiSerialBus。 - 用于中断的 GpioInt。 特定于 设备的 方法 GUID {6e2ac436- 0fcf-41af-a265- b32a220dcfab} _Dsm 包 定义包含设备特定信息的 结构。 设备重 置方法 _RST 符合 ACPI 6.0 7.3.25 的设备重置 方法,由主机 OS 作为 ACPI FLDR 调用。 每个 HID SPI 设备都必须提供以下必填字段: 硬件 ID 兼容 ID 硬件修订版 驱动程序加载 当前资源设置 特定于设备的方法 设备重置方法 有关其他信息,请参阅 ACPI) 6.0 (高级配置和电源接口规范。 下面提供了随机 HID SPI 设备的硬件 ID 和兼容 ID 的示例。 这些详细信息基于一个示例 设备,该设备将自身报告为 HID,其中包含一个“特定于供应商”的类的顶级集合。 高级配置和电源接口 (ACPI) 生成以下硬件 ID 和兼容 ID 以加载 HID SPI 传输驱动程序: 硬件标识符:兼容标识符 ACPI\Vid_xxxx&&Pid_yyyy Rev_zzzz;:ACPI\PNP0C51 ACPI\Vid_xxxxPid_yyyy;: ACPI\xxxxyyyyy;: 在前面的示例中,硬件 ID 是使用从示例设备的 _HID ACPI 方法中提取的值生成的。 兼容 ID 是使用从示例设备的 _CID ACPI 方法中提取的值生成的。 对于版本 1.0,HID over SPI 的兼容 ID 必须始终为 PNP0C51。 HIDClass.sys组件生成的 HID 客户端设备节点的硬件 ID 如下所示: 硬件标识符:兼容标识符 HID\VEN_MSFT&DEV_0010&REV_0002&Col01;:不适用 -HID\VEN_MSFT&DEV_0010&Col01 HID\MSFT0010&Col01;: N/A -HID\*MSFT0010Col01:不适用 -HID_DEVICE_UP:FF00_U:0001;: 不适用 -HID_DEVICE:不适用 硬件 ID 由 HIDClass.sys 生成,对于所有传输都是相同的。 此标识符基于从 ACPI) 提取 HIDSPI.SYS (传递给HIDClass.sys的值。 7 备注 如果提供 INF,则只应使用上表左列中的硬件标识符。 (不要在右侧列中使用兼容标 识符。) 设备枚举序列 加载 HID SPI 设备驱动程序 (HIDSPI.SYS) 后,它开始通过 SPI 总线与设备通信。 驱动程 序执行的第一个操作是设备枚举序列。 以下列表提供了枚举序列。 此列表的顺序在 Windows 的未来版本中可能会更改。 1. 从系统 BIOS 中检索 HID SPI 设备的 ACPI 源语言 (ASL) 代码。 2. 向设备发出主机发起的重置 调用 ACPI _RST 方法 设备断言 GPIO 中断 主机从设备读取重置响应 3. 从设备检索 HID 描述符 主机写入 HID 描述符请求 设备断言 GPIO 中断 主机读取 HID 描述符响应 4. 检索报表描述符 主机写入报告描述符请求 设备断言 GPIO 中断 主机读取报告描述符响应 如果主机未能成功完成设备的任何步骤,则 HIDSPI 驱动程序可能会加载错误代码 10。 如果未收到响应,主机可能会重新尝试重置设备,但不能保证重试逻辑。 下表概述了 HID SPI 协议支持的 HID 报告操作,以及用于执行该操作的输入和输出报 告。 HID 报告类型 Operation 输出报告类型 输入报告类型 输入报告 GET 0x06 (请求 - 空内容) 0x0B (响应) 输入报告 SET (不支持) 空值 空值 输入报告 中断 IN 不适用 - 无请求 0x01 功能报告 GET 0x04 (请求 - 空内容) 0x05 (响应) HID 报表操作 HID 报告类型 Operation 输出报告类型 输入报告类型 功能报告 SET 0x03 0x09 (确认 - 空内容) 输出报告 GET (不支持) 空值 空值 输出报告 SET 0x05 0x0A (确认 - 空内容) Operation 请求报告类型 响应报告类型 设备描述符请求 0x01 0x7 报告描述符请求 0x02 0x8 命令请求 0x07 0x4 重置响应 空值 0x3 ACPI 源语言 (ASL) 协议操作 另请参阅 基于 SPI 的 HID 电源管理 项目 • 2023/06/15 本文介绍有关通过 SPI 进行主机和设备电源管理的详细信息。 设备负责在主机没有任何电源设置的情况下优化其电源利用率。 这样,设备无需主机干 预即可进入最低功率状态,同时确保设备能够继续及时与主机通信。 若要正确符合设备启动的电源优化,请执行以下操作: 设备负责在其低功率模式下保留其状态。 所有设备电源优化都必须对主机和最终用户透明。 设备必须及时响应来自主机的所有请求。 设备负责在用户或系统交互时及时将自身 置于更高的功率模式。 设备必须以无损的方式通知主机任何输入报告更改。 设备不应丢失或删除任何事 件。 主机启动的电源优化中所述的电源状态不适用于设备启动的电源优化。 通常部署设备启动的电源优化方案包括: 1. 设备空闲了一小段时间。 设备确定它处于空闲状态,并使其处于最低功率状态,降 低其内部感应频率,直到重新启动运动。 一旦运动开始,数据就会立即发送到主 机。 2. 设备可降低其感应频率。 设备降低了扫描数据的频率。 主机负责优化整个系统和设备的电源。 当主机希望向设备提供电源优化通知时,将使用 这种电源优化方法。 以下电源状态是为主机启动的电源优化定义的,不会与供应商特定的设备发起的电源优化 状态混淆。 ON 睡眠 (设备可能会唤醒系统) 关闭 (设备无法唤醒系统,可能会从设备中删除电源) 在“开”状态下,设备运行正常,可以使用设备启动的电源优化来降低功耗。 在主机启动 重置后,启动 HIDSPI 通信时,设备负责处于“开”状态。 设备启动的电源优化 主机启动的电源优化 主机通过发出定义的 Set Power 命令,指示设备从 ON 状态进入低功耗状态。 主机将根 据设备的操作系统电源策略选择执行此操作。 当平台电源策略允许设备唤醒自身或系统时,主机将设备置于睡眠状态。 对 SLEEP 的支 持是可选的,通过 ACPI 或以适合平台特定控制器的总线的方式向主机操作系统指示。 收 到 SET POWER SLEEP 命令后,设备必须立即进入低功耗状态,它将等待用户交互,并且不 得断言中断,除非启动唤醒。 如果设备检测到输入,它会断言中断,并等待主机发送 SET POWER ON 命令。 设备响应命令并 SET POWER ON 恢复向主机发送输入。 不再需要与设备通信时,主机会将设备置于 OFF 状态。 ACPI (或特定于平台的控制器) 必 须配置为提供冷关闭状态。 收到 SET POWER OFF 命令后,设备会立即进入其最低功率状 态,并停止与主机的通信。 若要使设备处于 ON 状态,主机会启动重置,此时初始化过 程开始。 对于 ACPI 枚举设备,需要实现以下电源状态: D0 - 正常工作状态 D2 - 用于睡眠状态(如果受支持)。 设备应指示此电源状态的唤醒支持。 D3 – 这应该用于 OFF 状态。 设备不应指示此电源状态的唤醒支持。 对于特定于平台的控制器,可以使用备用 D 状态映射来考虑控制器硬件的电源要求。 平台级 D 状态映射不可见或与设备通信。 下表标识了设备和主机必须遵循的属性: 电 源 状 态 主机责任 设备责任 ON - 根据需要解决设备的中断 和 IO 问题。 - 重置 后处于 ON 电源状态 - 正在处理,但不提供对主机的 或 SET POWER OFF 命令的响应SET POWER SLEEP。 主机和设备电源状态责任 电 源 状 态 主机责任 设备责任 睡 眠 - 指示设备进入睡眠状态。 - 如果设备通过中断线发出 警报,则将设备设置为“开” 状态。 - 如果主机需要与设备通 信,它会在任何其他命令之 前发出 ( SET POWER ON) 的 命令。 - 在主机启动电源优化之前,取消断言中断线(如果已断 言)。 - 向主机发送中断以请求服务。 然后,设备不得重新确认中 断,直到主机发送命令 SET POWER 进入设备已响应的 ON 状 态,此时设备应再次断言中断,以通知主机任何挂起的输入报 告。 - 将功耗降低到绝对最小值,以保持状态,并选择性地支持远 程唤醒。 - 响应 SET POWER ON 来自主机的命令。 OFF - 指示设备进入 OFF 状态。 - 指示平台将设备置于 OFF 状态。 - 当设备无法自行唤醒时, 将设备置于此状态。 - 在主机启动电源优化之前,取消断言中断线(如果已断 言)。 - 设备将无法在此状态下启动唤醒或提供中断。 - 将功耗降低到绝对最小值。 不需要维护状态。 - 处理 OFF -> ON 转换,因为它将定期通电。 设备电源状态 另请参阅 基于 SPI 的 HID 的错误处理 项目 • 2023/06/14 本文介绍 HID over SPI 的错误检测和处理过程。 SPI 总线上的错误分为以下几类: 协议错误 超时错误 协议错误进一步分为以下分类: 短数据包错误 位级错误 当主机或设备未返回 HID SPI 协议请求和长度字段中标识的位数时,会发生短数据包错 误。 主机应以指定的位数进行时钟。 主机无法知道设备是否已停止发送数据,因为主机 将读取总线上发生的任何情况。 主机应检查同步字段和其他字段,以查看数据是否合 理。 意外数据或无效数据的主机行为是启动设备重置。 SPI 总线上可能发生位级错误。 这些错误通常是总线上的噪音或系统中其他总线的干扰造 成的。 此规范不支持 SPI 数据线上的位级错误的 CRC 或其他检测机制。 主机分析程序可以识别格式不正确的报表并丢弃它。 主机 HID 驱动程序堆栈负责防止格 式不正确的报表不符合报告描述符。 意外数据的主机行为是启动设备重置。 基于 SPI 的 HID 协议是连续的,预期设备必须及时响应主机请求。 在大多数情况下,从 设备到主机的响应在几毫秒内完成。 如果设备停滞且无法自行还原,则会出现强制超时 延迟,在此之后,主机可能会重置设备并重启操作。 TIMEOUT_HostInitiatedReset = 1 second 主机可能允许专有方法调整其特定设备的此超时值,但主机必须支持超时值。 协议错误 短数据包错误 位级错误 超时错误 检测到错误时,主机可能会重置设备以重新建立与设备的通信。 此机制适用于错误恢 复,应响应异常事件,例如与暴露在 ESD 排放中的设备重新建立通信。 主机发起的重置 D3 通过 SPI 设备对 HID 的Hot 支持 项目 • 2023/06/15 从 Windows 11 22H2 开始,HidSpiCx 提供对 D3Hot 电源策略的支持,允许硬件加速控 制器支持从 D3 唤醒。 这增加了对 PCI 等总线上的硬件加速应用程序的支持,使 HidSpiCx 设备能够保持唤醒 (处于 HIDSPI SLEEP 状态) 处于 D3Hot 电源状态,而无需在 返回到 D0 时执行主机启动的重置。 启用 D3Hot 电源策略具有以下效果: 如果 HIDSPI 设备进入 HIDSPI OFF 电源状态 (未为唤醒) 武装,则转换回 D0 (HIDSPI ON 电源状态时,它将重置) 如果 HIDSPI 设备进入 HIDSPI SLEEP 电源状态, (在 或 D2中D1进行唤醒) ,则不会 将其重置Dx为D0转换 (HIDSPI ON 电源状态) 。 如果 HIDSPI 设备进入 HIDSPI SLEEP 电源状态, (在 中 D3为唤醒) 武装: D3COLD_SUPPORT_INTERFACE如果 由父总线公开,并且对接口的调用指示D3Cold发 生了转换,则设备将重置D3Cold为D0转换 (HIDSPI ON 电源状态) 。 D3COLD_SUPPORT_INTERFACE如果 由父总线公开,并且对接口的调用指示D3Cold未 发生转换,则设备不会重置D3Hot为D0转换 (HIDSPI ON 电源状态) 。 如果父总线未公开 ,D3COLD_SUPPORT_INTERFACE则假定设备不支持 D3Cold,并且 不会将其重置D3为D0转换。 如果没有 D3Hot 电源策略,则默认行为为: 如果 HIDSPI 设备进入 HIDSPI OFF 电源状态 (未为唤醒) 武装,则转换回 D0 (HIDSPI ON 电源状态时,它将重置) 如果 HIDSPI 设备进入 HIDSPI SLEEP 电源状态, (在 或 D2中D1进行唤醒) ,则不会 将其重置Dx为D0转换 (HIDSPI ON 电源状态) 。 如果 HIDSPI 设备转到 HIDSPI SLEEP (为唤醒) 或OFF电源状态 (未在 中D3为唤醒) 武 装,则会将其重置D3为D0转换 (HIDSPI ON 电源状态) 。 若要使用 D3Hot 电源策略,HidSpiCx 客户端驱动程序可以通过在设备的硬件密钥下添加 UseD3HotPowerPolicy 注册表值来选择加入。 在安装 HidSpiCx 客户端 HWA 驱动程序的 INF 文件中,使用 AddReg 指令。 行为 配置 支持使用 HIDSPI SLEEP 电源状态的所有驱动程序 (这意味着设备将在 D3 中启用唤醒) , 应在其驱动程序安装 INF 中启用 UseD3HotPowerPolicy 。 [EXAMPLE_DEVICE.NT.AddReg] HKR,,"UseD3HotPowerPolicy",0x00010001,1 非 HID 旧设备 项目 • 2023/06/15 本部分介绍了非 HID 键盘和鼠标的驱动程序、传输方式和筛选器驱动程序。 这些设备主 要以 PS/2 传输方式运行。 本部分不包含有关 Sermouse 的信息,Sermouse 是适用于串行鼠标的 Windows 系统函 数驱动程序。 请注意,适用于 I8042prt 的操作约束不适用于 Sermouse。 此外,高级设 备筛选器驱动程序不与 Sermouse 一起使用来自定义串行鼠标的操作。 相反,供应商需 要为设备安装特定于设备的函数驱动程序。 特定于设备的函数驱动程序和 Sermouse 可 以同时运行,彼此独立。 Windows 8将以下驱动程序堆栈用于非 HID 键盘、鼠标和触摸板硬件。 Windows 8支持 的唯一非 HID 传输是 PS2。 非 HID 驱动程序堆栈 键盘和鼠标类驱动程序的配置 项目 • 2023/06/15 非 HID 键盘和鼠标可以通过多个旧式总线进行连接,但仍使用相同的类驱动程序。 本部 分包含有关类驱动程序本身的详细信息。 以下部分详细介绍了控制器。 本主题介绍 Microsoft Windows 2000 及更高版本中键盘和鼠标设备的典型物理配置。 下图显示了采用单个键盘和单个鼠标的两种常见配置。 左侧的图显示了通过独立控制器连接到系统总线的键盘和鼠标。 典型配置包括通过 i8042 控制器操作的 PS/2 样式键盘和通过串行端口控制器操作的串行样式鼠标。 以下附加信息对于键盘和鼠标制造商非常重要: 出于安全原因,操作系统堆栈以独占模式打开键盘 Windows 支持同时连接多个键盘和鼠标设备。 Windows 不支持客户端对每台设备进行独立访问。 本主题介绍以下 Microsoft Windows 2000 及更高版本系统类驱动程序的功能: Kbdclass,GUID_CLASS_KEYBOARD设备类的设备的类驱动程序 Mouclass,GUID_CLASS_MOUSE设备类的设备的类驱动程序 7 备注 本主题适用于配置键盘和鼠标类驱动程序的开发人员。 如果要修复鼠标或键盘,请 参阅: Windows 中的鼠标、触摸板和键盘问题 对无法正常工作的无线鼠标进行故障排除 类驱动程序功能 Kbdclass 实现 Kbdclass 服务,其可执行映像kbdclass.sys。 Mouclass 实现 Mouclass 服务,并且其可执行映像mouclass.sys。 Kbdclass 和 Mouclass 各功能: 设备类的通用和与硬件无关的操作。 即插即用、电源管理和 Windows Management Instrumentation (WMI) 。 旧设备的操作。 同时操作多个设备。 类服务回调例程的连接,函数驱动程序使用该例程将数据从设备的输入数据缓冲区 传输到类驱动程序的数据缓冲区。 下图显示了即插即用 PS/2 样式键盘和鼠标设备的设备对象的配置。 每个类驱动程序创建 一个高级类 筛选器设备对象 , (筛选器 DO) ,该对象通过可选的高级设备筛选器 DO 附 加到函数设备对象 (FDO) 。 上层设备筛选器驱动程序创建高级设备筛选器 DO。 I8042prt 创建函数 DO 并将其附加到根总线驱动程序 (PDO) 的物理设备对象。 设备对象的配置 PS/2 键盘 键盘驱动程序堆栈由以下内容组成。 Kbdclass,上层键盘类筛选器驱动程序 一个或多个可选的高级键盘筛选器驱动程序 I8042prt,函数驱动程序 鼠标驱动程序堆栈由以下内容组成。 Mouclass,上层鼠标类筛选器驱动程序 一个或多个可选的上层鼠标筛选器驱动程序 I8042prt,函数驱动程序 Kbdclass 和 Mouclass 可以在两种不同模式下支持多个设备。 在 一对一模式下,每个设 备都有一个独立的设备堆栈。 类驱动程序创建独立的类 DO 并将其附加到每个设备堆 栈。 每个设备堆栈都有自己的控制状态和输入缓冲区。 Microsoft Win32 子系统通过唯 一的文件对象访问每个设备的输入。 在 grandmaster 模式下,类驱动程序按以下方式操作所有设备: 类驱动程序同时创建表示所有设备的 grandmaster 类 DO 和每个设备的 从属类 DO 。 类驱动程序将从属类 DO 附加到每个设备堆栈。 在从属类 DO 下,设备堆栈与在一 对一模式下创建的堆栈相同。 grandmaster 类 DO 控制所有从属 DO 的操作。 Win32 子系统通过表示 grandmaster 类设备的文件对象访问所有设备输入。 所有设备输入都缓冲在大师的数据队列中。 大师维护单个全局设备状态。 如果 Kbdclass 和 Mouclass 的注册表项值 ConnectMultiplePorts 设置为项 HKLM\Services\CurrentControlSet service\Parameters 下的0x00 (,则它们以一 对一模式运行,其中类服务为 Kbdclass 或 Mouclass) 。 否则,Kbdclass 和 Mouclass 以 大师模式运行。 Microsoft Win32 子系统可打开所有键盘和鼠标设备供其独占使用。 对于每个设备类, Win32 子系统会将来自所有设备的输入视为来自单个输入设备。 应用程序无法请求仅接 PS/2 鼠标 通过类驱动程序打开和关闭 收来自一个特定设备的输入。 Win32 子系统在从即插即用管理器收到启用GUID_CLASS_KEYBOARD或 GUID_CLASS_MOUSE设备接口的通知后,动态打开即插即用输入设备。 Win32 子系统在 收到已打开接口被禁用的通知后关闭即插即用设备。 Win32 子系统还按名称 (打开旧设 备,例如“\Device\KeyboardLegacyClass0”) 。 请注意,一旦 Win32 子系统成功打开旧设 备,它便无法确定是否稍后以物理方式删除该设备。 在 Kbdclass 和 Mouclass 收到创建请求后,它们对即插即用和旧操作执行以下操作: 即插即用操作 如果设备处于即插即用启动状态,则类驱动程序会将IRP_MJ_CREATE请求发送到驱 动程序堆栈。 否则,类驱动程序完成请求而不将请求发送到驱动程序堆栈。 类驱动 程序设置对设备具有读取访问权限的受信任文件。 如果有 grandmaster 设备,则类 驱动程序会向与从属类设备关联的所有端口发送创建请求。 旧操作 类驱动程序向端口驱动程序发送内部设备控制请求以启用设备。 类驱动程序必须先将其类服务连接到设备,然后才能打开设备。 类驱动程序在将类 DO 附加到设备堆栈后连接其类服务。 函数驱动程序使用类服务回调将输入数据从设备传输 到设备的类数据队列。 设备的函数驱动程序的 ISR 调度完成例程调用类服务回调。 Kbdclass 提供类服务回调 KeyboardClassServiceCallback,Mouclass 提供类服务回调 MouseClassServiceCallback。 供应商可以通过为设备安装上层筛选器驱动程序来修改类服务回调的操作。 示例键盘筛 选器驱动程序 Kbfiltr 定义 KbFilter_ServiceCallback 回调,示例鼠标筛选器驱动程序 Moufiltr 定义 MouFilter_ServiceCallback 回调。 可以将示例筛选器服务回调配置为修改 从设备的端口输入缓冲区传输到类数据队列的输入数据。 例如,筛选器服务回调可以删 除、转换或插入数据。 类和筛选器服务回调按以下方式连接: 类驱动程序将内部设备连接请求发送到设备堆栈 (IOCTL_INTERNAL_KEYBOARD_CONNECT 或 IOCTL_INTERNAL_MOUSE_CONNECT) 。 类连接数据由CONNECT_DATA结构指 定,该结构包括指向类设备对象的指针和指向类服务回调的指针。 筛选器驱动程序收到连接请求后,会保存类连接数据的副本,并将请求的连接数据 替换为筛选器连接数据。 筛选器连接数据指定指向筛选器设备对象的指针和指向筛 将服务回调连接到设备 选器驱动程序服务回调的指针。 然后,筛选器驱动程序将筛选的连接请求发送到函 数驱动程序。 类和筛选器服务回调按以下方式调用: 函数驱动程序使用筛选器连接数据对筛选器服务回调进行初始回调。 筛选输入数据后,筛选器服务回调使用它保存的类连接数据对类服务回调进行回 调。 I8042prt 支持以下内部设备控制请求,以查询有关键盘设备的信息,并在键盘设备上设置 参数: IOCTL_KEYBOARD_QUERY_ATTRIBUTES IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION IOCTL_KEYBOARD_QUERY_INDICATORS IOCTL_KEYBOARD_QUERY_TYPEMATIC IOCTL_KEYBOARD_SET_INDICATORS IOCTL_KEYBOARD_SET_TYPEMATIC 有关所有键盘设备控制请求的详细信息,请参阅 人机接口设备参考。 在 Microsoft Windows 操作系统中,输入设备提供的 PS/2 兼容扫描代码将转换为虚拟密 钥,这些密钥以 Windows 消息的形式通过系统传播。 如果设备为某个密钥生成了错误的 扫描代码,则会发送错误的虚拟密钥消息。 可以通过编写筛选器驱动程序来修复此问 题,该驱动程序分析固件生成的扫描代码,并将不正确的扫描代码修改为系统理解的扫描 代码。 但是,这是一个繁琐的过程,如果内核级筛选器驱动程序中存在错误,有时可能 会导致严重问题。 Windows 2000 和 Windows XP 包括一个新的扫描代码映射器,它提供了一种允许映射扫 描代码的方法。 Windows 的扫描代码映射存储在以下注册表项中: syntax 查询和设置键盘设备 扫描键盘的代码映射器 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout 注意 还有一个 键盘布局 键 (注意复数形式) 下控件键,但不应修改该键。 在 “键盘布局” 键中,必须添加 “扫描代码映射 ”值。 此值的类型REG_BINARY (小 Endian 格式) ,并具有下表中指定的数据格式。 起始偏移量 (字节) 大小(以字节为单位) 数据 0 4 标头:版本信息 4 4 标头:标志 8 4 标头:映射数 12 4 单个映射 ... ... ... 最后 4 个字节 4 null 终止符 (0x00000000) 第一个和第二个 DWORDS 存储标头信息,对于当前版本的扫描代码映射器,应设置为所 有零。 第三个 DWORD 条目包含后续映射总数的计数,包括 null 终止映射。 因此,最小 计数为 1, (未) 指定映射。 各个映射都跟在 标头后面。 每个映射的长度为一个 DWORD,并划分为两个 WORD 长度字段。 每个 WORD 字段存储要映射的密钥的扫描 代码。 映射存储在注册表中后,必须重新启动系统才能使映射生效。 请注意,如果需要在按键 上映射扫描代码,则会在将扫描代码转换为虚拟密钥之前在用户模式下执行该步骤。 在 用户模式下执行此转换可能会存在某些限制,例如在终端服务下运行时映射无法正常工 作。 若要删除这些映射,请删除 Scancode Map 注册表值并重新启动。 下面提供了一个示例。 若要将左侧 CTRL 键与 CAPS LOCK 键交换,请使用注册表编辑器 (最好Regedt32.exe) 修改具有以下值的 Scancode Map 键: syntax 下表包含拆分为 DWORD 字段和交换的字节的这些条目。 值:解释 0x00000000:标头:版本。 设置为所有零。 示例 1 00000000 00000000 03000000 3A001D00 1D003A00 00000000 0x00000000:标头:标志。 设置为所有零。 0x00000003:映射中的三个条目 (包括 null 条目) 。 0x001D003A:左 CTRL 键 --> CAPS LOCK (0x1D --> 0x3A) 。 0x003A001D:CAPS LOCK --> 左 ctrl 键 (0x3A --> 0x1D) 。 0x00000000:Null 终止符。 还可以添加键盘上未正式提供的键,或删除从未使用的键。 以下示例演示了 存储在 Scancode Map 中的值,以删除右 CTRL 键并将右 Alt 键的功能更改为静音键: syntax 下表包含拆分为 DWORD 字段和交换的字节的这些条目。 值:解释 0x00000000:标头:版本。 设置为所有零。 0x00000000:标头:标志。 设置为所有零。 0x00000003:映射中的三个条目 (包括 null 条目) 。 0xE01D0000:删除右 ctrl 键 (0xE01D -> 0x00) 。 0xE038E020:右 ALT 键 --> 静音键 (0xE038 --> 0xE020) 。 0x00000000:Null 终止符。 生成必要的数据后,可以通过多种方式将其插入注册表中。 可以生成 .reg 文件,该文件可以使用注册表编辑器轻松合并到系统注册表中。 也可以使用包含要添加的注册表信息的 [AddReg] 部分创建 .inf 文件。 Regedt32.exe可用于手动将信息添加到注册表。 扫描代码映射器有几个优点和缺点。 优点包括: 映射器可用作更正固件错误的简单修复方法。 示例 2 00000000 00000000 03000000 00001DE0 20E038E0 00000000 可以通过在注册表中修改映射,将常用键添加到键盘。 例如,不经常使用的键 (右 CTRL 键) 可以映射到 null, (删除) 或交换其他键。 可以轻松更改关键位置。 用户可以轻松自定义常用密钥的位置,以使其受益。 认识到以下缺点: 将映射存储在注册表中后,需要重新启动系统才能激活它。 存储在注册表中的映射在系统级别工作,并应用于所有用户。 这些映射不能设置为 以不同的方式工作,具体取决于当前用户。 当前实现限制映射的功能,以便映射始终应用于连接到系统的所有键盘。 目前无法 按键盘创建地图。 I8042prt 支持以下内部设备控制请求来查询有关鼠标设备的信息: IOCTL_MOUSE_QUERY_ATTRIBUTES 有关所有鼠标设备控制请求的详细信息,请参阅 人机接口设备参考。 下面是与鼠标类驱动程序关联的注册表项列表。 [Key: HKLM\SYSTEM\CurrentControlSet\Services\Mouclass\Parameters] MaximumPortsServiced - 不在 Windows XP 及更高版本上使用。 仅适用于 Windows NT4。 PointerDeviceBaseName - 指定由鼠标类设备驱动程序创建的设备对象的基名称 ConnectMultiplePorts – 确定每个类设备对象是有一个还是多个端口设备对象。 此 项主要由设备驱动程序使用。 MouseDataQueueSize - 指定鼠标驱动程序缓冲的鼠标事件数。 它还用于计算非分 页内存池中鼠标驱动程序的内部缓冲区的大小。 对于 GUID_CLASS_MOUSE 类型的设备,设备的函数驱动程序: 处理特定于设备的输入。 创建 MouseClassServiceCallback 所需的MOUSE_INPUT_DATA结构。 查询鼠标设备 与鼠标类驱动程序关联的注册表设置 绝对指向设备 通过在 ISR 调度完成例程中调用 MouseClassServiceCallback ,将 MOUSE_INPUT_DATA结构传输到 Mouclass 数据队列。 对于绝对指向设备,设备的函数驱动程序必须按以下方式设置MOUSE_INPUT_DATA结构 的 LastX、 LastY 和 Flags 成员: 除了将设备输入值除以设备的最大功能之外,驱动程序还会按以下0xFFFF缩放设备 输入值: C++ 驱动程序在 Flags 中设置MOUSE_MOVE_ABSOLUTE标志。 如果窗口管理器应将输入映射到整个虚拟桌面,驱动程序会在 Flags 中设置 MOUSE_VIRTUAL_DESKTOP标志。 如果未设置MOUSE_VIRTUAL_DESKTOP标志,则 窗口管理器仅将输入映射到主监视器。 下面按设备类型指定如何实现对绝对指向设备的这些特殊要求: HID 设备: 适用于 HID 鼠标设备的 Windows 函数驱动程序 Mouhid 会自动实现这些特殊要 求。 PS/2 样式设备: 需要上层筛选器驱动程序。 筛选器驱动程序提供 IsrHook 回调和类服务回调。 I8042prt 调用 IsrHook 来处理原始设备输入,并调用筛选器类服务回调来筛选输 入。 筛选器类服务回调反过来又调用 MouseClassServiceCallback。 IsrHook 回调 和类服务回调的组合处理特定于设备的输入、创建所需的MOUSE_INPUT_DATA结 构、缩放设备输入数据并设置MOUSE_MOVE_ABSOLUTE标志。 即插即用 Serenum 枚举的 COM 端口设备: 需要即插即用函数驱动程序。 函数驱动程序创建所需的MOUSE_INPUT_DATA结构, 缩放设备输入数据,并在调用 MouseClassServiceCallback 之前设置 MOUSE_MOVE_ABSOLUTE标志。 非即插即用 COM 端口设备: LastX = ((device input x value) * 0xFFFF ) / (Maximum x capability of the device) LastY = ((device input y value) * 0xFFFF ) / (Maximum y capability of the device) 需要特定于设备的函数驱动程序。 函数驱动程序创建所需的MOUSE_INPUT_DATA结 构,缩放设备输入数据,并在调用 MouseClassServiceCallback 之前设置 MOUSE_MOVE_ABSOLUTE标志。 不受支持的总线上的设备: 需要特定于设备的函数驱动程序。 函数驱动程序创建所需的MOUSE_INPUT_DATA结 构,缩放设备输入数据,并在调用 MouseClassServiceCallback 之前设置 MOUSE_MOVE_ABSOLUTE标志。 PS/2 (i8042prt) 驱动程序 项目 • 2023/06/14 本主题介绍适用于 PS/2 样式键盘和鼠标设备的 I8042prt、Microsoft Windows 2000 及更 高版本的系统功能驱动程序的功能。 I8042prt 实现 I8042prt 服务,其可执行映像i8042prt.sys。 I8042prt 的功能包括: PS/2 样式键盘和鼠标设备与硬件相关的同时操作。 键盘和鼠标共享 I/O 端口,但使用不同的中断、中断服务例程 (ISR) 和 ISR 调度完成 例程。 即插即用、电源管理和 WMI 旧设备的操作。 键盘类服务回调例程和鼠标类服务回调例程的连接。 I8042prt 使用类服务回调将数据从 I8042prt 的输入数据缓冲区传输到类驱动程序的 数据缓冲区。 为键盘设备添加供应商提供的 PI8042_KEYBOARD_INITIALIZATION_ROUTINE 回调 例程。 可选的上层设备筛选器驱动程序提供回调例程。 添加供应商提供的 PI8042_KEYBOARD_ISR 回调例程和自定义 PI8042_MOUSE_ISR 回调例程。 可选的上层设备筛选器驱动程序提供这些回调例程。 键盘写入缓冲区请求 和 鼠标写入缓冲区请求。 上层设备筛选器驱动程序可以使用写入缓冲区请求将其写入设备与设备的 ISR 以及 设备上的其他读取和写入同步。 键盘启动信息请求 和 鼠标启动信息请求。 启动信息请求将指向设备的中断对象的指针传递到上层筛选器驱动程序。 筛选器驱 动程序可以使用中断对象将其操作与设备的 ISR 同步。 I8042prt 回调例程。 上层设备筛选器驱动程序可以使用设备的 ISR 上下文中的回调例程来写入设备,并 从设备对数据包进行排队。 下面是与 PS/2 端口驱动程序关联的注册表项列表。 syntax EnableWheelDetection [REG_DWORD] - 确定驱动程序是否尝试在鼠标设备上检测 并启用滚轮。 某些设备配备了鼠标滚轮,以提供快速滚动和其他控制功能(如果应 用程序支持)。 ResendIterations [REG_DWORD] – 指定硬件操作尝试的最大次数。 如果试用次数超 过此项的值,Windows 会将操作视为失败。 NumberOfButtons [REG_DWORD] – 指定启动时鼠标端口鼠标上的按钮数。 如果启 动时检测到的按钮数不正确,可以通过更改此项的值来替代它。 KeyboardDataQueueSize [REG_DWORD] – 指定键盘驱动程序缓冲的键盘事件数。 此项还用于计算非分页内存池中键盘驱动程序的内部缓冲区的大小。 为了确定要为 缓冲区分配的字节数,系统会将 KEYBOARD_INPUT_DATA 结构的大小乘以 KeyboardDataQueueSize 的值。 PollStatusIterations [REG_DWORD] – 指定系统验证 i8042 控制器状态寄存器上的中 断的最大次数。 如果无法在此项的值中指定的试验次数中验证中断,则忽略中断。 PollingIterations [REG_DWORD] - 指定 Windows 2000 轮询硬件的最大次数。 如果 超出此条目中指定的试用次数,Windows 2000 将停止轮询。 SampleRate [REG_DWORD] – 指定 PS/2 驱动程序测量 PS/2 鼠标的特征和活动的频 率。 驱动程序使用通过采样收集的信息来优化鼠标设备的操作。 PollingIterationsMaximum [REG_DWORD] – 指定 Windows 2000 在旧式 AT 键盘上 轮询硬件的最大次数。 如果超出此条目中指定的试用次数,Windows 将停止轮询。 MouseResendStallTime [REG_DWORD] – 确定如果在没有 ACK 的情况下返回 RESEND 消息,则鼠标驱动程序等待确认 (ACK) 重置的时间。 当鼠标驱动程序中断 服务例程包含重置时,将使用此项。 OverrideKeyboardType [REG_DWORD] – 指定键盘类型。 可以将此项添加到注册 表,以更正启动时检测到的键盘类型中的错误。 OverrideKeyboardSubtype [REG_DWORD] – 指定依赖于 OEM 的键盘子类型。 可以 将此项添加到注册表,以更正启动时检测到的键盘子类型中的错误。 有关详细信息,请参阅: 关于注册表 注册表参考 与 PS/2 驱动程序关联的注册表设置 [Key: HKLM\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters] 第三方筛选器驱动程序 项目 • 2023/06/15 本主题介绍 Microsoft Windows 驱动程序工具包 (WDK) 中的以下示例筛选器驱动程序的 功能: Kbfiltr,即插即用 PS/2 样式键盘设备的可选高级筛选器驱动程序 Moufiltr,适用于即插即用 PS/2 样式鼠标设备的可选高级筛选器驱动程序 Kbfiltr 和 Moufiltr 演示如何筛选 I/O 请求并添加回调例程来修改类服务和 I8042prt 的操 作。 Kbfiltr 和 Moufiltr 支持即插即用和电源管理。 Kbfiltr 提供以下回调例程: KbFilter_ServiceCallback 键盘筛选器服务回调将添加到键盘类服务回调。 可以将筛选器 服务回调配置为修改保存在类驱动程序的数据队列中的键盘输入数据。 KbFilter_IsrHook 键盘筛选器 ISR 挂钩例程是 I8042prt 对键盘设备支持的 IsrRoutine 回 调的模板。 可以将回调配置为自定义键盘的 ISR 操作。 KbFilter_InitializationRoutine 键盘筛选器初始化例程是 I8042prt 对键盘设备支持的 InitializationRoutine 回调的模板。 可以将此回调配置为自定义键盘设备的初始化。 Moufiltr 提供以下回调例程: MouFilter_ServiceCallback 将鼠标筛选器服务回调添加到鼠标类服务回调。 可以将筛选 器服务回调配置为修改保存在类驱动程序的数据队列中的鼠标输入数据。 MouFilter_IsrHook 鼠标筛选器 ISR 挂钩例程是 I8042prt 对鼠标设备支持的 IsrRoutine 回 调的模板。 可以将回调配置为自定义该鼠标的 ISR 的操作。 7 备注 适用于 Windows 2000 及更高版本的终端服务器的设计不支持使用示例键盘和鼠标 筛选器驱动程序来筛选物理安装在远程客户端上的设备的输入。 安装在终端服务器 上的筛选器驱动程序只能用于筛选物理安装在终端服务器上的设备的输入。 这是终 端服务器的 TermDD.sys 驱动程序处理来自远程客户端的输入的方式的结果。 自定义设备的初始化和 ISR 供应商可以提供可选的上层设备筛选器驱动程序,这些驱动程序可将以下可选回调添加到 I8042prt 的操作: PI8042_KEYBOARD_ISR (ISR) 键盘中断服务例程自定义 I8042prt 键盘 ISR 的操作。 如果 I8042prt 的默认操作足够,则不需要键盘 ISR 回调。 在 I8042prt 键盘 ISR 验证键盘中断 后,它会调用键盘 ISR 回调。 PI8042_MOUSE_ISR 鼠标 ISR 自定义 I8042prt 鼠标 ISR 的操作。 如果 I8042prt 的默认操 作足够,则不需要鼠标 ISR 回调。 I8042prt 鼠标 ISR 验证鼠标中断后,它会调用鼠标 ISR 回调。 PI8042_KEYBOARD_INITIALIZATION_ROUTINE 键盘初始化回调补充 I8042prt 对键盘设 备的默认初始化。 I8042prt 在初始化键盘设备时调用此例程。 I8042prt 通过使用键盘设备的 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD 请求和鼠标 设备的 IOCTL_INTERNAL_I8042_HOOK_MOUSE 请求来添加上层设备筛选器驱动程序提 供的回调。 在 I8042prt 收到来自设备类驱动程序的连接请求后,I8042prt 会同步将特定 于设备的挂钩请求发送到设备堆栈的顶部。 筛选器驱动程序收到挂钩请求后,会执行以下操作: 保存传递给筛选器驱动程序的上层驱动程序挂钩信息(如果有)。 挂钩信息包括指向上下文的指针、指向 ISR 回调的指针,以及指向仅) 键盘的初始化 回调 (初始化回调的指针。 将上层驱动程序挂钩信息替换为筛选器驱动程序的挂钩信息。 保存 I8042prt 的上下文和指向筛选器驱动程序回调可以使用的回调的指针。 示例筛选器驱动程序 Kbfiltr 和 Moufiltr 提供以下回调例程: KbFilter_IsrHook 是PI8042_KEYBOARD_ISR回调的模板。 KbFilter_InitializationRoutine 是PI8042_KEYBOARD_INITIALIZATION_ROUTINE回调 的模板。 MouFilter_IsrHook 是PI8042_MOUSE_ISR回调的模板。 I8042prt 使用启动信息请求将指向设备中断对象的指针传递到其设备堆栈中的上层驱动程 序。 设备启动后,筛选器驱动程序可以使用中断对象将其操作与中断服务例程同步。 筛 选器驱动程序应仅在调用 KeSynchronizeExecution 时使用中断对象。 将筛选器驱动程序的操作与设备的 ISR 同步 I8042prt 通过使用键盘设备的 IOCTL_INTERNAL_I8042_KEYBOARD_START_INFORMATION 请求和鼠标设备的 IOCTL_INTERNAL_I8042_MOUSE_START_INFORMATION 请求,将中断对象指针传递到 设备堆栈的顶部。 在设备的硬件初始化后,I8042prt 将启动信息请求同步发送到设备堆 栈顶部。 筛选器驱动程序收到启动信息请求后,会保存启动信息,并将请求向下传递到 设备堆栈。 I8042prt 完成请求。 若要自定义设备的操作,筛选器驱动程序需要将控制数据写入设备。 筛选器驱动程序必 须将对设备的写入与设备的中断服务例程以及设备上的其他异步读取或写入同步 (,例 如,由集类型化请求或设置键盘指示器请求启动的写入) 。 为此,I8042prt 支持 IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER 请求和 IOCTL_INTERNAL_I8042_MOUSE_WRITE_BUFFER 请求。 写入缓冲区请求与设备的 ISR 和其他读取或写入设备的请求同步。 I8042prt 支持高级设备筛选器驱动程序在其 ISR 回调中可以使用的以下回调: PI8042_ISR_WRITE_PORT 设备的写入端口回调在设备的 ISR IRQL 处写入 i8042 端口。 PI8042_QUEUE_PACKET 设备的队列数据包回调将输入数据包排队,以便由设备的 ISR DPC 进行处理。 PI8042_SYNCH_READ_PORT 此回调可用于 PI8042_KEYBOARD_INITIALIZATION_ROUTINE 回调。 I8042prt 指定 I8042prt 输入到键 盘初始化例程的 ReadPort 参数中的读取端口回调。 PI8042_SYNCH_WRITE_PORT 此回调可用于 PI8042_KEYBOARD_INITIALIZATION_ROUTINE 回调。 I8042prt 指定 I8042prt 输入到键 盘初始化例程的 WritePort 参数中的写入端口回调。 I8042prt 将指针传递到 INTERNAL_I8042_HOOK_KEYBOARD 结构中的键盘设备回调, I8042prt 使用该结构通过 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD 请求输入信息。 I8042prt 将指针传递到 INTERNAL_I8042_HOOK_MOUSE 结构中的鼠标设备回调, I8042prt 使用该结构通过 IOCTL_INTERNAL_I8042_HOOK_KEYBOARD 请求输入信息。 筛选器驱动程序收到挂钩设备请求后,会保存 I8042prt 回调指针,以便在筛选器驱动程 序的 ISR 回调中使用。 将筛选器驱动程序的写入同步到设备 筛选器驱动程序可以使用的 I8042prt 回调 OS 驱动程序安装 项目 • 2023/06/15 本部分记录以下特定于类的 INF 文件条目,供应商可以使用这些条目来控制 Microsoft 提 供的键盘和鼠标类安装程序如何在 Microsoft Windows 2000 及更高版本下安装设备 : INF DDInstall.MigrateToDevNode 节 INF SharedDriver 条目 INF PS2_Inst.NoInterruptInit.Bioses 节 INF PS2_Inst.NoInterruptInit 节 有关特定示例,请参阅 keyboard.inf 和 msmouse.inf 中的这些 INF 文件条目的用法Microsoft 提供的键盘和鼠标设备设置类的 INF 文件。 对于通过 PS/2 兼容控制器连接的每个内部/集成设备,Microsoft Windows 操作系统使用 ACPI 为设备构造设备标识字符串列表。 即插即用管理器使用这些设备标识字符串将设备 与 INF 文件匹配。 即插即用设备字符串分为以下类型: 单个唯一设备 ID (通常只是硬件 ID 列表中的第一个 ID) 硬件 ID 的有序列表 兼容 ID 的有序列表 即插即用管理器在尝试将设备与 INF 文件匹配时,始终使用列表中的所有标识符,但会 首先尝试使用最具体的标识符。 这样,设置软件就可以按其适用性顺序优先选择驱动程 序,供应商提供的驱动程序位于优先级列表的顶部。 为了找到驱动程序匹配项,安装程序会将设备的父总线驱动程序) 报告 (设备的硬件 ID 和 兼容 ID 与计算机上的 INF 文件中列出的硬件 ID 和兼容 ID 进行比较。 如果安装程序找到 多个匹配项,则会为每个可能的驱动程序匹配项分配一个“排名”。 排名数字越低,驱动 程序与设备的匹配越好。 若要实现上述方案,ACPI 应报告以下内容: 用于标识固件和/或硬件模型的一个或多个硬件 ID。 ACPI 规范 V5.0) 中定义的 HWID (的 格式如下所示: ACPI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss&REV_rrrr PS/2 键盘和鼠标的一般规则 ACPI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss ACPI\VEN_vvvv&DEV_dddd&REV_rrrr ACPI\VEN_vvvv&DEV_dddd&CLS_cccc&SUBCLS_nnnn&PI_pp ACPI\VEN_vvvv&DEV_dddd ACPI\vvvdddd ACPI\vvvvdddd 一个兼容 ID,允许操作系统加载泛型类驱动程序。 这些通用 ID 已在键盘和鼠标 INF 中 列出。 具有正确格式的 PS/2 键盘硬件 ID 的系统示例如下: 硬件 ID:ACPI\MSF0001; 兼容 ID:*PNP0303 注意: Windows 允许旧版 (例如 ACPI 4.0) 样式的 ACPI 硬件 ID,但首选始终标识唯一的键 盘或鼠标设备。 Windows 硬件认证工具包包括以下要求 (System.Fundamentals.Input.PS2UniqueHWID) 。 在移动计算元素上通过 PS/2 嵌入 键盘和鼠标的系统制造商必须确保唯一的硬件 ID。 唯一硬件 ID 的格式必须允许 Windows 更新 (WU) 标识设备并为其加载正确的驱动程序。 此Windows 8徽标要求 适用于 x86/64 移动系统, (不支持 ARM 系统上的 PS/2) 有关更多详细信息,请参阅标题为“笔记本电脑上 PS/2 输入设备的硬件 ID”的 MSDN 白皮 书。 INF DDInstall.MigrateToDevNode 部分 项目 • 2023/03/08 [install-section-name.MigrateToDevNode] [install-section-name.nt.MigrateToDevNode] [install-section-name.ntx86.MigrateToDevNode] [install-section-name.ntia64.MigrateToDevNode] ServiceName=value-name [,value-name],... 键盘和鼠标类安装程序将 值名称 字符串列表指定的条目值从注册表项 HKLM\System\CurrentControlSet\Services\ServiceName\Parameters 复制到所安装设 备的设备节点。 ServiceName:指定与设备端口关联的服务名称, (例如 i8042prt、 sermouse 等) 。 value-name:指定注册表项 HKLM\System\CurrentControlSet\Services\ServiceName\Parameters 下的条目 值。 Microsoft 支持 INF DDinstall。MigratetoDevNode 部分主要用于简化将Windows NT 4.0 旧设备移植到 Windows 2000 及更高版本。 键盘和鼠标类安装程序在系统启动设备堆栈之前复制所有 value-name 条目值。 指定的项 值可以是任何有效的注册表项值。 value-name 条目值不会从 *...\ServiceName_\Parameters 注册表项中删除。 条目和值 注解 INF SharedDriver 条目 项目 • 2023/03/08 [ControlFlags] SharedDriver=install-section-name,warning-text-string 在键盘或鼠标类安装程序安装 PS/2 设备之前,它会在设备的 INF ControlFlags 部分中检 查 SharedDriver 条目。 如果存在此类条目值,类安装程序将通过显示警告文本字符串来 通知用户,并为用户提供取消更改 PS/2 端口驱动程序的选项。 SharedDriver:指定设备驱动程序由 PS/2 键盘和鼠标设备共享。 install-section-name:指定设备的 DDInstall 部分。 warning-text-string:指定类安装程序在更改 PS/2 端口驱动程序之前用于警告用户 的字符串。 条目和值 INF PS2_Inst.NoInterruptInit.Bioses 部分 项目 • 2023/06/15 [PS2_Inst.NoInterruptInit.Bioses] 禁用=disable-string 鼠标类安装程序检查 disable-string 是否是 HKLM\Hardware\Description\System\SystemBiosVersion 字符串值的子字符串。 如果 是,类安装程序将执行 INF PS2_Inst.NoInterruptInit 节中指定的 INF 指令。 禁用:设置为 disable-string 值。 disable-string:指定 HKLM\Hardware\Description\System\SystemBiosVersion 中 唯一标识系统 BIOS 的子字符串。 此部分仅用于 PS/2 鼠标设备,并且仅与 INF PS2_Inst.NoInterruptInit 节结合使用。 条目和值 注解 INF PS2_Inst.NoInterruptInit 部分 项目 • 2023/06/15 [PS2_Inst.NoInterruptInit] AddReg = add-reg-section**。AddReg** 如果 INF PS2_Inst.NoInterruptInit.Bios 中的“禁用”条目与系统 BIOS 版本匹配,则鼠标类 安装程序将执行此部分中的指令。 add-reg-section:指定鼠标类安装程序用于在设备的硬件密钥中设置注册表值的 AddReg 部分。 注册表值确定系统是使用中断还是轮询初始化鼠标设备。 此部分仅与 INF PS2_Inst.NoInterruptInit.Bioses 部分结合使用。 本部分的主要用途是指 定 AddReg 部分,用于将注册表值添加到鼠标设备的硬件密钥。 HKR,“DisableInitializePolledUI”,0x00010001,1 HKR,“MouseInitializePolled”,0x00010001,1 DisableInitializePolledUI 指定一个REG_DWORD标志,该标志指示属性页上的“快速初始化检查”框是否可用。 如果 DisableInitializePolledUI 设置为非零值,则检查框不可用;否则,检查框可用。 MouseInitializedPolled 指定一个REG_DWORD标志,该标志指示系统是否必须轮询设备才能初始化它。 如果 MouseInitializedPolled 设置为 1,系统会轮询鼠标设备;否则,系统会使用中断。 条目和值 注解 add-reg 节条目 DirectInput 概述 项目 • 2023/06/14 Microsoft DirectInput 文档介绍如何为 Microsoft DirectX 版本 1.0、2.0、3.0、5.0、6.0、 7.0、7.0a 和 8.0 的输入组件编写驱动程序。 DirectX 版本 1.0 和 2.0 包含与原始 Microsoft Windows 95 相同的游戏杆支持,而 DirectX 3.0 添加了组件对象模型 (COM) 用 于鼠标和键盘访问的接口,并改进了某些游戏杆支持的实现,而无需更改驱动程序模型。 DirectX 5.0 及更高版本添加了一个 COM 接口,用于游戏杆访问、力回馈以及简化对游戏 杆配置信息的访问。 本文档包括以下主题: 游戏杆支持 强制反馈设备驱动程序接口 扩展 DirectInput 游戏控制器控制面板 “游戏杆支持”概述 项目 • 2023/06/15 Microsoft DirectX 提供的游戏杆支持类型因版本不同而有所不同。 在 Windows 95/98/Me 中,DirectX 支持两种方法来自定义游戏杆功能:通过 Windows 注册表中的自 定义条目和虚拟设备驱动程序 (VxD) 创建(称为 游戏杆微型驱动程序)。 DirectX 版本 1.0、2.0 和 3.0 中使用的微型驱动程序支持原始微型驱动程序接口,但 DirectX 3.0 接口 略有不同。 除了原始微型驱动程序模型,DirectX 版本 5.0 及更高版本还包括一个备用驱 动程序接口,该接口通常单独描述。 Windows 95/98/Me 游戏杆驱动程序和配置程序支持插入 IBM 标准游戏端口的模拟游戏 杆。 游戏杆制造商可以使游戏杆配置程序可自定义,并为最终用户提供有关如何自定义 游戏杆的明确指示。 游戏杆可以通过注册表向 Windows 95/98/Me 发送其功能信号。 这 些功能可能包括使用油门、视点 (POV) 帽、舵和游戏杆按钮的数量。 除自定义注册表信息外,所有非 IBM 标准游戏杆(例如数字游戏杆、MIDI 游戏杆和由游 戏杆加速器驱动的模拟游戏杆)都必须提供游戏杆微型驱动程序。 游戏杆 OEM 可以编写 微型驱动程序,以便访问非标准游戏杆硬件。 这为数字游戏杆提供了一种机制,用于使 用游戏杆应用程序编程接口 (API) 的任何基于 Windows 的游戏。 驱动程序模型可以处理最多六个轴、一个 POV 帽和一个双字按钮,以便 OEM 可以轻松 地为具有比当前游戏端口所允许的自由度更高的新硬件创建微型驱动程序。 游戏杆微型 驱动程序为硬件供应商提供完全的灵活性,并允许游戏创建者将已安装的基础与游戏一起 使用。 在 DirectX 5.0 及更高版本中,模拟游戏杆支持也分为使用新接口的微型驱动程 序。 仅当配置了模拟游戏端口时,才会加载此新接口。 轮询扩展了三个额外的 POV 帽、另外三个包含按钮数据的双字,以及一个指定它返回每个轴的速度、加速度和/或力 数据的方法。 当前虚拟游戏杆驱动程序 (VJoyD) 允许配置最多 16 台设备,其中任意数量都可以由微型 驱动程序驱动。 微型驱动程序到设备的配置可以是一对一或一对多。 本节包括: 原始接口 DirectX 5.0 接口 INF 文件创建 注册表设置 VJoyD 微型驱动程序重写 轴选择 原始接口 项目 • 2023/06/15 以下游戏杆微型驱动程序回调特定于原始接口。 在从处理SYS_DYNAMIC_DEVICE_INIT消 息返回之前,必须向 VJoyD VJOYD_Register_Device_Driver 服务注册四个特定于游戏杆的 回调。 EAX 必须指向轮询例程,EBX (配置处理程序) ,ECX (功能回调) ,EDX (标识例程) 。 游戏杆微型驱动程序注册序列的示例如下所示: Mov eax、offset32 _PollRoutine@8 Mov ebx、offset32 _CfgRoutine Mov ecx、offset32 _HWCapsRoutine@8 Mov edx、offset32 _JoyIdRoutine@8 VxDcall VJOYD_Register_Device_Driver 除了注册,微型驱动程序此时还可以执行任何其他初始化。 游戏杆微型驱动程序模型不 需要任何特定操作来响应SYS_DYNAMIC_DEVICE_EXIT,但 VxD 仍可能将其用于最终内部 清理。 C++ 有关如何连接配置管理器的常规信息,请参阅 Windows 驱动程序开发工具包 (DDK) 的 Windows Me 部分的 即插即用 环境部分。 DDK 位于 Windows 驱动程序工具包 (WDK) 之前。 仅当 VJoyD 收到回调时加载微型驱动程序时,配置管理器回调才会传递给微型驱动程 序。 因此,此回调的当前实现存在严重问题。 当在系统启动期间枚举设备节点时,当配 置管理器在运行时针对特殊事件(例如设备重新配置)发送消息时,以及系统关闭时, VJoyD 将接收与其关联的那些设备节点的回调。 因此,只有上次启动时选择的设备才会 及时加载以接收这些消息。 这会限制调用此回调时执行的潜在函数数,因为用户可以启 动系统、配置游戏杆、玩游戏、取消配置游戏杆,以及在不调用此回调的情况下关闭。 Configuration Manager 回调 CONFIGRET CM_HANDLER CfgRoutine( CONFIGFUNC cfFuncName, SUBCONFIGFUNC scfSubFuncName, DEVNODE dnToDevNode, ULONG dwRefData, ULONG ulFlags ); 对于不需要任何硬件资源的设备,这不是问题。 使用此类资源的设备有多个选项:它们 只能在启动时配置时工作,可以从配置管理器动态分配资源,或者可以在注册表中搜索其 设备节点的分配并请求信息。 给定上述信息后,驱动程序会在首次加载驱动程序并接收SYS_DYNAMIC_DEVICE_INIT时 或首次通过轮询例程正确初始化。 同样,在收到SYS_DYNAMIC_DEVICE_EXIT消息时,应 释放资源。 另一个问题是,当前服务游戏杆设备的所有配置管理器回调都发送到所有已加载的微型驱 动程序。 但是,可以使用 dnToDevNode 参数查找设备标识符,并且可以针对此驱动程序 可以处理的设备检查此标识符。 C++ 调用轮询例程是为了直接响应调用 joyGetPos 或 joyGetPosEx 的应用程序,或者当 Windows 95/98/Me 定期为名为 joySetCapture 的应用程序调用 joyGetPos 时。 仅当微型 驱动程序首次在其轮询回调上收到调用时,才能确定应用程序需要来自它的数据。 对于 当前位于 16 个可用游戏杆列表中的所有设备,无论是否有任何应用程序请求了数据,都 会调用所有其他回调。 可能的返回值为JOY_OEMPOLLRC_YOUPOLL、JOY_OEMPOLLRC_FAIL和 JOY_OEMPOLLRC_OK。 除仅按钮轮询外,返回值在返回到应用程序之前会解释为 JOYERR_NOERROR或JOYERR_UNPLUGGED。 始终假定按钮轮询成功。 如果轮询的设备未响应,或者 VJoyD 请求微型驱动程序无法处理的轮询,则返回 JOY_OEMPOLLRC_FAIL。 在前一种情况下,应确保设备不会发生故障,除非它确实出现 故障,因为应用程序可能会停止一切,并请求用户检查与设备的连接。 例如,如果第一 次轮询失败,对 joySetCapture 的调用会失败。 在需要用户干预或检测到不可恢复的设 备错误之前,次要设备故障不应导致故障报告。 例如,如果某个数据包无效,使用基于 数据包的协议进行通信的设备应在轮询失败之前尝试重试。 识别正版设备故障并最终返回错误非常重要;否则,应用程序无法确定是否需要用户干 预。 如果在执行错误恢复时返回旧数据或错误数据,则应限制返回的数据的含义、允许 的轮询数或初始错误允许的时间,以便驱动程序不会延迟过长的时间。 当请求微型驱动 程序在它无法控制的设备上执行轮询,或者执行它无法服务的轮询类型或子类型时,失败 始终是正确的响应。 如果标准模拟投票产生正确的结果,则可以使用 JOY_OEMPOLLRC_YOUPOLL。 轮询回调 int stdcall PollRoutine( int type, LPJOYOEMPOLLDATA pojd ); 当 JOYINFOEX 结构填充了请求的数据时,你应该在常规情况下返回 JOY_OEMPOLLRC_OK。 如果使用轮询在设备上执行初始化,则必须小心。 应用程序可以通过检查返回代码执行 初始轮询,以检查设备的可用性。 然后,他们可以在没有错误检查的情况下进行后续轮 询。 这实质上是 joySetCapture 的作用。 理想情况下,应执行所有初始化和第一次轮 询。 对于设置设备所需的时间长达一秒的情况,只需验证设备是否存在且正常工作,并 为第一次轮询返回惰性数据就足够了。 API 和系统驱动程序对应用程序发出的请求执行验证,并在完成后将所需数据复制到应用 程序结构中。 微型驱动程序不应复制此功能。 但是,没有什么能阻止一个进程轮询设 备,而另一个进程仍在轮询中。 此事件的后果并不比报告两个轴的不同样本更严重。 如 有必要,微型驱动程序可以执行自己的进程同步。 返回值取决于“type”参数及其支持的设备。 应始终返回按钮和按钮编号。 由于无法向微 型驱动程序指定需要 POV 轮询,因此,如果请求任何轴,应返回此值。 如果设备不支 持,请设置POV_UNDEFINED。 对于单轴轮询,该值在 DIRECTX 5.0 及更高版本中 (的 VJPOLLDATA 结构的 dwX 成员中返回,) 。 对于请求的轴数为奇数的多轴请求, JOYOEMPOLLDATA 结构的 do_other 成员指定是就地返回最后一个轴,还是返回下一个 轴。 例如,在三轴轮询中, 成员指定返回的轴是 X、Y、Z 还是 X、Y、R。 下面是其他可能返回值的列表,按类型分类 (可以填充额外数据,但请注意,奇数轴的所 有轮询都必须解码 do_other 成员,以确定它) 返回的内容: JOY_OEMPOLL_GETBUTTONS:没有额外内容。 JOY_OEMPOLL_POLL1:在 dwX 成员中返回do_other成员中指定的轴。 JOY_OEMPOLL_POLL2:X 轴和 Y 轴在 dwX 和 dwY 成员中返回。 JOY_OEMPOLL_POLL3:X 轴和 Y 轴在 dwX 和 dwY 成员中返回。 如果 do_other 成员为非零,则 dwR 成员中返回 R 轴。 否则,将在 dwZ 成员中返 回 Z 轴。 JOY_OEMPOLL_POLL4:X、Y、Z 和 R 轴分别在 dwX、 dwY、 dwZ 和 dwR 成员中 返回。 JOY_OEMPOLL_POLL5:X、Y、Z 和 R 轴分别在 dwX、 dwY、 dwZ 和 dwR 成员中 返回。 如果 do_other 成员为非零,则 dwR 成员中返回 V 轴。 否则,将在 dwZ 成员中返 回 U 轴。 JOY_OEMPOLL_POLL6:X、Y、Z、R、you 和 V 轴分别在 dwX、 dwY、 dwZ、 dwR、 dwU 和 dwV 成员中返回。 DirectX 3.0 添加了非轮询类型 JOY_OEMPASSDRIVERDATA,其中 do_other 成员包含应用 程序传递的 DWORD。 可以将此 DWORD 用于任何微型驱动程序定义的函数,但它特别 旨在使已完全标识微型驱动程序的自定义安装应用程序能够发送特定于设备的命令和配置 信息。 微型驱动程序应返回它不支持的所有类型的JOY_OEMPOLLRC_FAIL。 虽然坐标轴数据以双字返回,但如果将标准游戏杆控制面板配置用作唯一配置机制,则轴 值的范围应限制为大约 10 位值。 由于用户无法轻松查看所发生的情况,因此这有助于避 免混淆。 为了帮助与现有应用程序兼容,微型驱动程序返回的轴应与模拟游戏杆 (返回的 轴相同(如果适用) )。 例如,X 是左侧最小化的从左到右的移动,依此而过。 对于激活的 POV 帽子,方向应表示为角度(以度为单位)乘以 100,其中 0 表示向前, 9000 向右,向后 18000,向左 27000。 由于轮询例程调用是设备仍在使用的唯一正面指示,因此使用共享资源(如通信端口)的 微型驱动程序应跟踪上次使用它们的时间。 如果使用时间过长,微型驱动程序应停止对 设备采样,并释放资源,以防用户已完成设备使用,现在正尝试将资源用于其他目的。 如果发生通信错误,这一点很重要,因为这可能表明设备已拔出电源。 C++ 每当请求设备的硬件功能时,将调用 HWCapsRoutine。 特别是,VJoyD 在从 VJOYD_Register_Device_Driver 返回之前调用 HWCapsRoutine。 因此,在注册设备之 前,驱动程序必须完成此调用所依赖的任何初始化。 这些值通常是常量。 对于具有四个 按钮和三个轴的设备,其中第三个可能返回一个限制或一个方向键值,以下为合适: C++ 硬件功能回调 int __stdcall HWCapsRoutine( int joyid, LPJOYOEMHWCAPS pjhwc ); pjhwc->dwMaxButtons = 4; // This should always be the number of buttons pjhwc->dwMaxAxes = 4; // The largest axis number which may be requested pjhwc->dwNumAxes = 3; // The number of axes the device has 游戏杆识别回调 C++ 当用户将游戏杆配置为 16 个游戏杆之一或取消配置时,VJoyD 调用 JoyIDRoutine。 如果 微型驱动程序可以支持 joyid 中请求的 ID,则 JoyIdRoutine 将返回非零值。 如果微型驱 动程序不支持 ID,则例程返回零值。 每当进行任何更改并调用 joyConfigChanged 来更新驱动程序时,VJoyD 会从 JOYSTICKID1 开始循环访问所有 16 台设备。 它将所有设备重置为未使用设备,然后再次 循环访问它们以设置系统需要使用的所有设备。 在控制面板操作期间,此过程可能需要 大量的调用,这会导致初始化的回调用法出现问题。 如果在系统启动完成之前(即其他 服务不可用)之前进行调用,则为 true。 为多个设备服务回调的微型驱动程序应尽可能尝试将游戏杆标识符绑定到单个物理设备, 以避免用户混淆。 在单个会话期间,可以相对轻松地实现此功能,但重启后可能不需要 这样做。 在从处理SYS_DYNAMIC_DEVICE_INIT消息返回之前,必须向 VJoyD VJOYD_Register_Device_Driver服务注册四个特定于游戏杆的回调。 EAX 必须指向轮询例 程,EBX (配置处理程序) ,ECX (功能回调) ,EDX (标识例程) 。 游戏杆微型驱动程序注册 序列的示例如下所示: Mov eax、offset32 _PollRoutine@8 Mov ebx、offset32 _CfgRoutine Mov ecx、offset32 _HWCapsRoutine@8 Mov edx、offset32 _JoyIdRoutine@8 VxDcall VJOYD_Register_Device_Driver 除了注册,微型驱动程序此时还可以执行任何其他初始化。 游戏杆微型驱动程序模型不 需要任何特定操作来响应SYS_DYNAMIC_DEVICE_EXIT,但 VxD 仍可能使用它进行最终的 内部清理。 int __stdcall JoyIdRoutine( int joyid, BOOL used ); DirectX 5.0 接口 项目 • 2023/06/15 VJoyD 及其任何早期版本都无法识别 DirectX 5.0 及更高版本的接口。 因此,微型驱动程 序必须在尝试注册之前检查 VJoyD 的版本。 VJoyD 不支持标准版本消息。 因此,必须获 取设备描述符块 (DDB) ,以便 VJoyD 手动实现此目的,然后检查 DDB 中标记的版本。 有关如何实现此功能的详细信息,请参阅示例驱动程序。 请注意,DDB 中标记的版本与 版本资源中标记的版本不同。 微型驱动程序注册其回调的过程得到了显著扩展,并在 DirectX 5.0 中启动。 如前所述,VJoyD 或外部所有者 ((如 HID 堆栈) )可以加载 Minidrivers。 当 VJoyD 加 载设备时,它要求微型驱动程序使用 VJoyD VJOYD_Register_Device_Driver服务注册自 身。 但是,微型驱动程序可能会收到三条系统控制消息,这应提示其注册。 第一个是 SYS_DYNAMIC_DEVICE_INIT消息,如果在 VJoyD 加载 VxD 之前未加载 VxD,微型驱动程 序将收到该消息。 这使用与用于注册的原始接口相同的机制。 由于它是 VxD 的新负载, 因此任何定义的 INIT 部分都可用。 收到此消息后,VxD 执行内部初始化,然后向 VJoyD 注册。 例如,如果应用程序已加载微型驱动程序 (,如果应用程序已加载它以使用专用 IOCTL 接 口) ,则在 VJoyD 加载它时不会再次收到此消息。 在这种情况下,Windows 98 会发出 SYS_DYNAMIC_DEVICE_REINIT消息,作为响应,微型驱动程序应注册到 VJoyD。 由于这 不是 VxD 的新负载,因此 INIT 部分不再可用。 对于未在 Windows 98 下运行的微型驱动 程序,VJoyD 认为加载微型驱动程序时缺少响应,因为 VxD 已加载。 VJoyD BEGIN_RESERVED_PRIVATE_SYSTEM_CONTROL发出定向系统控制消息,微型驱动程序应 注册该消息作为响应。 除了加载时注册之外,当驱动程序检测到其所驱动设备的状态发生更改时,VJoyD 现在还 接受新类型的注册。 除了回调,DirectX 5.0 接口还允许在注册时设置各种控制参数和设 备说明。 这包括设备的完整说明 (完整的校准信息) ,它可以更改以适应它检测到的任何 其他设备。 DirectX 5.0 及更高版本的接口的游戏杆微型驱动程序回调由控制回调、轮询回调和强制 反馈回调组成。 为了适应这些更改,将重载 VJoyD VJOYD_Register_Device_Driver 服 务,以便 EAX 保留0xFFFFFFFF以表明新注册正在使用,ECX 保留指向包含参数的结构的 指针。 EBX 和 EDX 的值未定义,驱动程序可能假定 EBX 从未损坏的调用返回。 下表显示了游戏杆微型驱动程序注册序列: mov eax, 0ffffffffh mov ecx,offset32 RegData VxDcall VJOYD_Register_Device_Driver VJREGDRVINFO 结构将传递给新注册。 必须VJRT_LOADED VJREGDRVINFO 结构的 dwFunction 成员;所有其他值都保留。 VJRT_LOADED在新接口中的使用方式与在原始接口中使用注册的方式相同。 也就是说, 将回调传递给 VJoyD 以响应正在加载的微型驱动程序。 控件回调和轮询回调合并到单个表中,因为所有驱动程序都必须提供控件回调,并且只有 少数设备仅输出。 这些回调是使用 VJPOLLREG 结构注册的。 VJPOLLREG 结构的 lpCfg 成员指向标准配置管理器回调,与原始接口中的 CfgRoutine 完 全相同。 主要区别在于 VJoyD 会根据需要调用配置管理器回调。 VJoyD 将驱动程序链接 到已安装的设备节点,并调用此回调以通知驱动程序配置管理器活动。 上一个接口为每 个配置管理器回调调用所有加载的驱动程序,而 DirectX 5.0 及更高版本接口仅调用它已 链接到已更改的设备节点的一个驱动程序。 此外,由于配置管理器活动可能会在未加载 驱动程序时发生,因此 VJoyD 实现基元缓存系统,以便在设备节点已启动的情况下,驱 动程序在加载时通知此设备节点。 由于始终调用驱动程序进行资源分配,因此它们不应检查默认端口来查找所需的资源。 遗憾的是,必须找到某种方法来使用上一个接口的驱动程序仍然以旧的方式工作。 这意 味着,虽然 VJoyD 仅将一组资源分配给单个驱动程序,但加载的任何旧驱动程序仍可以 使用尚未分配给它们的端口。 分配资源后,驱动程序应对设备执行所需的任何握手,以 确定设备状态。 由 VJPOLLREG 结构的 fpInitialize 成员指向的 Initialize 回调 () 替换上一个接口中的 JoyId 回调。 main区别在于,VJoyD 将设备在注册期间传递给 VJoyD 的任何设备实例标识传回 驱动程序,以便在驱动程序支持多个设备时可以区分实例。 7 备注 如果需要打开注册表项,应使用 VJOYD_OpenConfigKey_Service 和 VJOYD_OpenTypeKey_Service 宏,而不是直接打开注册表项。 使用这些服务宏可 确保打开正确的注册表分支。 此外,如果基础注册表数据的结构可能不同,则未来 版本的 DirectInput 将支持服务宏。 创建 INF 文件 项目 • 2023/06/15 应使用 INF 文件安装所有微型驱动程序和 OEM 定义的游戏杆,以便向系统提供所有必要 的信息。 INF 文件根据设备类、需要复制的文件、任何兼容设备、设备所需的任何系统 资源以及注册表更改来描述设备安装。 用于自定义标准模拟驱动程序的 INF 文件不需要 复制任何文件、状态兼容设备或指定系统资源。 INF 文件可以指定其他操作,例如修改 Autoexec.bat文件,但这不是游戏杆微型驱动程序所必需的。 INF 文件包含以下元素: 游戏杆属于 MEDIA 类,在“添加新硬件”控制面板下标题为“声音、视频和游戏控制器”。 应从示例或 Joystick.inf 文件复制类相关部分。 INF 文件的“SourceDisksFiles”部分指定要复制的文件。 这包括所有必要的驱动程序以及 任何其他文件,例如文档和设置应用程序。 由于这可能是要安装在用户系统上的第一个 游戏杆驱动程序,因此除了此设备的特定驱动程序外,还应复制系统游戏杆驱动程序 Vjoyd.vxd 和 Msjstrick.drv。 这两个驱动程序的源应通过引用 Layout.inf (导致提示用户输 入 Windows 95/98/Me 安装光盘) 而不是分发在 OEM 光盘上。驱动程序应复制到用户的 系统目录,即目标代码 11。 INF 文件指向的特定于制造商的部分包含每个可安装的设备的一个条目。 每个条目都包 含设备的名称,后跟安装部分的名称、设备 ID 和任何兼容设备。 如果设备已注册为即插 即用兼容,则即插即用 ID (以星号) 开头应用于设备 ID。 如果设备尚未注册,则应使用不 即插即用兼容的设备 ID (即不以星号) 开头的设备 ID。 注册此类设备时,请避免选择与其 他设备 ID 冲突的 ID (“游戏杆”,例如,不会是一个好的 ID) 。 需要系统资源(例如输入/输出 (I/O) 端口)的设备使用安装部分中的 LogConfig 条目来 指定它们可以使用的配置。 某些设备不使用自己的资源。 相反,它们使用另一个驱动程 序(如串行端口驱动程序)来与设备通信。 DirectX 3.0 VJoyD 在处理模拟游戏端口 I/O 端口要求方面不同于以前的版本。 仅当至少一个设备配置了标准游戏端口范围中的 I/O 设置设备类 选择源文件 设置特定于制造商的数据 设置 LogConfig 条目 端口分配0x200以0x20f时,旧版本才起作用。 此外,第二个 I/O 范围必须是单个端口。 如果没有将游戏端口配置为允许没有游戏端口的系统使用通过微型驱动程序操作的设备, 则较新的 VJoyD 将有效。 第二个 I/O 范围现在可以是多个端口。 使用0x200 0x20f范围内的端口的设备被 VJoyD 解释为模拟游戏端口,因此,配置管理器 可能将其视为冲突设备。 忽略任何其他游戏端口 I/O 端口集;如果计算机在两张卡上具有 游戏端口,则仅轮询一个卡上的端口。 如果设备需要以非标准方式使用标准游戏端口, 事情会变得更加有趣。 在设备的安装部分的 LogConfig 条目中请求标准端口可以正常工 作,但通常会导致大量重新配置和重新启动以交换游戏杆。 另一种方法是使用通过符合 游戏端口条件的配置管理器回调传递的任意一组 I/O 范围与 VJoyD 共享资源。 只要用户 不同时为标准模拟驱动程序和 OEM 驱动程序配置游戏杆,然后运行一个尝试轮询它们的 应用程序,这样就有效。 在 DirectX 3.0 中,实现了更改,允许通过设置JOY_HWS_ISGAMEPORTDRIVER标志来调 用 OEM VxD 来代替标准模拟轮询。 控制面板允许将此类设备设置为全局驱动程序,这 意味着,对于任何没有与之关联的微型驱动程序的游戏杆,它将被调用,而不是内部模拟 轮询。 这可确保 VJoyD 不会干扰 OEM 设备的轮询。 如果启动过程中的前四个设备全部由微型驱动程序处理 (这可能是 OEM 全局驱动程序) , 则 VJoyD 不会检查并且无法使用任何游戏端口,即使这些设备不再由微型驱动程序处 理。 如果 VJoyD 不能 (使用其端口,或者) 不存在游戏端口,则向轮询请求返回 JOY_OEMPOLLRC_YOUPOLL不会导致使用标准轮询。 仅当重新分配游戏端口资源 (可能 直到重新启动) 之后,才使用此轮询重新配置回设备。 INF 文件还需要在安装部分的 AddReg 条目选择的节中设置注册表项。 对于需要微型驱 动程序的设备,需要设置以下内容,以确保驱动程序与多媒体系统驱动程序正确关联: C++ %OEMJoy.DeviceDesc% 字符串将替换为已调用的任何设备名称字符串。 描述此游戏杆的值将放入注册表中的 OEM 定义的键下,从HKEY_LOCAL_MACHINE) 下找 到的路径REGSTR_PATH_JOYOEM (开始。 在此键下,OEM 可以放置许多静态值,这些值 设置 AddReg 条目 HKR,,DevLoader,,mmdevldr.vxd HKR,Drivers,,, HKR,Drivers,MIGRATED,,0 HKR,Drivers\joystick,,, HKR,,Driver,,vjoyd.vxd HKR,Drivers\joystick\msjstick.drv,,, HKR,Drivers\joystick\msjstick.drv,Description,,%OEMJoy.DeviceDesc% HKR,Drivers\joystick\msjstick.drv,Driver,,msjstick.drv 自定义 OEM 游戏杆在游戏杆校准程序中的显示方式,以及用于 Windows 95/98/Me 的应 用程序。 值的名称在 Regstr.h 中定义,因此下面讨论的是这些常量的名称,而不是注册 表中显示的名称。 每个 OEM 定义的设备都必须至少定义其基本属性,以及用户可以在游 戏杆选择框中看到控制面板的名称。 若要加载微型驱动程序,该值必须包含微型驱动程 序 VxD (包括 .vxd 扩展) 的名称。 OEM 名称值 (REGSTR_VAL_JOYOEMNAME) ,微型驱动 程序文件名 (REGSTR_VAL_JOYOEMCALLOUT) 值为简单字符串。 值 REGSTR_VAL_JOYOEMDATA的基本属性是二进制数据,其含义详见以下段落。 有两个双字:第一个包含一组标志,第二个是设备具有的按钮数。 标志指定它是哪种类型的设备、存在的轴以及应如何解释它们。 大多数标志在 Mmddk.h 中定义。 DirectX 3.0 中添加的两个新标志在 Dinput.h 中定义。 以下标志仅用于重新映射由 VJoyD 直接轮询的 OEM 定义的模拟游戏杆的轴。 在执行模 拟轮询时,它们会更改 VJoyD 的默认行为,但对微型驱动程序返回的数据没有影响。 标志 描述 JOY_HWS_XISJ1Y X 位于 J1 Y 轴上。 JOY_HWS_XISJ2X X 位于 J2 X 轴上。 JOY_HWS_XISJ2Y X 位于 J2 Y 轴上。 JOY_HWS_YISJ1X Y 位于 J1 X 轴上。 JOY_HWS_YISJ2X Y 位于 J2 X 轴上。 JOY_HWS_YISJ2Y Y 位于 J2 Y 轴上。 JOY_HWS_RISJ1X R 位于 J1 X 轴上。 JOY_HWS_RISJ1Y R 位于 J1 Y 轴上。 JOY_HWS_RISJ2Y R 位于 J2 Y 轴上。 JOY_HWS_ZISJ1X Z 位于 J1 X 轴上。 JOY_HWS_ZISJ1Y Z 位于 J1 Y 轴上。 JOY_HWS_ZISJ2X Z 位于 J2 X 轴上。 JOY_HWS_POVISJ1X 轮询 POV 位于 J1 X 轴上。 JOY_HWS_POVISJ1Y 轮询 POV 位于 J1 Y 轴上。 JOY_HWS_POVISJ2X 轮询 POV 位于 J2 X 轴上。 默认行为是: X 默认为 J1 X 轴。 Y 默认为 J1 Y 轴。 R (方向) 默认为 J2 X 轴。 Z 默认为 J2 Y 轴。 POV 帽子 (如果实现为轮询) 默认为 J2 Y 轴。 还定义了标志,以确定 POV 数据是来自轴还是来自按钮组合。 如果所述设备由 VJoyD 轮 询,JOY_HWS_POVISBUTTONCOMBOS会导致 VJoyD 解释按钮组合以生成 POV,否则使 用轴来查找它。 如果通过微型驱动程序轮询所述设备,则 dwPOV 中除POV_UNDEFINED 以外的值会导致替代任何其他 POV 计算。 但是,如果设置了 JOY_HWS_POVISBUTTONCOMBOS,VJoyD 将像解释模拟游戏杆一样解释按钮。 否则, 如果未设置JOY_HWS_HASZ,则从 Z 轴值获取 POV,否则从 R 获取 POV。 如果可能, 微型驱动程序应避免让通用 VJoyD 解释 POV 信息,因为微型驱动程序通常具有有关硬件 实现的详细信息。 以下标志用于描述设备具有的功能: 标志 描述 JOY_HWS_HASZ 游戏杆具有 Z (第三轴) 信息。 JOY_HWS_HASR 游戏杆具有 R (四轴) 信息。 JOY_HWS_HASU 游戏杆具有 R (四轴) 信息。 JOY_HWS_HASV 游戏杆具有 R (四轴) 信息。 JOY_HWS_HASPOV 游戏杆有一顶 POV 帽子。 以下标志用于描述设备类型: 标志 设备类型 JOY_HWS_ISYOKE 飞行Yoke JOY_HWS_ISGAMEPAD 游戏板 JOY_HWS_ISCARCTRL 赛车控制器 JOY_HWS_ISHEADTRACKER (DirectX 3.0) 中定义的头部跟踪器。 最后,DirectX 3.0 中添加的 JOY_HWS_ISGAMEPORTDRIVER 标志指示此微型驱动程序取 代了游戏端口的标准轮询。 例如,如果数字游戏杆具有八个按钮,并返回 X、Y、Z、R 和 POV 的值,则需要设置位 JOY_HWS_HASZ、JOY_HWS_HASPOV和JOY_HWS_HASR。 这会提供以下内容: 0x00000001 JOY_HWS_HASZ 01,00,00,00 | 0x00000002 JOY_HWS_HASPOV 02,00,00,00 | 0x00080000 JOY_HWS_HASR 00,00,08,00 = 0x00080003 组合 03,00,08,00 将此 DWORD 设置为 little-endian 格式,后跟按钮数的 DWORD ,将为你提供 03,00, 08,00,00,00,00,00,00,00,这是 INF 文件中所需的一系列字节。 INF 文件中提供的所有剩余注册表设置都自定义标准控制面板提供的校准说明,如下所 示: 注册表设置 说明 REGSTR_VAL_JOYOEMXYLABEL 此字符串显示在游戏杆 CPL 的测试和校准对话框中的 XY 位置控件下方。 REGSTR_VAL_JOYOEMZLABEL 此字符串显示在游戏杆 CPL 的测试和校准对话框中的 Z 位置控件下方。 REGSTR_VAL_JOYOEMRLABEL 此字符串显示在游戏杆 CPL 的测试和校准对话框中的 R 位置控件下方。 REGSTR_VAL_JOYOEMPOVLABEL 此字符串显示在游戏杆 CPL 的测试和校准对话中找到 的 POV 帽子控件下方。 REGSTR_VAL_JOYOEMULABEL 此字符串显示在游戏杆 CPL 的测试和校准对话框中的 U 位置控件下方。 REGSTR_VAL_JOYOEMVLABEL 此字符串显示在游戏杆 CPL 的测试和校准对话中找到 的 V 位置控件下方。 REGSTR_VAL_JOYOEMTESTMOVEDESC 此字符串显示在测试对话框的移动部分中。 它向用户 介绍如何测试游戏杆。 REGSTR_VAL_JOYOEMTESTBUTTONDESC 此字符串显示在测试对话框的按钮部分中。 它向用户 介绍如何测试按钮。 REGSTR_VAL_JOYOEMTESTMOVECAP 此字符串显示为测试对话框移动部分周围的分组框的描 述文字。 REGSTR_VAL_JOYOEMTESTBUTTONCAP 此字符串显示为测试对话框按钮部分周围分组框的描述 文字。 REGSTR_VAL_JOYOEMTESTWINCAP 此字符串显示为测试对话框的描述文字。 REGSTR_VAL_JOYOEMCALCAP 此字符串将显示为校准对话框的描述文字。 注册表设置 说明 REGSTR_VAL_JOYOEMCALWINCAP 此字符串显示为校准对话框的描述文字。 REGSTR_VAL_JOYOEMCAL1 此字符串指示用户如何使游戏杆的 XY 部分居中进行校 准。 REGSTR_VAL_JOYOEMCAL2 此字符串指示用户如何移动游戏杆的 XY 部分进行校 准。 REGSTR_VAL_JOYOEMCAL3 此字符串指示用户如何更新游戏杆的 XY 部分进行校 准。 REGSTR_VAL_JOYOEMCAL4 此字符串指示用户如何移动游戏杆的 Z 部分进行校准。 REGSTR_VAL_JOYOEMCAL5 此字符串指示用户如何移动游戏杆的 R 部分进行校 准。 REGSTR_VAL_JOYOEMCAL6 此字符串指示用户如何移动游戏杆的 U 部分进行校 准。 REGSTR_VAL_JOYOEMCAL7 此字符串指示用户如何移动游戏杆的 V 部分进行校 准。 REGSTR_VAL_JOYOEMCAL8 此字符串指示用户如何向上移动 POV 帽子进行校准。 REGSTR_VAL_JOYOEMCAL9 此字符串指示用户如何向右移动 POV 帽子进行校准。 REGSTR_VAL_JOYOEMCAL10 此字符串指示用户如何向下移动 POV 帽进行校准。 REGSTR_VAL_JOYOEMCAL11 此字符串指示用户如何移动 POV 帽左移进行校准。 REGSTR_VAL_JOYOEMCAL12 此字符串包含一条消息,告知用户校准过程已完成。 注册表设置 项目 • 2023/06/15 游戏杆接口使用注册表来存储配置、校准和用户首选项信息。 它还用于存储校准程序的 自定义文本。 Windows 95/98/Me 游戏杆校准程序可以通过注册表进行自定义,以在校 准期间向用户提供特定于游戏杆的说明。 这些值分为五组: OEM 提供的原始数据,并从上述 INF 文件 (安装的原始数据) 。 当前注册表设置有两个部分:要存储的值(标准轮询的替代项),以及存储功能、校准值 和微型驱动程序数据的键。 可在名为 REGSTR_VAL_JOYCALLOUT 的键中定义用于轮询没有关联微型驱动程序来替换 标准轮询的微型驱动程序。 此功能是 DirectX 3.0 的新增功能。 当用户从包含已设置 JOY_HWS_ISGAMEPORTDRIVER标志的所有微型驱动程序的列表中选择新的全局驱动程序 时,控制面板设置这些值。 其余设置存储在REGSTR_KEY_JOYCURR键下。 当设备首次配置为特定游戏杆 ID 时,控制 面板将值从REGSTR_PATH_JOYOEM下的相关 OEM 密钥复制到REGSTR_KEY_JOYCURR 键。 此键下的每个键值名称都包含游戏杆 ID 作为名称的一部分,因此每个游戏杆都有自 己的设置。 REGSTR_VAL_JOYOEMNAME值将复制到相关 REGSTR_VAL_JOYNOEMNAME,如果存在,则会将REGSTR_VAL_JOYOEMCALLOUT值复 制到REGSTR_VAL_JOYNOEMCALLOUT。 REGSTR_VAL_JOYOEMDATA值用作 REGSTR_VAL_JOYNCONFIG值的前两个双字,当展开) 时,该值的整个定义 (,如下所 示: C++ 用户值 struct { /* usage settings, copied from REGSTR_VAL_JOYOEMNAME */ struct { DWORD dwFlags; DWORD dwNumButtons; } hws; /* usage flags, described below */ DWORD dwUsageSettings; struct { /* values returned by hardware during calibration */ 使用设置是以下值的组合: 设置 值 说明 JOY_US_HASRUDDER 0x00000001 配置有舵的操纵杆 JOY_US_PRESENT 0x00000002 游戏杆是否确实存在? struct { /* minimums for each axis */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpMin; /* maximums for each axis */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpMax; /* center positions for each axis */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpCenter; } jrvHardware; /* POV values returned by hardware during calibration */ DWORD dwPOVValues[JOY_POV_NUMDIRS]; /* calibration flags, described below */ DWORD dwCalFlags; } hwv; /* type of joystick, described below */ DWORD dwType; /* reserved for OEM drivers */ DWORD dwReserved; }; 设置 值 说明 JOY_US_ISOEM 0x00000004 游戏杆是 OEM 定义的类型 JOY_US_RESERVED 0x80000000 预留 校准标志是以下值的组合: 标志 值 说明 JOY_ISCAL_XY 0x00000001 XY 已校准 JOY_ISCAL_Z 0x00000002 Z 已校准 JOY_ISCAL_R 0x00000004 R 已校准 JOY_ISCAL_U 0x00000008 U 已校准 JOY_ISCAL_V 0x00000010 V 已校准 JOY_ISCAL_POV 0x00000020 POV 已校准 dwType 成员包含一个数字,表示预定义游戏杆的类型。 如果 OEM 校准实用工具设置了 此值,它应设置一个超出 Mmddk.h 中定义的值范围的值。 确切的值并不重要,因为它 由标准控制面板重置。 这些注册表设置是在从 INF 文件安装期间设置的,如 创建 INF 文件中所述,以及在启动 时的设备枚举期间设置的。 保存当前游戏杆设置时,保存在REGSTR_KEY_JOYCURR键下的REGSTR_VAL_JOYNCONFIG 也会写入子项中的REGSTR_KEY_JOYSETTINGS键下,其名称与从中获取 OEM 定义的设置 的名称相同, (非 OEM 设置保存在子项“predef”中以及类型号) 中。 更换游戏杆时,保存 的设置将保留,这样,如果游戏杆恢复,保存的设置将放回当前设置中。 这些注册表值 仅由控制面板使用。 名为 REGSTR_VAL_JOYUSERVALUES 的单个值存储下面所述的结构。 此结构指定当应用 程序请求缩放、居中或定义死区时,VJoyD 应如何处理数据。 当前设置 保存的设置 驱动程序设置 C++ 用户值、当前设置和保存的设置都存储在注册表中属于“当前”游戏杆驱动程序的路径下。 安装有驱动程序的每个游戏杆设备的路径REGSTR_PATH_JOYCONFIG下都有一个键,其格 式为 Msjstick.drv,其中 xxxx 是用于保持密钥名称唯一的四位数。 该数字与已安 struct { /* value at which to time-out internal joystick polling */ DWORD dwTimeOut; /* range of values app wants returned for axes */ struct { /* minimums for each axis */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpMin; /* maximums for each axis */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpMax; /* center positions for each axis */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpCenter; } jrvRanges; /* area around center to be considered as "dead". specified as */ /* a percentage (0-100). Only X & Y handled by system driver */ struct { DWORD dwX; DWORD dwY; DWORD dwZ; DWORD dwR; DWORD dwU; DWORD dwV; } jpDeadZone; } 装的多媒体 (声音、视频和游戏控制器) 驱动程序的数量相关。 在启动时,Msjstick.drv 将 初始化为每个游戏控制器驱动程序的配置。 由于一次只能处理一个配置,因此每个配置 将替换最后一个,而“当前”驱动程序是最后一个要初始化的驱动程序。 这意味着,在安 装新驱动程序时,用户可能会丢失所有当前设置,并且无法基于这些注册表值的路径始终 相同的假设来构建微型驱动程序。 VJoyD 微型驱动程序替代 项目 • 2023/06/14 未加载 JoyHID.VxD 设备驱动程序的 USB/HID 设备有时可以在与其他 USB/HID 设备一起 使用时显示游戏选项控制面板中的重复设备条目。 当符合 JoyHID 的设备与非 JoyHID 设 备同时连接到系统时,会发生此情况。 如果你的设备使用除 JoyHID 以外的 VJoyD 微型驱动程序(大概由设备制造商或关联公司 开发)-你可以通过在注册表中正确设置设备类型键和相关命名值来防止这些问题。 本文 中所述的功能仅适用于类型键为“VID_vvvv&PID_pppp”形式的设备,其中字母 v 和 p 是产 品的零填充供应商和产品 ID 值。 给定格式正确的类型键后,以下步骤可防止 JoyHID 尝试从设备检索数据或在控制面板/ 添加列表中显示不必要的设备条目。 将 OEMData 设置为 JOY_HWS_AUTOLOAD。 这可以防止设备名称显示在设备的添 加列表中。 将 OEMCallout 设置为应为设备加载的驱动程序。 这可以防止为设备加载 JoyHID.VxD。 将 OEMName 设置为适合设备的名称。 如果需要,可以将注册表值设置为任意值,以防止 JoyHID 从设备读取数据。 例如,可以 使用以下值: 名称 值 OEMName “IHV 设备 X 的未使用条目,请勿删除” OEMData OEMData 是包含两个 DWORD 的二进制注册表字段。 第一个是一组JOY_HWS_* 标 志,第二个是设备上的按钮数。 标志JOY_HWS_AUTOLOAD的值在 dinput.h 中定 义,以0x10000000。 由于本例中的按钮数无关紧要,十六进制) 中 (八个字节应为 00,00,00,10,00,00,00,00。 OEMCallout “未使用” 此类值仅阻止 JoyHID 尝试从设备读取数据。 如果设备使用 VJoyD 微型驱动程序,则应 将上述值设置为正确反映设备名称和要加载的驱动程序。 轴选择 项目 • 2023/06/15 本部分包含有关 DirectInput 如何映射轴以供 DirectInput 和 Windows 多媒体应用程序使 用的信息。 在 Windows 2000 上使用 DirectX 7.0 API 时,轴分配按设备驱动程序公开轴的顺序进 行,如下表所示: 使用情况页 使用情况 DirectInput 轴 HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_X GUID_XAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_Y GUID_YAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_Z GUID_ZAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_WHEEL GUID_ZAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_RX GUID_RxAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_RY GUID_RyAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_RZ GUID_RzAxis HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_HATSWITCH GUID_POV HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_SLIDER GUID_Slider HID_USAGE_PAGE_GENERIC HID_USAGE_GENERIC_DIAL GUID_Slider HID_USAGE_PAGE_SIMULATION HID_USAGE_SIMULATION_STEERING GUID_XAxis HID_USAGE_PAGE_SIMULATION HID_USAGE_SIMULATION_ACCELERATOR GUID_YAxis HID_USAGE_PAGE_SIMULATION HID_USAGE_SIMULATION_BRAKE GUID_RzAxis HID_USAGE_PAGE_SIMULATION HID_USAGE_SIMULATION_RUDDER GUID_RzAxis HID_USAGE_PAGE_SIMULATION HID_USAGE_SIMULATION_THROTTLE GUID_Slider HID_USAGE_PAGE_GAME HID_USAGE_ SIMULATION_POV GUID_POV SetDataFormat 使用这些 GUID 将请求的数据格式与设备对象匹配。 对于使用小于 0x0600 DIRECTINPUT_VERSION 编译的应用程序,如果数据格式在GUID_Slider (之前指定 Windows 2000,旧版接口 一个GUID_ZAxis,因为默认游戏杆数据格式) 在 Z 轴之前在设备上找到滑块,则滑块将匹 配为 Z 轴。 这旨在更好地与 HID 兼容。 通过 Windows 95/98/Me 上的 DirectX 7.0 接口,WinMM 轴到 DirectInput 轴的映射是一 维的: WinMM 轴 DirectInput 分配 X GUID_XAxis Y GUID_YAxis Z GUID_ZAxis R GUID_RzAxis U GUID_Slider V GUID_Slider WinMM 轴通过 DirectX 8.0 接口以不同的方式映射,如下所述。 DirectX 8.0 接口创建的映射不同于旧接口进行的映射。 下表介绍了 DirectX 8.0 接口中的 映射。 对于通过 WinMM 检索的数据,默认映射为: WinMM 轴 DirectInput 分配 X GUID_XAxis Y GUID_YAxis Z GUID_Slider R GUID_RzAxis Windows 9x 平台 7 备注 尽管 JoyHID.VxD 尚未映射转向、加速和制动的车辆控制用法,但它对转向使用检 查,如果找到一个,它会将设备视为 WinMM 汽车控制器。 此外,DirectX 8.0 版本 的 JoyHID.VxD 复制任何 IHV 提供的 WinMM 控制器类型标志 (JOY_HWS_ISYOKE、 JOY_HWS_ISGAMEPAD、JOY_HWS_ISCARCTRL或JOY_HWS_ISHEADTRACKER) 和按 钮计数,因此这些类型可由 OEMData 注册表值的 IHV 设置。 WinMM 轴 DirectInput 分配 U GUID_Slider V GUID_Slider 由于游戏设备上的第三个轴很少是 Z 轴,因此这些映射有助于更好地与 Windows 2000、 Windows XP 和 Windows 95/98/Me HID 兼容。 强制反馈设备驱动程序接口 项目 • 2023/06/15 本部分介绍 DirectInput 与特定于设备的力量反馈驱动程序之间的接口。 新的游戏杆注册表项位于特定于 OEM 的密钥下,该键安装在注册表项下,注册表路径 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\MediaProperties\PrivateP roperties\Joystick\OEM。 首次安装设备时,将初始化存储在此特定于 OEM 的密钥下的 数据,然后仅用于参考目的。 除了为现有游戏杆设备定义的值外,还定义了两个新的可 选泛型值和一组力回馈特定值。 这两个泛型值是包含版本信息的二进制值和 regstr.h 中 (REGSTR_VAL_MANUFACTURER的 制造商 字符串值,) 包含制造商名称的字符串。 后者是对保存设备名称的现有 OEMName 值的补充。 已定义一个新的 OEMForceFeedback 密钥,用于保存强制反馈特定的键和值。 此键下是 一个效果 子项,其中包含每个效果的两个值。 在 “效果” 子项下是子项列表,每个效果各有一个。 每个子项的名称都是一个全局唯一标 识符, (GUID) 格式为“”。{12345678-1234-1234-1234-123456789012} 在名为“{...}”的键下 面有两个值。 默认值是效果的字符串友好名称。 Attributes 值为 DIEFFECTATTRIBUTES 结构。 C++ OEMForceFeedback 键还包括一个值,该值包含设备属性和两个可选值之一。 在可选值 中,如果使用环 3 驱动程序 (DLL) ,请使用 CLSID ;如果使用环 0 驱动程序 (VxD) ,请使 用 VJoyD 。 C++ OEMForceFeedback 注册表设置 "{guid1}" Default value = friendly name for effect {guid1} (string) "Attributes" = DIEFFECTATTRIBUTES structure (binary) "{guid2}" Default value = friendly name for effect {guid2} (string) "Attributes" = DIEFFECTATTRIBUTES structure (binary) "Attributes" = DIFFDEVICEATTRIBUTES structure (binary) "CLSID" = {GUID} for force feedback effect driver (string)(optional) "VJoyD" = zero-length binary (optional) 可选值的名称指示使用哪种形式的接口。 如果 CLSID 值存在,则它应该是一个字符串 值,其中包含提供驱动程序接口的 COM 对象“”形式的{12345678-1234-1234-1234- 123456789012} GUID。 如果 存在 VJoyD 值,则它应该是一个零长度的二进制值,该值 指示与要使用的设备关联的 VJoyD 微型驱动程序应为驱动程序接口提供额外的回调。 添 加一个值,指示人机接口设备 (HID) 实现时提供驱动程序接口。 如果设备支持的硬件效果不属于 (DIEFT_CONSTANTFORCE、DIEFT_RAMPFORCE、 DIEFT_PERIODIC、DIEFT_CONDITION或DIEFT_CUSTOMFORCE) 的任何预定义类别,则效 果的 DIEFFECTATTRIBUTES 结构应将DIEFT_HARDWARE指定为效果类型。 设备可以支持属于上一段) 中列出的预定义类别 (硬件效果,还可以接收不属于 DICONSTANTFORCE、DIRAMPFORCE、DIPERIODIC、DICONDITION 或 DICUSTOMFORCE) 标准类型特定数据 (结构一部分的其他参数。 有关这些结构的信息, 请参阅 DirectX 软件开发工具包 (SDK) 的 DirectInput 部分。 在这些情况下,效果应按如 下所示列出两次: 在预定义类别下列出效果。 如果应用程序在预定义类别中创建效果,则驱动程序应 为不属于标准类型特定数据结构的指定参数提供合适的默认值。 在“DIEFT_HARDWARE”类别下列出效果。 创建包含额外参数的特定于类型的特殊结 构 (,例如 DIPERIODICFORCEWITHDECAY) 。 这样,为硬件设计的应用程序可以使用第二个效果描述符来访问效果的全部功能,而为通 用硬件设计的应用程序可以使用第一个效果描述符来访问效果的基本功能。 如果力回馈驱动程序是基于 COM 的,则 DirectInput 会创建驱动程序的实例。 如果指定 的接口为“VJoyD”,则 VJoyD 将加载 VJoyD 微型驱动程序。 这两个驱动程序路径都支持 以下导出的方法: DestroyEffect 初始化 DownloadEffect GetEffectStatus GetForceFeedbackState 逃脱 SendForceFeedbackCommand 驱动程序接口 SetGain StartEffect StopEffect 所有力回馈设备都支持此功能。 DirectInput 通过创建 CLSID 命名的对象来创建力回馈效果驱动程序的实例,该对象存储 在游戏杆类型子项的 OEMForceFeedback 注册表子项中。 由于使用 DirectInput 的应用程序不需要加载 OLE,因此效果驱动程序应小心不要依赖于 特定于 OLE 的行为。 例如,不能依赖使用 DirectInput 的应用程序来调用 CoFreeUnusedLibraries 方法。 DirectInput 执行标准 COM 操作以创建效果驱动程序对象 的实例。 下面介绍了此唯一应该对效果驱动程序实现的可见影响。 DirectInput 释放最后一个效果驱动程序对象后,它会手动执行效果驱动程序 DLL 的 FreeLibrary。 因此,如果效果驱动程序 DLL 创建与效果驱动程序对象无关的其他资源, 它应手动加载库本身以人为地增加其 DLL 引用计数,从而防止 DirectInput 中的 FreeLibrary 过早卸载 DLL。 具体而言,如果效果驱动程序 DLL 创建工作线程,则只要工作线程存在,效果驱动程序 就必须执行此人工 LoadLibrary 操作。 例如,当不再需要工作线程 (时,在上一个效果驱 动程序对象) 被销毁时发出通知时,工作线程应调用 FreeLibraryAndExitThread 方法来递 减 DLL 引用计数并终止线程。 DirectInput 使用的所有数量级和增益值在整个范围内都是统一的线性值。 物理设备中的 任何非线性必须由设备驱动程序处理,以便应用程序看到线性设备。 由 IDirectInputEffectDriver接口公开的用户模式力回馈函数必须由力回馈效果驱动程序 DLL 实现。 有关这些函数的详细信息,请参阅 IDirectInputEffectDriver。 User-Mode函数 扩展 DirectInput 游戏控制器控制面板 项目 • 2023/06/15 本主题介绍如何为 Microsoft DirectInput 游戏控制器控制面板创建属性表。 DirectInput 支持游戏控制器,例如游戏板、游戏杆和力回馈设备。 在 Microsoft DirectX 5.0 及更高版本中,DirectInput 提供了名为 joy.cpl的新游戏控制器控制面板。 控制面板允 许扩展性,其中为每个控制器显示的属性表可以替换为特定于该控制器的属性页。 这是 通过创建包含有关这些属性表信息的 DLL 来完成的。 此 DLL 公开由 DirectInput 控制面 板调用的 COM 接口。 建议游戏控制器硬件供应商使用此扩展性功能为其游戏控制器提供自定义属性表,而不是 创建单独的控制面板。 这允许用户打开单个控制面板来配置和测试其游戏控制器。 本部分介绍 DirectInput 控制面板可扩展属性表的基本结构。 DirectInput 控制面板的基本体系结构包括 DirectInput 游戏控制器控制面板、支持 IDIGameCntrlPropSheet COM 接口的抽象层库以及每个游戏控制器属性表的 COM 对 象。 DirectInput 控制面板直接与 DirectInput 配合使用,而 DirectInput 则直接使用设备驱动 程序。 作为其副产品,即使应用程序位于后台,DirectInput 控制面板也有权访问输入设 备。 关于 DirectInput 控制面板 DirectInput 控制面板体系结构 游戏控制器控制面板 7 备注 “object”一词描述 CreateInstance 为支持 COM 接口的方法而创建的实体,即使这些 方法不是通过面向对象的编程语言(如 C++)调用的。 单词“sheet”描述页面插入到 的对话框。 “页面”一词描述“属性表”对话框的内容对话框。 默认模拟设备属性表 未创建自己的控制面板的硬件供应商使用 Gcdef.dll 提供的默认模拟设备属性表的服务。 注册表中在其 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\MediaProperties\PrivateP roperties\Joystick\OEM\<> CONTROLLER_NAME项下没有 ConfigCLSID 键的任何控制 器都使用此默认属性表。 此属性表包含以下两页: 测试: 本页演示设备正确响应。 它返回与设备属性关联的注册表设置的图形表示形 式,并允许用户查看它们。 设置: 此页允许用户将有关设备的特定信息写入系统。 提供校准和舵或踏板服务。 由于属性表页是 COM 对象,因此它必须注册到 Windows。 这可以通过 INF 文件或通过 DirectInput 的 IDirectInputJoyConfig8 接口完成。 示例 INF 文件是 DirectX 驱动程序开 发工具包 (DDK) 中示例属性表的一部分。 注册属性表页: 1. 使用Microsoft Windows SDK) 中包含的 GuidGen 工具 (为属性表创建 CLSID, (这与 前面) 提到的 ConfigCLSID 条目中输入的 CLSID 相同。 请记住,这是特定于设备的 属性表 GUID,它应与代码中的 GUID 相同。 2. 使用此新 GUID 在 注册表中的“我的Computer\HKEY_CLASSES_ROOT\CLSID ”下创 建新密钥。 它应类似于 {B9EA2BE1-E8E9-11D0-9880-00AA0044480F}。 3. 在该键内,创建名为 InProcHandler32 和 InProcServer32 的子项。 4. 在 InProcServer32 键中,编辑默认条目以反映属性表 DLL 的位置和名称。 你的设备还必须正确注册为游戏设备。 这可以通过 DirectInput 或 INF 文件完成。 注册设备: 1. 在注册表项 “我的 Computer\HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\MediaPro perties\PrivateProperties\Joystick\OEM”中,输入设备的密钥。 使此密钥名称与设 备 OEM 名称相同。 2. 创建以下条目: 键值 键值类型 键值类型内容 ConfigCLSID “字符串值” “{your 属性表 CLSID}” 与 Windows 集成 键值 键值类型 键值类型内容 OEMName “字符串值” “设备的产品名称” 本部分介绍 DirectInput 控制面板的概念和组件,并提供信息来帮助你开始实现自己的特 定于设备的属性表。 你将需要 Windows 软件开发工具包 (SDK) 。 dinputd.h 头文件提供必要的接口、结构、 类定义和错误。 使用 DirectInput 的 IDirectInputJoyConfig8 接口进行所有注册表访问。 如果计划在属性页中使用 DirectInput,则还必须使用关联的 Windows SDK 文件。 DirectInput 控制面板中的所有结构都打包在 8 字节边界上。 验证属性表是否将结构打包 在 8 字节边界上。 此示例演示 DirectInput 的许多方面,并为你自己的自定义属性表提供了一个很好的起 点。 从头开始创建自定义属性表的过程相对简单。 1. 创建 GUID 以标识属性页: 7 备注 这两个条目是入门所需的最低要求。 有关所有可用条目及其关联服务的其他信 息,请参阅 Windows SDK。 DirectInput 控制面板基本信息 文件和生成环境 7 备注 测试控制面板时,请确保在主显示器设置为 640 x 480 像素分辨率的系统上对其进行 测试。 确保所有控件在此减少的分辨率下仍然可见。 创建属性表 创建自己的属性表 使用 Windows SDK) 中包含的 GuidGen 工具 (,无论) 多少页,都仅为属性页 创建一个 GUID (一个。 在特定于应用程序的包含文件中定义此内容。 创建所需的 DllGetClassObject 和 DllCanUnloadNow。 为 dinputd.h 中定义的 COM ClassFactory 创建实现。 创建 IDIGameCntrlPropSheet 接口的实现。 使用 RegEdit,将定义的 GUID 添加到 “我的 Computer\HKEY_CLASSES_ROOT\CLSID ”密钥。 然后将密钥 InProcHandler32 和 InProcServer32 添加到密钥。 修改 inProcServer32 条目 (默认) 条目,使其指向属性表 DLL 的位置。 例如: “C:\my_device\my_propertysheet.dll”。 此示例显示了一个 ProgID 条目。 这 不是必需的,但通常用于存储驻留在该 GUID 上的模块的相关信息。 2. 像创建任何 Windows 应用程序一样创建对话框模板和对话过程。 3. 填充 DIGCPAGEINFO 和 DIGCSHEETINFO 结构,并在 IDIGameCntrlPropSheet::GetPageInfo 和 IDIGameCntrlPropSheet:: GetSheetInfo 的实现中分别返回该信息。 属性表页的生成是通过 PropertySheet 函数完成的。 此函数的所有行为都是属性表页中 固有的。 例如,属性表页反映它接收的最大对话模板。 如果用户创建一个页面,并且其 关联的模板非常小,则这直接反映在生成的对话框的大小上。 在考虑视觉对齐和页面上控件居中时,对话框模板也很重要。 例如,假设用户创建两个 页面,其中包含指定在页面上居中的项目。 一个要居中的项目是 200 个对话框单位, (dll) 宽度;另一个是 100 个单位。 在这种情况下,后一项不在页面上居中。 相反,控件将 居中到其模板,并且额外的空白 (或灰色,因为它可能会) 添加到更窄的页面的宽度。 即 使未全部使用,也应创建相同大小的对话框模板。 (有关 PropertySheet 函数的详细信 息,请参阅 Windows SDK.) 在测试属性表页期间,运行 DirectInput 和 DirectInput 控制面板的调试版本。 DirectX 组 件旨在向调试窗口/终端发出有用的错误和警告消息。 调试控制面板应用程序可能很棘手。 使用以下步骤调试 Microsoft Developer Studio 5.0 和更新版本中的自定义属性表页, (其他编译器的行为) 相似。 7 备注 你可能希望将属性表的测试容器编写为窗口,该窗口将页面作为独立对话框启 动。 此时,还可以将可能拥有的任何现有控制面板转换为 DirectInput 控制面 板。 测试属性表 1. 在“项目”菜单中,选择“设置”。 2. 选择“调试”选项卡。 3. 对于调试会话的可执行文件,请输入 C:\WINDOWS\SYSTEM32\RUNDLL32.EXE,假 设 C:\WINDOWS 是 Windows 目录。 4. 对于程序参数,请输入 shell32.dll,Control_RunDLL c:\windows\system32\joy.cpl。 同样,这假定 C:\WINDOWS 是你的 Windows 目 录。 参数区分大小写,必须完全按所示输入。 5. 设置您的断点。 6. 在生成菜单中,依次选择“ 开始调试”、“ 转到”。 现在可以调试自定义属性表页。 DirectInput Kernel-Mode 服务宏 项目 • 2023/06/15 DirectInput 提供一组宏,其中包含内核模式服务的入口点。 这些入口点是: Microsoft 服务 VJOYD_Register_Device_Driver。 有关此服务宏的信息,请参阅 DirectX 5.0 接口。 VJOYD_GetPosEx_Service VJOYD_GetPosEx_Service宏允许内核模式组件获取游戏杆数据,从而绕过 WinMM。 C++ 进入: eax = 指向 JOYINFOEX 的指针 ebx = 游戏杆 ID 退出: eax = 游戏杆返回代码 DirectInput 服务 VJOYD_GetInitParams_Service。 在 DirectX 5.0 及更高版本中, 初始化 回调会向驱动程 序发出有关设备标识的信号。 此回调替换游戏杆标识回调 (请参阅 DirectX 早期版本中使 用的 游戏杆标识回调 。 C++ VJOYDAPI_GetPosEx_Service, SERVICE /* Parameters dwDeviceID Indicates the joystick ID number being used. The Windows joystick subsystem allocates external IDs. lpInitParams Points to a DID_INITPARAMS structure that contains the initialization parameters. Return value When access is being started, returns S_OK on success; otherwise returns an VJOYD_Poll_Service。 请参阅 轮询回调。 C++ error value if the driver cannot service this ID. The result is ignored if access is being stopped. */ HRESULT Initialize( DWORD dwDeviceID, LPDID_INITPARAMS lpInitParams ); /* Parameters dwDeviceID Indicates the joystick ID number being used. lpdwMask Points to a DWORD mask that describes the data requested on entry, and the data returned on exit. The mask is a combination of the following: JOYPD_X Bitmask for the dwX member of the VJPOLLDATA structure. JOYPD_Y Bitmask for the dwY member of the VJPOLLDATA structure. JOYPD_Z Bitmask for the dwZ member of the VJPOLLDATA structure. JOYPD_R Bitmask for the dwR member of the VJPOLLDATA structure. JOYPD_U Bitmask for the dwU member of the VJPOLLDATA structure. JOYPD_V Bitmask for the dwV member of the VJPOLLDATA structure. JOYPD_POV0 Bitmask for the dwPOV0 member of the VJPOLLDATA structure. JOYPD_POV1 Bitmask for the dwPOV1 member of the VJPOLLDATA structure. JOYPD_POV2 Bitmask for the dwPOV2 member of the VJPOLLDATA structure. JOYPD_POV3 Bitmask for the dwPOV3 member of the VJPOLLDATA structure. JOYPD_BTN0 lpdwMask 参数的上下字分别处理。 下部单词是 VJPOLLDATA 结构中元素的简单位掩 码。 上半部分描述请求这些元素的属性。 轮询的 lpPollData 参数包含的 VJPOLLDATA 结 构的数组至少与掩码的上一字中设置的位相同。 Bitmask for the dwBTN0 member of the VJPOLLDATA structure. JOYPD_BTN1 Bitmask for the dwBTN1 member of the VJPOLLDATA structure. JOYPD_BTN2 Bitmask for the dwBTN2 member of the VJPOLLDATA structure. JOYPD_BTN3 Bitmask for the dwBTN3 member of the VJPOLLDATA structure. JOYPD_RESERVED0 Bitmask for the dwReserved0 member of the VJPOLLDATA structure. JOYPD_RESERVED1 Bitmask for the dwReserved1 member of the VJPOLLDATA structure. JOYPD_ELEMENT_MASK Bitmask for all members of the VJPOLLDATA structure. JOYPD_POSITION Bitmask for the position attribute of the device. JOYPD_VELOCITY Bitmask for the velocity attribute of the device. JOYPD_ACCELERATION Bitmask for the acceleration attribute of the device. JOYPD_FORCE Bitmask for the force attribute of the device. JOYPD_ATTRIB_MASK Bitmask for all possible attributes of the device. lpPollData Points to the polling data. Return value Returns S_OK if the poll was completed successfully; returns S_FALSE if returned data is (partially or wholly) out of date; otherwise, returns an error code. */ HRESULT Poll( DWORD dwDeviceID, LPDWORD lpdwMask, LPVJPOLLDATA lpPollData ); 第一个 VJPOLLDATA 结构应包含位置信息。 接下来的三个 VJPOLLDATA 结构应按此顺序 包含有关加速度、速度和力的信息。 例如,如果设备仅支持位置和力,则第一个结构包 含位置数据,第二个和第三个结构为空,因此跳过,第四个结构包含力信息。 微型驱动程序应始终将掩码设置为它可以返回的内容,即使轮询因设备拔下电源而失败也 是如此。 因此,如果设备只有不到 33 个按钮、X、Y 和 R(仅位置),则应在搜索可用 数据之前执行以下操作: *pdwMask &= ( JOYPD_POSITION | JOYPD_BTN0 | JOYPD_X | JOYPD_Y | JOYPD_R ); 如果设备可以返回多个属性的数据,则上一个单词为每个属性设置了一个位,而下层单词 应为可为任何受支持的属性返回的任何元素设置位。 因此,尽管 force 是单位) 按钮掩码 (不太可能的值,但如果设备报告位置数据中的按钮并针对 X 和 Y 报告强制,则位置、 力、X、Y 和按钮都应设置其位。 设备服务 VJOYD_Escape_Service。 请参阅 IDirectInputEffectDriver::Escape。 VJOYD_CtrlMsg_Service。 CtrlMsg 回调将特定消息发送到微型驱动程序。 C++ /* Parameters dwDeviceID Indicates the joystick ID number being used. dwMsgId Indicates the message being sent to the minidriver. A value of VJCM_PASSDRIVERDATA indicates that the dwParam parameter contains a DWORD to pass to the driver. A value of VJCM_CONFIGCHANGED indicates that the dwParam parameter informs the minidriver of a change in configuration. dwParam Specifies one of the following: If the dwMsgId parameter is set to VJCM_PASSDRIVERDATA, this parameter contains a DWORD to pass to the driver. This allows the JOY_OEMPOLL_PASSDRIVERDATA poll type that was used to pass driver data to a DirectX 3.0 driver to still be used for a driver designed for DirectX 5.0 and later versions. If the dwMsgId parameter is set to VJCM_CONFIGCHANGED, this parameter contains a pointer to a VJCFGCHG structure that informs the minidriver of a change in configuration. Return value Returns S_OK if successful, otherwise returns S_FALSE. 力回馈设备服务 VJOYD_DestroyEffect_Service。 请参阅 IDirectInputEffectDriver::D estroyEffect。 VJOYD_DownloadEffect_Service。 请参阅 IDirectInputEffectDriver::D ownloadEffect。 VJOYD_GetEffectStatus_Service。 请参阅 IDirectInputEffectDriver::GetEffectStatus。 VJOYD_GetFFState_Service。 请参阅 IDirectInputEffectDriver:: GetForceFeedbackState。 VJOYD_SendFFCommand_Service。 请参阅 IDirectInputEffectDriver:: SendForceFeedbackCommand。 VJOYD_SetGain_Service。 请参阅 IDirectInputEffectDriver::SetGain。 VJOYD_StartEffect_Service。 请参阅 IDirectInputEffectDriver::StartEffect。 VJOYD_StopEffect_Service。 请参阅 IDirectInputEffectDriver::StopEffect。 中断轮询服务 VJOYD_DeviceUpdateNotify_Service 从其设备接收异步更新的微型驱动程序应调用 VJOYD_DeviceUpdateNotify_Service,以 通知 DirectInput 新数据可用。 如果应用程序已从此设备请求数据,DirectInput 将通过发 出轮询来响应以检索数据。 如果没有应用程序从此设备请求数据,或者如果应用程序未 使用 DirectInput (则改用 WinMM 函数) 此服务不执行任何操作。 屏幕保护程序服务 VJOYD_JoystickActivity_Service VJOYD_JoystickActivity_Service宏在内部调用,以允许 DirectInput 接收有关通过 WinMM 函数报告的游戏杆活动的信息。 此信息应阻止激活屏幕保护程序。 此宏不应由 微型驱动程序调用,并且将来的版本可能不支持此宏。 注册表访问服务 */ HRESULT CtrlMsg( DWORD dwDeviceID, DWORD dwMsgId, DWORD dwParam ); 游戏杆驱动程序使用VJOYD_OpenConfigKey_Service宏打开配置键。 这应镜像 IDirectInputJoyConfig8::OpenConfigKey 方法。 VJOYD_OpenConfigKey_Service, SERVICE 进入: eax = 要打开的密钥的 ID ecx = 要在其中存储密钥的 DWORD 的地址 退出: eax = 与 _RegOpenKey 相同,只不过,如果 VJoyD 尚未建立当前配置键,则返回 ERROR_CANTOPEN。 VJOYD_OpenConfigKey_Service 游戏杆驱动程序使用VJOYD_OpenTypeKey_Service宏打开类型键。 它应镜像 IDirectInputJoyConfig8::OpenTypeKey 方法。 VJOYD_OpenTypeKey_Service, SERVICE 进入: eax = 指向类型名称的指针 ecx = 指向存储密钥的 DWORD 的指针 退出: eax = 与 _RegOpenKey 相同 7 备注 如果需要打开注册表项,应使用 VJOYD_OpenConfigKey_Service 和 VJOYD_OpenTypeKey_Service 服务宏,而不是直接打开注册表项。 使用这些服务可 确保打开正确的注册表分支。 此外,如果基础注册表数据的结构可能不同,则未来 版本的 DirectInput 将支持服务宏。 DirectInput 消息 项目 • 2023/06/15 DirectInput 支持广播的新通知消息,以便在 DirectInput 应用程序开始使用 DirectInput 服务时发出通知。 这些通知可用于检测最近启动的、使用 DirectInput 的应用程序以及这 些应用程序如何使用 DirectInput 的功能。 应用程序可以通过调用 Win32 函数 RegisterWindowMessage 并传递 Dinputd.h) 中定义的 DIRECTINPUT_NOTIFICATION_MSGSTRING (来注册通知。 与对 RegisterNotificationMessageString 的任何其他调用一样,函数返回的 UINT 值是已 注册的应用程序在其窗口进程中应挂钩的消息值。 收到消息后,消息的 wParam 参数将 描述要发送的通知的类型。 wParam 的值是以下常量之一,在 Dinputd.h 中定义: DIMSGWP_NEWAPPSTART DirectInput 已由当前用户以前未使用过的应用程序初始化。 DIMSGWP_DX8APPSTART DirectInput 已由使用 DirectX 8.0 DirectInput 功能的应用程序初始化,但在当前用 户之前运行的任何 DirectInput 映射器上未使用 DirectInput 映射器函数。 DIMSGWP_DX8MAPPERAPPSTART DirectInput 已由使用 DirectX 8.0 中提供的 DirectInput 映射器函数的应用程序初始 化。 收到这些通知后,应用程序可以通过调用 IDirectInputJoyConfig8:: OpenAppStatusKey 方法查询其他信息。 DirectInput 应用程序访问消息 消息 (wParam) 注解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/950757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

遇到 Binder这些面试题,你会怎么答?

作为开发人员&#xff0c;每个人都有每个人擅长领域&#xff0c;自然也有自己不擅长的领域&#xff0c;很难成为完美的一个全栈开发。在面试中最怕遇见的一件事是面试官专挑你不擅长的领域进行提问&#xff0c;目的就是看你遇到问题的应变能力。 接下给大家分享一个面试中容易被…

CUDA小白 - NPP(3) 图像处理 Color and Sampling Conversion

cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化&#xff0c;具体的可以参考别的博主的介绍&#xff0c;都比较详细。还有一些cuda中的专有名词的含义&#xff0c;可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus&#xf…

标准库STL容器使用值语义

C自学精简实践教程 目录(必读) 标准库STL的容器都是值语义的。 即&#xff0c;无法将一个变量放到容器里。容器里存放的只是我们放进去的变量的拷贝&#xff08;副本&#xff09;。 示例&#xff1a; #include <iostream> #include <vector> using namespace s…

【Apollo学习笔记】——规划模块TASK之RULE_BASED_STOP_DECIDER

文章目录 前言RULE_BASED_STOP_DECIDER相关配置RULE_BASED_STOP_DECIDER总体流程StopOnSidePassCheckClearDoneCheckSidePassStopIsPerceptionBlockedIsClearToChangeLaneCheckSidePassStopBuildStopDecisionELSE:涉及到的一些其他函数NormalizeAngleSelfRotate CheckLaneChang…

创建python环境——Anaconda

在Windows中安装Anaconda和简单使用 一.Anaconda发行概述 Anaconda是一个可以便捷获取和管理包&#xff0c;同时对环境进行统一管理的发行版本&#xff0c;它包含了conda、 Python在内的超过180个科学包及其依赖项。 1.Anaconda发行版本具有以下特点&#xff1a; (1)包含了…

Qt实现一个简单的放射式弹出菜单

Qt实现一个简单的放射式弹出菜单 实现效果&#xff1a; GitHub源码 支持特性 可设置弹出选项的起始角度与角度范围 按住中心按钮&#xff0c;可以拖拽窗口 动画支持&#xff0c;可以设置动画时间、选项的延迟弹出 设置菜单的布局对齐、边距&#xff0c;方便根据场景放置在…

YOLO目标检测——蔬菜检测数据集下载分享

YOLO蔬菜检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;图片格式为jpg&#xff0c;共21000张图片。 数据集点击下载&#xff1a;YOLO蔬菜检测数据集21000图片数据说明.rar

科研无人机平台P600进阶版,突破科研难题!

随着无人机技术日益成熟&#xff0c;无人机的应用领域不断扩大&#xff0c;对无人机研发的需求也在不断增加。然而&#xff0c;许多开发人员面临着无法从零开始构建无人机的时间和精力压力&#xff0c;同时也缺乏适合的软件平台来支持他们的开发工作。为了解决这个问题&#xf…

7.Redis-list

list list常用命令lpushlrangelpushxrpushrpushxlpop / rpoplindexlinsertllenlremltrimlset 阻塞版本命令blpop/brpop 总结内部编码应用场景使用redis作为消息队列 redis中的 list 是一个双端队列, list 相当于是数组或者顺序表。list 并非是一个简单的数组&#xff0c;而是更…

matlab使用教程(29)—微分方程实例

此示例说明如何使用 MATLAB 构造几种不同类型的微分方程并求解。MATLAB 提供了多种数值算法来求解各种微分方程&#xff1a; 1.初始值问题 vanderpoldemo 是用于定义 van der Pol 方程的函数 type vanderpoldemo function dydt vanderpoldemo(t,y,Mu) %VANDERPOLDEMO Defin…

UDP协议的重要知识点

UDP&#xff0c;即用户数据报协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;是一个简单的无连接的传输层协议。与TCP相比&#xff0c;UDP提供了更少的错误检查机制&#xff0c;并允许数据包在网络上更快地传输。在这篇博客中&#xff0c;我们将深入探讨UDP的…

【请求报错:javax.net.ssl.SSLHandshakeException: No appropriate protocol】

1、问题描述 在请求服务时报错说SSL握手异常协议禁用啥的 javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)2、解决方法 在网上查找了方法原因后得知是jdk的问题 修改java.security 文件 Linu…

UG\NX二次开发BlockUI 进入NX的BlockUI编辑界面

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 简介: 要使用BlockUI,需要先进入NX的BlockUI编辑界面。在低版本中,可以在Toolbar工具条中进入开始→所有应用模块→块UI样式编辑器;在高版本中,可以在Ribbon工具栏…

iframe如何用?常见的一些套路

文章目录 &#x1f30a;什么是iframe我们来看一个demoiframe的常用属性iframe的优缺点 &#x1f30a;点击劫持和安全策略&#x1f30a;postMessage通信postMessage &#x1f30a;iframe如何解决跨域资源链接 &#x1f30a;什么是iframe iframe 标签规定一个内联框架。内联框架…

阿里云轻量应用服务器Linux-Centos7下Oracle19c的配置

初始环境&#xff1a;阿里云轻量应用服务器已经安装Oracle19c 具体目标&#xff1a;配置Oracle Database 19c 目录 第一步&#xff1a;切换到Oracle命令行第二步&#xff1a;新建用户和表空间第三步&#xff1a;切换用户第四步&#xff1a;在当前用户下创建一些表第五步&#x…

自动驾驶和辅助驾驶系统的概念性架构(一)

摘要&#xff1a; 本文主要介绍包括功能模块图&#xff0c;涵盖了底层计算单元、示例工作负载和行业标准。 前言 本文档参考自动驾驶计算联盟(Autonomous Vehicle Computing Consortium)关于自动驾驶和辅助驾驶计算系统的概念系统架构。 该架构旨在与SAE L1-L5级别的自动驾驶保…

[Pandas] pandas.melt

melt是溶解 / 分解的意思&#xff0c;即拆分数据 melt()函数可以将一些列的内容进行合并&#xff0c;把宽表整合成长表 语法格式 pandas.melt(frame, id_varsNone, value_varsNone, var_nameNone, value_namevalue)参数说明 frame&#xff1a;要处理的数据集 id_vars&#…

超时取消订单

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

BlockUI专栏目录

文章作者&#xff1a;里海 来源网站&#xff1a;王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C-CSDN博客 简介&#xff1a; BlockUI是一个设计NX对话框的工具&#xff0c;是官方推荐使用的对话框制作方法&#xff0c;能够与NX自身风格相统一&#xff0c;并且在实际…

el-checkbox 多选搜索查询,搜索后选中状态仍保留

<template><div><div class"half-transfer"><div class"el-transfer-panel"><div><el-checkbox v-model"selectAll" change"handleSelectAll">全部</el-checkbox></div><el-input…