客户服务

macOS上的应用软件如何接收诺为翻页笔的API通道数据

2024-09-24 17:12:12 诺为

macOS上的应用软件如何接收诺为翻页笔的API通道数据

诺为翻页笔对电脑来说,就是一个和鼠标、键盘一样的HID(Human Interface Device)设备。其所用的技术,和无线键盘、无线鼠标是一样的。

目前,如果在电脑上想获得翻页笔的按键信息,或者说想用翻页笔来控制电脑上的软件,有两种方法。一种是设置快捷键来获得翻页笔的按键信息,另一种是使用翻页笔的APP通道来获得数据。本文讲述的是macOS上的应用软件如何接收诺为翻页笔的APP通道数据,主要是程序实现。

本文所述的短按是按键抬起时触发,只要没有超过长按计时器的按键抬起,都是短按。本文所述的长按是持续按住按键超过长按计时器时触发。长按计时器一般为1秒,不同的产品可能会有差异。

一、诺为设备的设置和信息

1. 打开Norwii Presenter软件,【功能自定义】页面,在按键的短按或者长按的自定义界面,选择“特殊键” – “APP通道”,然后输入APP通道的值(这个值是十进制的,范围是1-255),点击“确定”和“保存”。

诺为 翻页笔扩音器 18年专业品牌 连续6年销量领先!

2. 在对码页面,按下已经定义为“APP通道”数据的按键,右侧的窗口中出现“APP通道”的键值,说明APP通道的自定义设置成功。

诺为 翻页笔扩音器 18年专业品牌 连续6年销量领先!

3. 在【关于】页面,获取诺为翻页笔的VID和PID。这两个值在USB HID通信中会使用到。页面显示的这两个值是16进制,使用的时候前面加上0x,下图中VID就是0x3243,PID就是 0x0341。不同的产品,VID相同,PID不同。

诺为 翻页笔扩音器 18年专业品牌 连续6年销量领先!

二、USB HID通信

1. Frameworks:IOKit.framework

2. 导入头文件

#import <IOKit/hid/IOHIDLib.h>

3. 初始化IOHIDManager

IOHIDManagerRef managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);

4. 进行配对设置,可以过滤其他USB设备

1) 无配对设备

IOHIDManagerSetDeviceMatching(managerRef, NULL);

2)单类设备配对(其中“pid”和“vid”分别替换为Presenter软件中查到的值)

NSMutableDictionary* dict= [NSMutableDictionary dictionary];

[dict setValue:[NSNumber numberWithLong:pid] forKey:[NSString stringWithCString:kIOHIDProductIDKey encoding:NSUTF8StringEncoding]];

[dict setValue:[NSNumber numberWithLong:vid] forKey:[NSString stringWithCString:kIOHIDVendorIDKey encoding:NSUTF8StringEncoding]];

IOHIDManagerSetDeviceMatching(managerRef, (__bridge CFMutableDictionaryRef)dict);

5. 注册插拔设备的callback

IOHIDManagerRegisterDeviceMatchingCallback(managerRef, &HandleDeviceMatchingCallback, NULL);

IOHIDManagerRegisterDeviceRemovalCallback(managerRef, &HandleDeviceRemovalCallback, NULL);

6. 加入RunLoop

IOHIDManagerScheduleWithRunLoop(managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

7. 打开IOHIDManager

IOReturn IOReturn = IOHIDManagerOpen(managerRef, kIOHIDOptionsTypeNone);

if(kIOReturnSuccess != IOReturn) puts("IOHIDManagerOpen failed.");

8. 实现插拔callback

void Handle_DeviceMatchingCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef)

{

    CFTypeRef ref;

    int32_t nVendorID, nProductID;

    ref = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey));

    if (CFGetTypeID(ref) == CFNumberGetTypeID()) {

        CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &nVendorID);

    }

    ref = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey));

    if (CFGetTypeID(ref) == CFNumberGetTypeID()) {

        CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &nProductID);

    }

    NSLog(@"insert hid, vid is:%d, pid is:%d",nVendorID, nProductID);

    CFRelease(ref);

    }

void Handle_DeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef)

{

    CFTypeRef ref;

    int32_t nVendorID, nProductID;

    ref = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey));

    if (CFGetTypeID(ref) == CFNumberGetTypeID()) {

         CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &nVendorID);

    }

    ref = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey));

    if (CFGetTypeID(ref) == CFNumberGetTypeID()) {

        CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &nProductID);

    }

NSLog(@"remove hid, vid is:%d, pid is:%d",nVendorID, nProductID);

CFRelease(ref);

}

9. 插入设备获取到IOHIDDeviceRef inIOHIDDeviceRef后,打开IOHIDDeviceRef

IOReturn ret = IOHIDDeviceOpen(inIOHIDDeviceRef,options);

if (ret != kIOReturnSuccess)

{

    printf("Open device failed!\n");return;

}

10. 注册接收数据方法,即可接收数据

unsigned char InputBuffer[64];

IOHIDDeviceRegisterInputReportCallback(inIOHIDDeviceRef, InputBuffer, sizeof(InputBuffer), MyInputCallback, NULL);

11. 接收数据callback,当操作定义为“APP通道”数据的按键会收到设备发送来的数据

int appChannel = 0;

void MyInputCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, uint32_t reportID, uint8_t *report,CFIndex reportLength)

{

    memcpy(ReceiveData,report,sizeof(ReceiveData));

    if (report[0] == 0x03 && report[1] == 0x31 && report[2] == 0x00 &&

    report[3] == 0x00 && report[4] == 0x02) {

    appChannel = report[5];

    }

}

12. 向USB设备发送指令

IOReturn ret = IOHIDDeviceSetReport(inIOHIDDeviceRef, kIOHIDReportTypeOutput, 0, (uint8_t*)outbuffer, size);

if (ret != kIOReturnSuccess) {

    PRINTMSG("发送hid数据失败,error number: %x\r\n",ret);

    return ret;

}

13. 断开设备

IOReturn ret = IOHIDDeviceClose(inIOHIDDeviceRef,0L);

if (ret == kIOReturnSuccess) {

    NSLog(@"断开成功");

}

14. 可能出现的问题

1)出现如下报错:

TCC deny IOHIDDeviceOpen

Open device failed!

需要赋予输入监听权限

诺为 翻页笔扩音器 18年专业品牌 连续6年销量领先!

2)赋予权限后依然不能打开hid时,需要在sandbox页赋予USB权限。

诺为 翻页笔扩音器 18年专业品牌 连续6年销量领先!