Windows 8.1应用外设开发之人机接口设备(HID)

失足处男的倒霉孩子 发布于 2013/12/28 14:43
阅读 2K+
收藏 1

Windows 8.1人机接口设备(HID)

快速开发手册

2013年11月

本文信息适用于以下版本产品:

Windows 8.1

 Windows规划与合作伙伴部


HID设备背景简介

人机接口设备(Human Interface Devices 或简称 HID) 是一系列以支持该同名协议为基准的设备。HID协议最早是为键盘、鼠标和游戏杆等设备而开发的。其最初设计目的是为了处理 USB 数据传输,但现在这个协议已可以支持范围更加广泛的设备,而不仅局限于 USB 一者。任何符合 HID 协议标准定义的设备均可被称为HID设备。

Windows Runtime 8.1下新引入的HID API大大简化了开发者与HID设备通信的过程。HID API可通过HID Reports( Feature Report, Input Report, Output Report ) 方便的与HID设备进行直接通信,如果您对HID 协议中相关的Usage Table, HID Report等概念较为生疏,您可以在下面链接页上找到有关其更详细的介绍:http://www.usb.org/developers/hidpage/

Windows Runtime 8.1下的HID API开发

在Windows Runtime 8.1下与HID设备进行通信非常简单且直观,Windows Runtime 8.1使用系统集成的HID内建驱动程序( Inbox Driver ) 原生支持在各类平台上( ARM/x86/x64 ) 对HID设备的读写Report功能,免去开发者为不同平台分别开发驱动程序的过程,而可以直接调用系统内建的HID API与HID设备进行通信。

首先要考虑的设备局限性问题

在开始HID API开发前,首先需要了解Windows Runtime 8.1 HID API基于安全方面的考虑,阻挡了对如下Usage Page操作页的访问权限:

  • HID_USAGE_PAGE_UNDEFINED
  • HID_USAGE_PAGE_GENERIC
  • HID_USAGE_GENERIC_KEYBOARD
  • HID_USAGE_GENERIC_KEYPAD
  • HID_USAGE_GENERIC_SYSTEM_CTL
  • HID_USAGE_PAGE_KEYBOARD
  • HID_USAGE_PAGE_CONSUMER
  • HID_USAGE_PAGE_DIGITIZER
  • HID_USAGE_PAGE_SENSOR
  • HID_USAGE_PAGE_BARCODE_SCANNER
  • HID_USAGE_PAGE_WEIGHING_DEVICE
  • HID_USAGE_PAGE_MAGNETIC_STRIPE_READER
  • HID_USAGE_PAGE_TELEPHONY

请注意基于以上Usage Page操作页的访问请求都将被系统拒绝。

设备声明的必要性

在使用HID API前,首先需要在应用的manifest配置中声明即将使用设备的设备信息,这将告知系统本应用有权访问被声明的设备,否则系统将拒绝一切与该设备的通信请求。需要注意的是,即使该设备在此被声明有权访问,在程序中进行打开设备请求时用户仍有最终决定是否允许访问该设备的权利。关于设备声明的详细内容请参考: 简单4步启动HID API应用开发 – 声明设备

简单4步启动HID API 应用开发

Windows Runtime 8.1下的HID API设备通信可以简单归纳为以下4个步骤:声明设备发现设备连接设备读写设备

下面介绍如何快速的实现这些步骤,如果您希望更进一步了解更多的资讯可以参考本文后面的API快速参考及相关资源列表。

请注意,下面信息可能并不完全适用于最终生产环境,一些商业应用中应考虑的相关场景(如设备占用,应用挂起、恢复处理等)并未在下述中涉及到。

1. 声明设备: 

该步骤引导您首先需要在工程的Package.appxmanifest文件中声明对目标HID设备的使用。

对此只需要在<Capabilities>…</Capabilities>内加入对该HID设备的设备描述,包括Vendor ID + Product ID 以及Usage信息,例如:

