How to get Magic Mouse/Trackpad InputValueCallback

<plist version="1.0"> <dict> <key>com.apple.security.app-sandbox</key> <true/> <key>com.apple.security.device.bluetooth</key> <true/> <key>com.apple.security.device.usb</key> <true/> <key>com.apple.security.files.user-selected.read-only</key> <true/> </dict> </plist>

I confirmed that I had successfully turned on the device and registered the callback method, but the callback method was not successfully invoked when moving with Magic mouse. What method does the Magic Mouse and Magic Trackpad need to use to get the input value of the device?

IOReturn ioReturn = IOHIDDeviceOpen(deviceRef, kIOHIDOptionsTypeNone); if ( kIOReturnSuccess == ioReturn ) { IOHIDDeviceRegisterInputValueCallback(deviceRef, mouseInputValueCallback, NULL); }

static void mouseInputValueCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) { NSLog(@"handle input value"); }

I passed the __IOHIDDeviceCopyMatchingInputElements get magic mouse input element <__NSArrayM 0x6000012c4900>( timestamp: 0 type: 1 usagePage: 1 usage: 48 reportID: 16 value: 0, timestamp: 0 type: 1 usagePage: 1 usage: 49 reportID: 16 value: 0, timestamp: 0 type: 2 usagePage: 9 usage: 1 reportID: 16 value: 0, timestamp: 0 type: 2 usagePage: 9 usage: 2 reportID: 16 value: 0 )

  • (NSArray *)getHIDReprots {

    if (!deviceRef) { return nil; }

    NSMutableArray *reports = [[NSMutableArray alloc] init]; CFArrayRef elements; CFIndex i;

    elements = IOHIDDeviceCopyMatchingElements(deviceRef, NULL, kIOHIDOptionsTypeNone); for (i = 0; i<CFArrayGetCount(elements); i++) { const IOHIDElementRef element = (void*)CFArrayGetValueAtIndex(elements, i); IOHIDElementType eleType = IOHIDElementGetType(element); NSString *eleTypeStr = @""; switch (eleType) { case kIOHIDElementTypeInput_Misc: eleTypeStr = @"kIOHIDElementTypeInput_Misc"; break; case kIOHIDElementTypeInput_Button: eleTypeStr = @"kIOHIDElementTypeInput_Button"; break; case kIOHIDElementTypeInput_Axis: eleTypeStr = @"kIOHIDElementTypeInput_Axis"; break; case kIOHIDElementTypeInput_ScanCodes: eleTypeStr = @"kIOHIDElementTypeInput_ScanCodes"; break; case kIOHIDElementTypeInput_NULL: eleTypeStr = @"kIOHIDElementTypeInput_NULL"; break; case kIOHIDElementTypeOutput: eleTypeStr = @"kIOHIDElementTypeOutput"; break; case kIOHIDElementTypeFeature: eleTypeStr = @"kIOHIDElementTypeFeature"; break; case kIOHIDElementTypeCollection: eleTypeStr = @"kIOHIDElementTypeCollection"; break; default: break; }

      uint32_t page = IOHIDElementGetUsagePage(element);
      uint32_t usage = IOHIDElementGetUsage(element);
      uint32_t reportID = IOHIDElementGetReportID(element);
      uint32_t reportSize = IOHIDElementGetReportSize(element);
      uint32_t reportCount = IOHIDElementGetReportCount(element);
      NSString *elementStr = [[NSString alloc] initWithFormat:@" reportID:%d, reportSize:%d, type:%@, UsagePage:%d, usage:%d, reportCount:%d\n\n",reportID, reportSize, eleTypeStr, page, usage, reportCount];
      [reports addObject:elementStr];
    

    } return reports;

}

reportID:0, reportSize:0, type:kIOHIDElementTypeCollection, UsagePage:1, usage:2, reportCount:1 reportID:0, reportSize:0, type:kIOHIDElementTypeCollection, UsagePage:1, usage:1, reportCount:1 reportID:16, reportSize:16, type:kIOHIDElementTypeInput_Misc, UsagePage:1, usage:48, reportCount:1 reportID:16, reportSize:16, type:kIOHIDElementTypeInput_Misc, UsagePage:1, usage:49, reportCount:1 reportID:16, reportSize:1, type:kIOHIDElementTypeInput_Button, UsagePage:9, usage:1, reportCount:1 reportID:16, reportSize:1, type:kIOHIDElementTypeInput_Button, UsagePage:9, usage:2, reportCount:1 reportID:71, reportSize:8, type:kIOHIDElementTypeFeature, UsagePage:6, usage:32, reportCount:1 reportID:85, reportSize:512, type:kIOHIDElementTypeFeature, UsagePage:65282, usage:85, reportCount:64 reportID:0, reportSize:0, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:-1, reportCount:1 reportID:0, reportSize:1, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:0, reportCount:1 reportID:16, reportSize:0, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:-1, reportCount:1 reportID:16, reportSize:1, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:0, reportCount:1 reportID:71, reportSize:0, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:-1, reportCount:1 reportID:71, reportSize:1, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:0, reportCount:1 reportID:85, reportSize:0, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:-1, reportCount:1 reportID:85, reportSize:1, type:kIOHIDElementTypeInput_NULL, UsagePage:0, usage:0, reportCount:1

