HIDUserDevice.m   [plain text]


//
//  HIDUserDevice.m
//  HID
//
//  Created by dekom on 10/9/17.
//

#import "HIDUserDevice.h"
#import <IOKit/hid/IOHIDUserDevice.h>

@implementation HIDUserDevice {
    IOHIDUserDeviceRef              _device;
    dispatch_queue_t                _queue;
    HIDUserDeviceGetReportHandler   _getReportHandler;
    HIDUserDeviceSetReportHandler   _setReportHandler;
    io_service_t                    _service;
}

- (nullable instancetype)initWithProperties:(nonnull NSDictionary *)properties
{
    self = [super init];
    
    if (!self) {
        return self;
    }
    
    _device = IOHIDUserDeviceCreate(kCFAllocatorDefault,
                                    (__bridge CFDictionaryRef)properties);
    if (!_device) {
        return nil;
    }
    
    _service = IOHIDUserDeviceCopyService(_device);
    
    return self;
}

- (void)dealloc
{
    if (_service) {
        IOObjectRelease(_service);
    }
    if (_device) {
        CFRelease(_device);
    }
}

- (BOOL)isEqualToHIDUserDevice:(HIDUserDevice *)device {
    if (!device) {
        return NO;
    }
    
    if (self->_device != device->_device) {
        return NO;
    }
    
    return YES;
}

- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    }
    
    if (![object isKindOfClass:[HIDUserDevice class]]) {
        return NO;
    }
    
    return [self isEqualToHIDUserDevice:(HIDUserDevice *)object];
}

- (NSString *)description {
    return [NSString stringWithFormat:@"%@", _device];
}

- (void)setCancelHandler:(nonnull dispatch_block_t __unused) handler
{
    //IOHIDUserDeviceSetCancelHandler(_device, handler);
}

- (void)setDispatchQueue:(nonnull dispatch_queue_t)queue
{
    assert(!_queue);
    _queue = queue;
}

- (void)activate
{
    assert(_queue);
    IOHIDUserDeviceScheduleWithDispatchQueue(_device, _queue);
}

- (void)cancel
{
    assert(_queue);
    IOHIDUserDeviceUnscheduleFromDispatchQueue(_device, _queue);
}

static IOReturn getReportCallback(void *refcon, IOHIDReportType type,
                                  uint32_t reportID, uint8_t *report,
                                  CFIndex *reportLength)
{
    NSUInteger length = (NSUInteger)*reportLength;
    IOReturn ret;
    HIDUserDevice *me = (__bridge HIDUserDevice *)refcon;
    
    ret = (me->_getReportHandler)(type, reportID, report, &length);
    *reportLength = (CFIndex)length;
    
    return ret;
}

- (void)setGetReportHandler:(nonnull HIDUserDeviceGetReportHandler)handler
{
    assert(!_getReportHandler);
    _getReportHandler = handler;
    
    IOHIDUserDeviceRegisterGetReportWithReturnLengthCallback(
                                                        _device,
                                                        getReportCallback,
                                                        (__bridge void *)self);
}

static IOReturn setReportCallback(void *refcon, IOHIDReportType type,
                                  uint32_t reportID, uint8_t *report,
                                  CFIndex reportLength)
{
    HIDUserDevice *me = (__bridge HIDUserDevice *)refcon;
    return (me->_setReportHandler)(type,
                                   reportID,
                                   report,
                                   (NSUInteger)reportLength);
}

- (void)setSetReportHandler:(nonnull HIDUserDeviceSetReportHandler)handler
{
    assert(!_setReportHandler);
    _setReportHandler = handler;
    IOHIDUserDeviceRegisterSetReportCallback(_device,
                                             setReportCallback,
                                             (__bridge void *)self);
}

- (IOReturn)handleReport:(nonnull uint8_t *)report
            reportLength:(NSInteger)reportLength
{
    return IOHIDUserDeviceHandleReport(_device, report, reportLength);
}

- (io_service_t)service
{
    return _service;
}

@end