Restore application if an error occurs.
[enjoyable.git] / Classes / NJHIDManager.m
1 //
2 // NJHIDManager.m
3 // Enjoyable
4 //
5 // Created by Joe Wreschnig on 3/13/13.
6 //
7 //
8
9 #import "NJHIDManager.h"
10
11 @implementation NJHIDManager {
12 NSArray *_criteria;
13 IOHIDManagerRef _manager;
14 }
15
16 - (id)initWithCriteria:(NSArray *)criteria
17 delegate:(id <NJHIDManagerDelegate>)delegate
18 {
19 if ((self = [super init])) {
20 self.criteria = criteria;
21 self.delegate = delegate;
22 }
23 return self;
24 }
25
26 - (void)dealloc {
27 [self stop];
28 }
29
30 static void input_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDValueRef value) {
31 NJHIDManager *self = (__bridge NJHIDManager *)ctx;
32 IOHIDDeviceRef device = IOHIDQueueGetDevice(inSender);
33 [self.delegate hidManager:self valueChanged:value fromDevice:device];
34 }
35
36 static void add_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) {
37 NJHIDManager *self = (__bridge NJHIDManager *)ctx;
38 [self.delegate hidManager:self deviceAdded:device];
39 IOHIDDeviceRegisterInputValueCallback(device, input_callback, ctx);
40 }
41
42 static void remove_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) {
43 NJHIDManager *self = (__bridge NJHIDManager *)ctx;
44 [self.delegate hidManager:self deviceRemoved:device];
45 }
46
47 - (void)start {
48 if (self.running)
49 return;
50 IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
51 IOHIDManagerSetDeviceMatchingMultiple(manager, (__bridge CFArrayRef)self.criteria);
52 IOReturn ret = IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone);
53 if (ret != kIOReturnSuccess) {
54 NSError *error = [NSError errorWithDomain:NSMachErrorDomain code:ret userInfo:nil];
55 IOHIDManagerClose(manager, kIOHIDOptionsTypeNone);
56 CFRelease(manager);
57 [self.delegate hidManager:self didError:error];
58 NSLog(@"Error starting HID manager: %@.", error);
59 } else {
60 _manager = manager;
61 IOHIDManagerScheduleWithRunLoop(_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
62 IOHIDManagerRegisterDeviceMatchingCallback(_manager, add_callback, (__bridge void *)self);
63 IOHIDManagerRegisterDeviceRemovalCallback(_manager, remove_callback, (__bridge void *)self);
64 [self.delegate hidManagerDidStart:self];
65 NSLog(@"Started HID manager.");
66 }
67 }
68
69 - (void)stop {
70 if (!self.running)
71 return;
72 IOHIDManagerUnscheduleFromRunLoop(_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
73 IOHIDManagerClose(_manager, kIOHIDOptionsTypeNone);
74 CFRelease(_manager);
75 _manager = NULL;
76 [self.delegate hidManagerDidStop:self];
77 NSLog(@"Stopped HID manager.");
78 }
79
80 - (BOOL)running {
81 return !!_manager;
82 }
83
84 - (NSArray *)criteria {
85 return _criteria;
86 }
87
88 - (void)setCriteria:(NSArray *)criteria {
89 if (!criteria)
90 criteria = @[];
91 if (![criteria isEqualToArray:_criteria]) {
92 BOOL running = !!_manager;
93 [self stop];
94 _criteria = [criteria copy];
95 if (running)
96 [self start];
97 }
98 }
99
100 @end