Devices: VendorID ProductID LocationID UsagePage Usage RegistryID Transport Class Product UserClass Built-In 0x4c 0x265 0x3bab3ec3 1 2 0x100001ec4 Bluetooth AppleHSBluetoothHIDDriver Magic Trackpad (null) 0
0x4c 0x265 0x3bab3ec3 0 1 0x100001eb2 Bluetooth AppleHSBluetoothDevice Magic Trackpad (null) 0
0x5ac 0x30d 0x5abbb32b 1 2 0x100001221 Bluetooth BNBMouseDevice Magic Mouse (null) 0
0x4c 0x265 0x3bab3ec3 65280 3 0x100001ed2 Bluetooth AppleHSBluetoothHIDDriver Magic Trackpad (null) 0
0x4c 0x265 0x3bab3ec3 65280 13 0x100001ecc Bluetooth AppleHSBluetoothHIDDriver Magic Trackpad (null) 0
0x4c 0x265 0x3bab3ec3 65280 11 0x100001eba Bluetooth AppleHSBluetoothHIDDriver Magic Trackpad (null) 0

Is there any technical support from Apple to help answer this question, Thank you!

Hello, Can you provide complete example of use IOHIDDevice API's to get input from mouse?

Complete code example would help to identify issue.

USBHIDDevice *currentDevice;

@interface USBHIDDevice() {

IOHIDDeviceRef deviceRef;

} @end

@implementation USBHIDDevice

-(instancetype)initWithDevice:(IOHIDDeviceRef)deviceRef {

self = [super init];
if (self) {
    [self setDeviceRef:deviceRef];
}
return self;

}

-(void)connectHID{

[self openDevice];

}

-(void)disConnectHID {

if(deviceRef){
    [self closeDevice];
}

}

-(IOReturn)openDevice {

if (!deviceRef) {
    return kIOReturnError;
}
currentDevice = self;
IOReturn ioReturn = IOHIDDeviceOpen(deviceRef, kIOHIDOptionsTypeNone);
if ( kIOReturnSuccess == ioReturn ) {
    char *inputbuffer = malloc(64);
    IOHIDDeviceRegisterInputReportCallback(deviceRef, (uint8_t*)inputbuffer, 64, inputCallback, NULL);
    NSDictionary *inputMatchingDict = @{@(kIOHIDElementUsagePageKey): @(0x09), @(kIOHIDElementUsageKey): @(0x02)};
    IOHIDDeviceSetInputValueMatching(deviceRef, (__bridge CFDictionaryRef)inputMatchingDict);
    IOHIDDeviceRegisterInputValueCallback(deviceRef, mouseInputValueCallback, NULL);
}else{
    [self setDeviceRef:NULL];
}
return ioReturn;

}

-(IOReturn)closeDevice {

IOReturn ioReturn = [self checkHIDDevice];
if (kIOReturnSuccess == ioReturn) {
    ioReturn = IOHIDDeviceClose(deviceRef, kIOHIDOptionsTypeNone);
}
[self setDeviceRef:NULL];
return ioReturn;

}

-(IOReturn)checkHIDDevice{

if (!deviceRef) {
    NSLog(@"close devie failed(%x).", kIOReturnNotOpen);
    return kIOReturnNotOpen;
}
return kIOReturnSuccess;

}

