Split actual IOKit HID interfacing off from NJDeviceController.
[enjoyable.git] / Classes / NJHIDManager.m
diff --git a/Classes/NJHIDManager.m b/Classes/NJHIDManager.m
new file mode 100644 (file)
index 0000000..2a139df
--- /dev/null
@@ -0,0 +1,99 @@
+//
+//  NJHIDManager.m
+//  Enjoyable
+//
+//  Created by Joe Wreschnig on 3/13/13.
+//
+//
+
+#import "NJHIDManager.h"
+
+@implementation NJHIDManager {
+    NSArray *_criteria;
+    IOHIDManagerRef _manager;
+}
+
+- (id)initWithCriteria:(NSArray *)criteria
+              delegate:(id <NJHIDManagerDelegate>)delegate
+{
+    if ((self = [super init])) {
+        self.criteria = criteria;
+        self.delegate = delegate;
+    }
+    return self;
+}
+
+- (void)dealloc {
+    [self stop];
+}
+
+static void input_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDValueRef value) {
+    NJHIDManager *self = (__bridge NJHIDManager *)ctx;
+    IOHIDDeviceRef device = IOHIDQueueGetDevice(inSender);
+    [self.delegate hidManager:self valueChanged:value fromDevice:device];
+}
+
+static void add_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) {
+    NJHIDManager *self = (__bridge NJHIDManager *)ctx;
+    [self.delegate hidManager:self deviceAdded:device];
+    IOHIDDeviceRegisterInputValueCallback(device, input_callback, ctx);
+}
+
+static void remove_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) {
+    NJHIDManager *self = (__bridge NJHIDManager *)ctx;
+    [self.delegate hidManager:self deviceRemoved:device];
+}
+
+- (void)start {
+    if (self.running)
+        return;
+    IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+    IOHIDManagerSetDeviceMatchingMultiple(manager, (__bridge CFArrayRef)self.criteria);
+    IOReturn ret = IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone);
+    if (ret != kIOReturnSuccess) {
+        NSError *error = [NSError errorWithDomain:NSMachErrorDomain code:ret userInfo:nil];
+        IOHIDManagerClose(manager, kIOHIDOptionsTypeNone);
+        CFRelease(manager);
+        [self.delegate hidManager:self didError:error];
+    } else {
+        _manager = manager;
+        IOHIDManagerScheduleWithRunLoop(_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+        IOHIDManagerRegisterDeviceMatchingCallback(_manager, add_callback, (__bridge void *)self);
+        IOHIDManagerRegisterDeviceRemovalCallback(_manager, remove_callback, (__bridge void *)self);
+        [self.delegate hidManagerDidStart:self];
+        NSLog(@"Started HID manager.");
+    }
+}
+
+- (void)stop {
+    if (!self.running)
+        return;
+    IOHIDManagerUnscheduleFromRunLoop(_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDManagerClose(_manager, kIOHIDOptionsTypeNone);
+    CFRelease(_manager);
+    _manager = NULL;
+    [self.delegate hidManagerDidStop:self];
+    NSLog(@"Stopped HID manager.");
+}
+
+- (BOOL)running {
+    return !!_manager;
+}
+
+- (NSArray *)criteria {
+    return _criteria;
+}
+
+- (void)setCriteria:(NSArray *)criteria {
+    if (!criteria)
+        criteria = @[];
+    if (![criteria isEqualToArray:_criteria]) {
+        BOOL running = !!_manager;
+        [self stop];
+        _criteria = [criteria copy];
+        if (running)
+            [self start];
+    }    
+}
+
+@end