将 Dream Cheeky Thunder Missile Launcher 连接到 Windows 8.1






4.50/5 (4投票s)
利用 Win8.1 中的新设备 API。
自 2013 年 BUILD 会议以来,有大量用户试图将外围设备集成到他们的现代应用程序中——在我们能插入计算机的众多设备中,只有一种设备脱颖而出,成为人们渴望连接的设备?
这款 Dream Cheeky Thunder Missile Launcher 是一款售价 35 美元的趣味玩具,可在全球各种零售商处购买。Thunder 的构造很简单——它是一款基于 USB 的气动导弹发射器,可以让你瞄准并向你附近毫无戒心的人发射泡沫飞镖。该设备在全球极客中非常受欢迎,甚至出现在了《生活大爆炸》中。
现代应用 -> HID 设备
除了我们这些经常写代码的人的信誉之外,Thunder 的另一个令人兴奋的特性是它的驱动程序堆栈。与 OWI-535 机械臂 类似使用专有驱动程序不同,该设备本身实际上利用了一个现有的 Windows 标准作为 HID(人机接口设备),就像键盘和鼠标一样。那么,这为什么对我们开发者来说是件好事呢?首先,我们无需对操作系统进行任何操作来安装或配置设备,而且由于它使用的是已移植到 ARM 堆栈的标准 Windows 驱动程序,因此该设备也能在 Surface 等 Windows RT 设备上运行!
插入设备并让 Windows 识别它只是我们解决方案的一小部分。作为应用程序开发者,我们希望从我们的现代应用程序中利用此设备,并允许我们的用户互相射击。幸运的是,Windows 8.1 通过引入 Windows.Device.HumanInterfaceDevices
命名空间为我们提供了支持。因此,让我们花几分钟看看开始发射导弹所需的代码。
Windows.Device.HumanInterfaceDevice
与任何想要超越标准 UI 提示的现代应用程序一样,我们需要征得用户的许可才能访问设备。这是一项安全功能,可防止应用程序变成恶意软件。在 Windows 8.1 中,与 Windows 8 一样,我们通过 package.appxmanifest 文件来完成此操作,并利用命名空间扩展来引用新的 8.1 功能。目前 Visual Studio manifest 编辑器不支持这些更改,因此请在文本编辑器中打开您的文件并添加以下行:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/2010/manifest"
xmlns:m2="http://schemas.microsoft.com/appx/2013/manifest">
<Capabilities> ...
<m2:DeviceCapability Name="humaninterfacedevice">
<m2:Device Id="any">
<m2:Function Type="usage:0001 0010"/>
</m2:Device>
</m2:DeviceCapability></Capabilities>
</Package>
在此示例中,我做出了更广泛的用户请求。具体来说,我没有定义一个产品,而是请求访问任何符合指定的用法页面和用法 ID 的 HID 设备。我特意这样做是为了展示指定一个应用程序寻找一个特定设备与寻找一系列设备之间的区别。如果您确实想更精细,则可以像我在 USB 示例中那样指定 VID 和 PID,而不是使用 any 参数。
一旦我们声明了访问意图,我们就需要设置一些代码来查找设备是否已连接到我们的计算机。同样,为了与我的上一篇文章形成对比,我将使用 DeviceWatcher
来执行此操作。如果我想要一个关于设备是否连接的即时视图,我可以使用我在机械臂文章中演示的 Windows.Devices.Enumeration
技术。相反,我选择使用监视器,使用同一对象 Windows.Devices.Enumeration.DeviceInformation
的一个方法。然而,监视器会监控计算机上的设备管理器以添加设备,并在找到设备时触发事件。这为您在应用程序的任何生命周期中处理添加或移除设备提供了功能。
创建监视器所需的代码是:
const ushort vid = 8483;
const ushort pid = 4112;
const ushort uid = 16;
const ushort uPage = 1;
var deviceWatcher = DeviceInformation.CreateWatcher(
HidDevice.GetDeviceSelector(uPage, uid, vid, pid));
deviceWatcher.Added += (s, a) => Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, async () => { .. do something here.. });
deviceWatcher.Start();
这与任何设备连接非常相似。我们使用 Windows.Devices.HumanInterfaceDevice.HidDevice
上的一个辅助方法,通过传入 Vendor ID、Product Id、Usage ID 和 Usage Page 值来创建一个 AQS(查询语句)字符串。然后,监视器使用 AQS 来查找连接到计算机的任何设备,这会触发事件。需要注意的一个重要代码是事件处理程序中的调度程序。这是因为当设备添加并且您尝试连接时,Windows 会在 UI 中弹出窗口,要求用户许可。因此,用于连接设备的任何代码都需要位于 UI 线程上。
要实际建立与设备的连接,只需在 Windows.Devices.HumanInterfaceDevice.HidDevice
对象上调用一个异步方法即可。
_hidDevice = await HidDevice.FromIdAsync(a.Id,FileAccessMode.ReadWrite);
FromIdAsync
方法接受两个参数,即设备 ID(从监视器事件的 DeviceInformation
返回)以及一个枚举的 FileAccessMode
来指定连接类型——在我们的情况下是 ReadWrite
,因为我们想将命令传递给设备。
现在我们已经与设备建立了主动连接,因此我们可以开始向其发送数据。HID 设备的数据包相对较小且易于传输——如果您想象一个键盘 HID 设备,它只会发送相应的按键数据,这些数据都相对较小。由于设备类型相似,Thunder 期望简单的小型数据包(尤其是与 USB 机械臂相比),对应于上、下、左、右、开火。
要发送此类数据,我们只需使用一个 byte[] 并将其附加到一个 OutputReport
对象。幸运的是,另一个辅助类为我们创建了该对象,因此我们只需附加我们的数据包并使用类似如下的代码发送数据
private async Task SendOutputMessage(byte[] message) {
if (_hidDevice != null) {
var report = _hidDevice.CreateOutputReport();
report.Data = message.AsBuffer();
await _hidDevice.SendOutputReportAsync(report);
}
}
就是这样!使用这几行代码,我们就可以与 USB Thunder 导弹发射器建立主动连接,并开始发送命令。
以下是我们如何打开 LED:
var LED_ON = new byte[] { 0, 3, 1, 0, 0, 0, 0, 0, 0 };
await SendOutputMessage(LED_ON);
在此期间,请尽情享受您的硬件黑客之旅!