HIDEventSystemClient.m   [plain text]

//
// HIDEventSystemClient.m
// HID
//
// Created by dekom on 12/20/17.
//

#import "HIDEventSystemClient.h"
#import "HIDEventSystemClientPrivate.h"
#import <IOKit/hid/IOHIDEventSystemClient.h>
#import <IOKit/hid/IOHIDLibPrivate.h>
#import "HIDEvent.h"
#import <os/assumes.h>

@implementation HIDEventSystemClient {
IOHIDEventSystemClientRef _client;

HIDEventHandler _eventHandler;
HIDBlock _resetHandler;
HIDEventFilterHandler _filterHandler;
HIDServiceHandler _serviceHandler;
HIDPropertyChangedHandler _propertyChangedHandler;
HIDBlock _cancelHandler;
}

- (nullable instancetype)initWithType:(HIDEventSystemClientType)type
{
return [self initWithType:type andAttributes:nil];
}

- (nullable instancetype)initWithType:(HIDEventSystemClientType)type andAttributes:(NSDictionary*) attributes
{
IOHIDEventSystemClientType clientType = (IOHIDEventSystemClientType)type;
self = [super init];

if (!self) {
return self;
}
self->_client = IOHIDEventSystemClientCreateWithType(kCFAllocatorDefault,
clientType,
(__bridge CFDictionaryRef)attributes);
if (!_client) {
return nil;
}

return self;
}

- (void)dealloc
{
if (_client) {
CFRelease(_client);
}
}

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

- (id)propertyForKey:(NSString *)key
{
return (id)CFBridgingRelease(IOHIDEventSystemClientCopyProperty(
_client,
(__bridge CFStringRef)key));
}

- (BOOL)setProperty:(id)value forKey:(NSString *)key
{
return IOHIDEventSystemClientSetProperty(_client,
(__bridge CFStringRef)key,
(__bridge CFTypeRef)value);
}
- (void)setMatching:(id)matching
{
os_assert([matching isKindOfClass:[NSDictionary class]] ||
[matching isKindOfClass:[NSArray class]],
"Unknown matching criteria: %@", matching);

if ([matching isKindOfClass:[NSDictionary class]]) {
CFDictionaryRef matchDict = (__bridge CFDictionaryRef)matching;

if (((NSDictionary *)matching).count) {
IOHIDEventSystemClientSetMatching(_client, matchDict);
} else {
IOHIDEventSystemClientSetMatching(_client, nil);
}
} else if ([matching isKindOfClass:[NSArray class]]) {
CFArrayRef matchArray = (__bridge CFArrayRef)matching;

if (((NSArray *)matching).count) {
IOHIDEventSystemClientSetMatchingMultiple(_client, matchArray);
} else {
IOHIDEventSystemClientSetMatchingMultiple(_client, nil);
}
}
}

- (NSArray<HIDServiceClient *> *)services
{
return (NSArray *)CFBridgingRelease(
IOHIDEventSystemClientCopyServices(_client));
}

- (void)setCancelHandler:(HIDBlock)handler
{
_cancelHandler = handler;
}

- (void)setDispatchQueue:(dispatch_queue_t)queue
{
IOHIDEventSystemClientSetDispatchQueue(_client, queue);
}

static void _eventCallback(void *target,
void *refcon __unused,
void *sender,
IOHIDEventRef event)
{
HIDEventSystemClient *me = (__bridge HIDEventSystemClient *)target;

(me->_eventHandler)((__bridge HIDServiceClient *)sender,
(__bridge HIDEvent *)event);
}

- (void)setEventHandler:(HIDEventHandler)handler
{
os_assert(!_eventHandler, "Event handler already set");
_eventHandler = handler;
IOHIDEventSystemClientRegisterEventCallback(_client,
_eventCallback,
(__bridge void *)self,
nil);
}

static void _resetCallback(void *target, void *context __unused)
{
HIDEventSystemClient *me = (__bridge HIDEventSystemClient *)target;

(me->_resetHandler)();
}

- (void)setResetHandler:(HIDBlock)handler
{
os_assert(!_resetHandler, "Reset handler already set");
_resetHandler = handler;
IOHIDEventSystemClientRegisterResetCallback(_client,
_resetCallback,
(__bridge void *)self,
nil);
}

static boolean_t _eventFilterCallback(void *target,
void *refcon __unused,
void *sender,
IOHIDEventRef event)
{
HIDEventSystemClient *me = (__bridge HIDEventSystemClient *)target;

return (me->_filterHandler)((__bridge HIDServiceClient *)sender,
(__bridge HIDEvent *)event);
}

- (void)setEventFilterHandler:(HIDEventFilterHandler)handler
{
os_assert(!_filterHandler, "Filter handler already set");
_filterHandler = handler;
IOHIDEventSystemClientRegisterEventFilterCallback(_client,
_eventFilterCallback,
(__bridge void *)self,
nil);
}

static void _serviceCallback(void *target,
void *refcon __unused,
IOHIDServiceClientRef service)
{
HIDEventSystemClient *me = (__bridge HIDEventSystemClient *)target;

(me->_serviceHandler)((__bridge HIDServiceClient *)service);
}

- (void)setServiceNotificationHandler:(HIDServiceHandler)handler
{
os_assert(!_serviceHandler, "Service notification handler already set");
_serviceHandler = handler;
IOHIDEventSystemClientRegisterDeviceMatchingCallback(_client,
_serviceCallback,
(__bridge void *)self,
nil);
}

static void _propertiesChangedCallback(void *target,
void *context __unused,
CFStringRef property,
CFTypeRef value)
{
HIDEventSystemClient *me = (__bridge HIDEventSystemClient *)target;

(me->_propertyChangedHandler)((__bridge NSString *)property,
(__bridge id)value);
}

- (void)setPropertyChangedHandler:(HIDPropertyChangedHandler)handler
matching:(id)matching
{
os_assert([matching isKindOfClass:[NSString class]] ||
[matching isKindOfClass:[NSArray class]],
"Unknown matching criteria: %@", matching);

os_assert(!_propertyChangedHandler, "Property changed handler already set");
_propertyChangedHandler = handler;

if ([matching isKindOfClass:[NSString class]]) {
CFStringRef matchString = (__bridge CFStringRef)matching;
IOHIDEventSystemClientRegisterPropertyChangedCallback(
_client,
matchString,
_propertiesChangedCallback,
(__bridge void *)self,
nil);
} else if ([matching isKindOfClass:[NSArray class]]) {
for (NSString *match in matching) {
CFStringRef matchString = (__bridge CFStringRef)match;

IOHIDEventSystemClientRegisterPropertyChangedCallback(
_client,
matchString,
_propertiesChangedCallback,
(__bridge void *)self,
nil);
}
}
}

- (void)activate
{
IOHIDEventSystemClientSetCancelHandler(_client, ^{
// Block captures reference to self while cancellation hasn't completed.
if (self->_cancelHandler) {
self->_cancelHandler();
self->_cancelHandler = nil;
}
});

IOHIDEventSystemClientActivate(_client);
}

- (void)cancel
{
IOHIDEventSystemClientCancel(_client);
}

- (IOHIDEventSystemClientRef) client
{
return _client;
}
@end