<m2:DeviceCapability Name="humaninterfacedevice"><!-- 此行声明如下为HID设备 -->
      <m2:Device Id="vidpid:1941 8021"><!-- 声明设备的Vendor ID为1941,Product ID为8021 -->
        <m2:Function Type="usage:FFA0 *" /><!-- 声明设备可使用其UsagePage:FFA0下的所有Usage ID:* -->
      </m2:Device>
</m2:DeviceCapability>

 
 
 

 

 
 

请注意如果未做以上声明应用将无法连接或读写此设备。

2. 发现设备: 

该步骤可通过两种方式实现:直接查找设备,或通过设备监视发现设备。

以直接查找设备方式: 

基本流程:获取设备描述HidDevice.GetDeviceSelector(...) -> 查找设备DeviceInformation.FindAllAsync(...)

示例C#代码 –

// 首先获取查找设备所需的设备描述信息Selector
string myHidSelector = HidDevice.GetDeviceSelector(usagePage = 0xFFA0, usageId = 0x01, vendorId = 0x1941, productId = 0x8021);

// 查找上面Selector所指向的设备
DeviceInformationCollection myDeviceInformationCollection = await DeviceInformation.FindAllAsync(myHidSelector);

通过对以上DeviceInformationCollection数据集中各元素进一步筛选获得目标设备之唯一DeviceInformation信息

以通过设备监视发现设备方式: 

添加一个设备监视器( DeviceWatcher ),监视HID设备的连接与断开,并在检测到这些变化时告知应用。

基本流程:获取设备描述HidDevice.GetDeviceSelector(...) -> 创建监视DeviceInformation.CreateWatcher(...) -> 添加设备事件处理 -> 开始监视DeviceWatcher.Start() 

示例C#代码 –

// 首先获取DeviceWatcher所需的监视设备描述信息Selector
string myHidSelector = HidDevice.GetDeviceSelector(usagePage = 0xFFA0, usageId = 0x01, vendorId = 0x1941, productId = 0x8021);

// 创建一个DeviceWatcher用来监视上面Selector指向的设备
DeviceWatcher myHidWatcher = DeviceInformation.CreateWatcher(myHidSelector);

// 注册和设备监视相关的事件处理函数
myHidWatcher.Added += new TypedEventHandler(this.OnDeviceAdded);//设备连接时系统将调用this.OnDeviceAdded
myHidWatcher.Removed += new TypedEventHandler(this.OnDeviceRemoved);//设备断开时将调用this.OnDeviceRemoved

// 开始监视
myHidWatcher.Start();

在事件处理函数this.OnDeviceAdded下系统传入的第二个参数即可以获得目标设备的唯一DeviceInformation信息。

通过以上两种方式获取的设备唯一DeviceInformation信息( 注:即使两台种类相同的设备也拥有不同的DeviceInformation信息 )将用于下一步与设备的连接。建议此处建立一个全局或公共变量记录该DeviceInformation信息供稍后使用,如:myHidDeviceInformation

3. 连接设备: 

该步骤通过已获取的DeviceInformation信息连接并打开该HID设备。

基本流程:获取设备唯一ID信息DeviceInformation.Id -> 获取设备句柄HidDevice.FromIdAsync(...) -> 判断设备句柄是否成功获取(null != HidDevice )

示例C#代码 –

// 通过上一步获得的DeviceInformation下的唯一Id信息获取该HID设备操作句柄HidDevice
HidDevice myHidHidDevice = await HidDevice.FromIdAsync(myHidDeviceInformation.Id, FileAccessMode.ReadWrite);

if (null != myHidHidDevice)//非null表明已成功连接并打开该设备
{
    // 成功打开设备,可以继续进行后续操作
}
else//未能成功打开该设备
{
    var deviceAccessStatus = DeviceAccessInformation.CreateFromId(mMyFTHIDDeviceInfo.Id).CurrentStatus;

    if (deviceAccessStatus == DeviceAccessStatus.DeniedByUser)//用户拒绝访问该设备
    { }
    else if (deviceAccessStatus == DeviceAccessStatus.DeniedBySystem)//系统拒绝访问该设备
    { }
    else//该设备可能已被其他应用打开
    { }
}

