编辑:这里报告的问题:https ://github.com/signal11/hidapi/issues/276
Inkling 是来自 Wacom 的笔设备。( InklingReader ) 是一个开源项目,可以从中获取实时数据。
我正在尝试整理 InklingReader 以使用HIDAPI而不是libusb (因为它在更高级别上工作:HID 而不是原始 USB,所以更紧凑和更合适。libusb 在最近的 OSX 上也失败了)。
HID API 一个小库:一个 .h,一个(每个平台).c。
我的代码如下所示:
unsigned short inklingVendorId = 0x056a, inklingProductId = 0x0221;
if (hid_init() == FAIL) return;
handle = hid_open(inklingVendorId, inklingProductId, nullptr);
在 Windows 上hid_open
失败。单步执行在这里揭示了故障点:
// path = "\\\\?\\hid#vid_056a&pid_0221&mi_00&col01#8&1ea90857&0&0000#"
// "{4d1e55b2-f16f-11cf-88cb-001111000030}"
//
static HANDLE open_device(const char *path, BOOL enumerate)
{
HANDLE handle;
DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
// enumerate = 0
handle = CreateFileA(path,
desired_access,
share_mode,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
0);
int err = GetLastError(); // 5 i.e. ERROR_ACCESS_DENIED
return handle; // returns 0xffffffff i.e. INVALID_HANDLE
}
现在,HIDAPI 作者说“HIDAPI 不适用于 Windows 上的键盘和鼠标。Windows 作为安全措施不允许打开鼠标和键盘 HID。” (这里)
如果我枚举 HID 设备:
struct hid_device_info *devs, *cur_dev;
devs = hid_enumerate(inklingVendorId, inklingProductId);
cur_dev = devs;
while (cur_dev) {
DBG2("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
DBG2("");
DBG2(" Manufacturer: %ls", cur_dev->manufacturer_string);
DBG2(" Product: %ls", cur_dev->product_string);
DBG2(" Release: %hx", cur_dev->release_number);
DBG2(" Interface: %d", cur_dev->interface_number);
DBG2(" Usage Page: %d", cur_dev->usage_page);
DBG2(" Usage: %d", cur_dev->usage);
DBG2("");
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
...我得到的不是一个而是两个条目:
Device Found
type: 056a 0221
path: \\?\hid#vid_056a&pid_0221&mi_00&col01#8&1ea90857&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
serial_number: 2B0400001C90C22A0002DD07FE8B022A
Manufacturer: Wacom, Inc.
Product: MSC Device
Release: 1256
Interface: 0
Usage Page: 1
Usage: 2
Device Found
type: 056a 0221
path: \\?\hid#vid_056a&pid_0221&mi_00&col02#8&1ea90857&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}
serial_number: 2B0400001C90C22A0002DD07FE8B022A
Manufacturer: Wacom, Inc.
Product: MSC Device
Release: 1256
Interface: 0
Usage Page: 13
Usage: 2
(注意:OSX 只报告 SECOND 条目!在 OSX 上没有问题!)
比较path
:
路径: \?\hid#vid_056a&pid_0221&mi_00& col01 #8&1ea90857&0& 0000 #...
路径: \?\hid#vid_056a&pid_0221&mi_00& col02 #8&1ea90857&0& 0001 #...
根据http://www.usb.org/developers/hidpage/Hut1_12v2.pdf,
UsagePage/Usage = 1/2 = {通用桌面控件}/{鼠标}。
UsagePage/Usage = 13/2 = {Digitizers}/{Pen}。
(编辑:有时第一个路径是 1/2,第二个是 13/2,其他时候它被交换)。
而 HIDAPI只采用它找到的第一个。
所以看起来这应该是解决方案。Inkling 暴露了 2 个“设备”,而 hidapi 使用了错误的(鼠标)设备,并且 Windows 不允许访问鼠标或键盘设备。
所以我调整了代码...
while (cur_dev) {
if (cur_dev->vendor_id == vendor_id &&
cur_dev->product_id == product_id &&
cur_dev->usage_page == 13)
{
...要获得正确的条目,它应该可以正常工作吗?
不, CreateFileA 只是引发了一个不同的错误:
usage_page== 1 => 错误代码 5 (ERROR_ACCESS_DENIED)
usage_page==13 => 错误代码 32 (ERROR_SHARING_VIOLATION)
嗯。这是相当令人不安的。我好像走投无路了!
我试过摆弄 CreateFileA 的参数,例如替换GENERIC_READ | GENERIC_WRITE
为 STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE
-- 现在它愉快地创建了一个句柄。但随后hid_read
的 -s 无法收集任何数据。
烤面包机和萤火虫都可以在 HID 堆栈中工作。toaster 展示了如何通过原始 PDO 处理过滤器,firefly 展示了如何使用 WMI 访问它。从 C 的角度来看,我认为原始 PDO 的编码要简单得多,WMI 有点讨厌和复杂。
作者推荐的是烤面包机,但它是一个很大的代码库,我没有 Windows 驱动程序编程的经验。
看起来我将不得不挖掘很多非常陌生的领域才能让任何事情发挥作用,所以在开始之前我在这里问。如果没有人回答并且我弄清楚了,我将回答我自己的问题。
我唯一能想到的另一件事是,也许另一个过程已经在参与这条路径。也许如果我可以终止这个过程, CreateFileA 可能会成功?Roel 的 libusb 方法涉及分离内核驱动程序:https ://github.com/roelj/inklingreader/blob/master/src/usb/online-mode.c#L98
PS 我在某处读到,如果另一个进程已经打开了这个设备,我们的打开必须与之前打开的权限相匹配。而且我还读到 Windows 在检测到时会自动打开所有 HID 设备。
PPS 也许一个想法是尝试替代 HID库 在 Windows 上与 USB HID 设备通信的最佳 USB 库是什么?
PPPS 也许我需要以管理员身份运行我的代码。但这不是一个好的解决方案。