-(NSArray *)getHIDReprots {

if (!deviceRef) {
    return nil;
}

NSMutableArray *reports = [[NSMutableArray alloc] init];

CFArrayRef elements;
CFIndex i;

elements = __IOHIDDeviceCopyMatchingInputElements(deviceRef, NULL);

elements = IOHIDDeviceCopyMatchingElements(deviceRef, NULL, kIOHIDOptionsTypeNone);
for (i = 0; i<CFArrayGetCount(elements); i++) {
    const IOHIDElementRef element = (void*)CFArrayGetValueAtIndex(elements, i);
    IOHIDElementType eleType = IOHIDElementGetType(element);
    NSString *eleTypeStr = @"";
    switch (eleType) {
        case kIOHIDElementTypeInput_Misc:
            eleTypeStr = @"kIOHIDElementTypeInput_Misc";
            break;
        case kIOHIDElementTypeInput_Button:
            eleTypeStr = @"kIOHIDElementTypeInput_Button";
            break;
        case kIOHIDElementTypeInput_Axis:
            eleTypeStr = @"kIOHIDElementTypeInput_Axis";
            break;
        case kIOHIDElementTypeInput_ScanCodes:
            eleTypeStr = @"kIOHIDElementTypeInput_ScanCodes";
            break;
        case kIOHIDElementTypeInput_NULL:
            eleTypeStr = @"kIOHIDElementTypeInput_NULL";
            break;
        case kIOHIDElementTypeOutput:
            eleTypeStr = @"kIOHIDElementTypeOutput";
            break;
        case kIOHIDElementTypeFeature:
            eleTypeStr = @"kIOHIDElementTypeFeature";
            break;
        case kIOHIDElementTypeCollection:
            eleTypeStr = @"kIOHIDElementTypeCollection";
            break;
        default:
            break;
    }
    
    uint32_t page = IOHIDElementGetUsagePage(element);
    uint32_t usage = IOHIDElementGetUsage(element);
    uint32_t reportID = IOHIDElementGetReportID(element);
    uint32_t reportSize = IOHIDElementGetReportSize(element);
    uint32_t reportCount = IOHIDElementGetReportCount(element);
    
    NSString *elementStr = [[NSString alloc] initWithFormat:@" reportID:%d, reportSize:%d, type:%@, UsagePage:%d, usage:%d, reportCount:%d\n\n",reportID, reportSize, eleTypeStr, page, usage, reportCount];
    
    [reports addObject:elementStr];
}
return reports;

}

CFArrayRef __IOHIDDeviceCopyMatchingInputElements(IOHIDDeviceRef device, CFArrayRef multiple) {

CFMutableArrayRef       inputElements   = NULL;
CFArrayRef              elements        = NULL;
CFIndex                 index, count;

// Grab the matching multiple.  If one has not already been specified,
// fallback to the default
if ( multiple ) {
    CFRetain(multiple);
} else {
    uint32_t inputTypes[] = { kIOHIDElementTypeInput_Misc, kIOHIDElementTypeInput_Button, kIOHIDElementTypeInput_Axis, kIOHIDElementTypeInput_ScanCodes};
    count = sizeof(inputTypes) / sizeof(uint32_t);
    CFDictionaryRef matching[count];
    bzero(matching, sizeof(CFDictionaryRef) * count);
    
    CFStringRef key = CFSTR(kIOHIDElementTypeKey);
    for ( index=0; index<count; index++ ) {
        CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inputTypes[index]);
        matching[index] = CFDictionaryCreate(kCFAllocatorDefault,
                                             (const void **)&key,
                                             (const void **)&number,
                                             1,
                                             &kCFCopyStringDictionaryKeyCallBacks,
                                             &kCFTypeDictionaryValueCallBacks);
        CFRelease(number);
    }
    
    multiple = CFArrayCreate(kCFAllocatorDefault, (const void **)matching, count, &kCFTypeArrayCallBacks);
    for ( index=0; index<count; index++ )
        CFRelease(matching[index]);
}

if ( !multiple )
    return NULL;
    
count = CFArrayGetCount( multiple );

for ( index=0; index<count; index++) {
    elements = IOHIDDeviceCopyMatchingElements( device,
                                                CFArrayGetValueAtIndex(multiple, index),
                                                0);
    if ( !elements )
        continue;
        
    if ( !inputElements )
        inputElements = CFArrayCreateMutableCopy(   kCFAllocatorDefault,
                                                    0,
                                                    elements);
    else
        CFArrayAppendArray( inputElements,
                            elements,
                            CFRangeMake(0, CFArrayGetCount(elements)));
 
    CFRelease(elements);
}

CFRelease(multiple);
return inputElements;

}

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

[currentDevice sendMessageWithDelegate:report length:reportLength];

}

static void mouseInputValueCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) { NSLog(@"handle input value"); }

-(void)sendMessageWithDelegate:(uint8_t*)recvData length:(CFIndex)reportLength{

}

Need to provide execution context for callback with IOHIDDeviceSetDispatchQueue or IOHIDDeviceUnscheduleFromRunLoop. Also consider setting up callbacks first: IOHIDDeviceRegisterInputReportCallback(deviceRef, (uint8_t*)inputbuffer, 64, inputCallback, NULL); NSDictionary *inputMatchingDict = @{@(kIOHIDElementUsagePageKey): @(0x09), @(kIOHIDElementUsageKey): @(0x02)}; IOHIDDeviceSetInputValueMatching(deviceRef, (__bridge CFDictionaryRef)inputMatchingDict); IOHIDDeviceRegisterInputValueCallback(deviceRef, mouseInputValueCallback, NULL); before calling IOHIDDeviceOpen

How to get Magic Mouse/Trackpad InputValueCallback
 
 
Q