4. 读写设备: 

通过上一步获得的设备操作句柄HidDevice向HID设备读写数据。

OutputReport基本流程:创建byte类数组,其总长度应与设备定义的ReportLength( 包括ReportID如果设备已定义之 )一致 -> Report内容写入byte类数组如果设备已定义ReportID则必须将之添加至数组首元素否则可对其忽略,顺序将Report内容写入各数组元素中,将后面空缺字节全部补0 ) -> 将数组内容附到HidOutputReport.Data -> 发送Report至设备HidDevice.SendOutputReportAsync(...)

InputReport基本流程:获取Report自设备HidDevice.GetInputReportAsync(...) -> 读取HidInputReport.Data 上内容至数组

示例C#代码 –

// 以下向HID设备输出OutputReport

// 以下向HID设备输出OutputReport
byte reportID = 0x00;//设定ReportID为0x00
Listbytestowrite = new List() { reportID, 0x10 };//即将输出的内容,第一个字节必须为reportID如果设备已对其进行定义
HidOutputReport outputReport = myHidHidDevice.CreateOutputReport(reportID);//创建OutputReport实例
for (int n = bytestowrite.Count; n < outputReport.Data.Length; n++) bytestowrite.Add(0);//将Report后面的空缺字节全补为0

// 创建一个DataWriter用来写入数据
var dataWriter = new DataWriter();
dataWriter.WriteBytes(bytestowrite.ToArray());
outputReport.Data = dataWriter.DetachBuffer();

// 发送OutputReport至HID设备
await myHidHidDevice.SendOutputReportAsync(outputReport);

//...

// 以下从HID设备获取InputReport
HidInputReport inputReport = await myHidHidDevice.GetInputReportAsync(reportID);

// 将InputReport中获取的字节数据全部读入
byte[] inputBytes = new byte[inputReport.Data.Length];
DataReader.FromBuffer(inputReport.Data).ReadBytes(inputBytes);

关闭设备

当设备不再使用时,关闭设备以释放资源是一种良好的习惯。

示例C#代码 –

if (myHidHidDevice != null)
{
    // 关闭该HID设备操作句柄
    myHidHidDevice.Dispose();

    myHidHidDevice = null;
}

Windows Runtime 8.1 HID API开发需要注意的问题

应用挂起 / 恢复 

应用挂起时系统将自动关闭使用中的设备,但在应用恢复时不会自动将设备打开。另外应用挂起时DeviceWatcher仍然会继续工作,因此此时程序应通过停止DeviceWatcher停止监视设备连接,以免干扰设备稍后的正常运行。并且为保持代码一贯性,应用挂起时程序还应将设备关闭,应用恢复时再将其重新打开。

Windows Runtime 8.1 HID API 相关资料参考

绝大部分HID API开发中需要运用到的API、事件及各类属性均位于以下两个命名空间。

Windows.Devices.HumanInterfaceDevice

Windows.Devices.Enumeration

更多关于HID的详细资料:

• Windows 8.1 设备开发概览

http://msdn.microsoft.com/zh-cn/library/windows/apps/bg182882.aspx

• Supporting human interface devices

http://msdn.microsoft.com/library/windows/apps/dn263140.aspx

• Quick Start: HID

http://msdn.microsoft.com/library/windows/apps/dn263133.aspx

• How to specify device capabilities for HID

http://msdn.microsoft.com/library/windows/apps/dn263091.aspx

• 自定义 HID 设备访问示例

http://code.msdn.microsoft.com/windowsapps/Custom-HID-Device-Access-40c3aa8f/

• 视频:Building apps that connect with devices (英文)

http://channel9.msdn.com/Events/Build/2013/2-023

• 视频:Apps for HID Devices (英文)

http://channel9.msdn.com/Events/Build/2013/2-924b

加载中
返回顶部
顶部