From d2b45b2c32dcc7c3cc553b62252ca48842e08d48 Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Tue, 26 Feb 2013 22:05:34 +0100 Subject: [PATCH] Switch controller/HID bridging to non-retained since the controller lives as long as the app delegate. Do not manually open and close HID devices; the HID manager does this and a manual close therefore causes a double-close and crash when a device is removed. Some reformatting, and make the joystick display name a virtual readonly attribute. --- Joystick.h | 25 ++++-------- Joystick.m | 36 ++++++----------- JoystickController.m | 96 ++++++++++++++++++-------------------------- 3 files changed, 59 insertions(+), 98 deletions(-) diff --git a/Joystick.h b/Joystick.h index 587ad3f..99587a7 100644 --- a/Joystick.h +++ b/Joystick.h @@ -9,26 +9,17 @@ #import @class JSAction; -@interface Joystick : NSObject { - int vendorId; - int productId; - int index; - NSString* productName; - IOHIDDeviceRef device; - NSMutableArray* children; - NSString* name; -} +@interface Joystick : NSObject -@property(readwrite) int vendorId; -@property(readwrite) int productId; -@property(readwrite) int index; -@property(readwrite, copy) NSString* productName; -@property(readwrite) IOHIDDeviceRef device; -@property(readonly) NSArray* children; -@property(readonly) NSString* name; +@property (assign) int vendorId; +@property (assign) int productId; +@property (assign) int index; +@property (copy) NSString *productName; +@property (assign) IOHIDDeviceRef device; +@property (readonly) NSArray *children; +@property (readonly) NSString *name; -(void) populateActions; --(void) invalidate; -(id) handlerForEvent: (IOHIDValueRef) value; -(id)initWithDevice: (IOHIDDeviceRef) newDevice; -(JSAction*) actionForEvent: (IOHIDValueRef) value; diff --git a/Joystick.m b/Joystick.m index d6c4362..2d50fa4 100644 --- a/Joystick.m +++ b/Joystick.m @@ -5,36 +5,26 @@ // Created by Sam McCall on 4/05/09. // -@implementation Joystick - +@implementation Joystick { + NSMutableArray *children; +} -@synthesize vendorId, productId, productName, name, index, device, children; +@synthesize vendorId, productId, productName, index, device, children; --(id)initWithDevice: (IOHIDDeviceRef) newDevice { - if(self=[super init]) { - children = [[NSMutableArray alloc]init]; - - device = newDevice; - productName = (__bridge NSString*)IOHIDDeviceGetProperty( device, CFSTR(kIOHIDProductKey) ); - vendorId = [(__bridge NSNumber*)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)) intValue]; - productId = [(__bridge NSNumber*)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)) intValue]; +- (id)initWithDevice: (IOHIDDeviceRef) newDevice { + if ((self = [super init])) { + children = [[NSMutableArray alloc] init]; - name = productName; + self.device = newDevice; + self.productName = (__bridge NSString *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); + self.vendorId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)) intValue]; + self.productId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)) intValue]; } return self; } --(void) setIndex: (int) newIndex { - index = newIndex; - name = [[NSString alloc] initWithFormat: @"%@ #%d", productName, (index+1)]; -} --(int) index { - return index; -} - --(void) invalidate { - IOHIDDeviceClose(device, kIOHIDOptionsTypeNone); - NSLog(@"Removed a device: %@", [self name]); +- (NSString *)name { + return [[NSString alloc] initWithFormat: @"%@ #%d", productName, index + 1]; } -(id) base { diff --git a/JoystickController.m b/JoystickController.m index 5056b0e..51c2a37 100644 --- a/JoystickController.m +++ b/JoystickController.m @@ -43,15 +43,7 @@ static NSMutableDictionary* create_criterion( UInt32 inUsagePage, UInt32 inUsage [outlineView expandItem: handler]; } -BOOL objInArray(NSMutableArray *array, id object) { - for (id o in array) { - if (o == object) - return true; - } - return false; -} - -void timer_callback(CFRunLoopTimerRef timer, void *ctx) { +static void timer_callback(CFRunLoopTimerRef timer, void *ctx) { JoystickController *jc = (__bridge JoystickController *)ctx; jc->mouseLoc = [NSEvent mouseLocation]; for (Target *target in [jc runningTargets]) { @@ -59,13 +51,12 @@ void timer_callback(CFRunLoopTimerRef timer, void *ctx) { } } -void input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef value) { - JoystickController* self = (__bridge JoystickController*)inContext; - IOHIDDeviceRef device = IOHIDQueueGetDevice((IOHIDQueueRef) inSender); +static void input_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDValueRef value) { + JoystickController *controller = (__bridge JoystickController *)ctx; + IOHIDDeviceRef device = IOHIDQueueGetDevice(inSender); - Joystick* js = [self findJoystickByRef: device]; + Joystick *js = [controller findJoystickByRef:device]; if([(ApplicationController *)[[NSApplication sharedApplication] delegate] active]) { - // for reals JSAction* mainAction = [js actionForEvent: value]; if(!mainAction) return; @@ -75,17 +66,17 @@ void input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDVal if(!subactions) subactions = @[mainAction]; for(id subaction in subactions) { - Target* target = [[self->configsController currentConfig] getTargetForAction:subaction]; + Target* target = [[controller->configsController currentConfig] getTargetForAction:subaction]; if(!target) continue; /* target application? doesn't seem to be any need since we are only active when it's in front */ /* might be required for some strange actions */ if ([target running] != [subaction active]) { if ([subaction active]) { - [target trigger: self]; + [target trigger: controller]; } else { - [target untrigger: self]; + [target untrigger: controller]; } [target setRunning: [subaction active]]; } @@ -96,8 +87,8 @@ void input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDVal // Add to list of running targets if ([target isContinuous] && [target running]) { - if (!objInArray([self runningTargets], target)) { - [[self runningTargets] addObject: target]; + if (![controller.runningTargets containsObject:target]) { + [[controller runningTargets] addObject: target]; } } } @@ -108,13 +99,13 @@ void input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDVal if(!handler) return; - [self expandRecursive: handler]; - self->programmaticallySelecting = YES; - [self->outlineView selectRowIndexes: [NSIndexSet indexSetWithIndex: [self->outlineView rowForItem: handler]] byExtendingSelection: NO]; + [controller expandRecursive: handler]; + controller->programmaticallySelecting = YES; + [controller->outlineView selectRowIndexes: [NSIndexSet indexSetWithIndex: [controller->outlineView rowForItem: handler]] byExtendingSelection: NO]; } } -int findAvailableIndex(id list, Joystick* js) { +static int findAvailableIndex(id list, Joystick* js) { BOOL available; Joystick* js2; for(int index=0;;index++) { @@ -131,46 +122,39 @@ int findAvailableIndex(id list, Joystick* js) { } } -void add_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef device) { - JoystickController* self = (__bridge JoystickController*)inContext; - - IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); - IOHIDDeviceRegisterInputValueCallback(device, input_callback, (void*) CFBridgingRetain(self)); - - Joystick *js = [[Joystick alloc] initWithDevice: device]; - [js setIndex: findAvailableIndex([self joysticks], js)]; - +static void add_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) { + JoystickController *controller = (__bridge JoystickController *)ctx; + IOHIDDeviceRegisterInputValueCallback(device, input_callback, (__bridge void*)controller); + Joystick *js = [[Joystick alloc] initWithDevice:device]; + js.index = findAvailableIndex(controller.joysticks, js); [js populateActions]; - - [[self joysticks] addObject: js]; - [self->outlineView reloadData]; + [[controller joysticks] addObject:js]; + [controller->outlineView reloadData]; } --(Joystick*) findJoystickByRef: (IOHIDDeviceRef) device { +- (Joystick *)findJoystickByRef:(IOHIDDeviceRef)device { for (Joystick *js in joysticks) if (js.device == device) return js; return nil; } -void remove_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef device) { - JoystickController* self = CFBridgingRelease(inContext); - - Joystick* match = [self findJoystickByRef: device]; - if(!match) - return; - - [[self joysticks] removeObject: match]; - - [match invalidate]; - [self->outlineView reloadData]; +static void remove_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) { + JoystickController *controller = (__bridge JoystickController *)ctx; + Joystick *match = [controller findJoystickByRef:device]; + IOHIDDeviceRegisterInputValueCallback(device, NULL, NULL); + if (match) { + [controller.joysticks removeObject:match]; + [controller->outlineView reloadData]; + } } --(void) setup { +- (void)setup { hidManager = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone); - NSArray *criteria = @[create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick), - create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad), - create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController)]; + NSArray *criteria = @[ + create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick), + create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad), + create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController)]; IOHIDManagerSetDeviceMatchingMultiple(hidManager, (CFArrayRef)CFBridgingRetain(criteria)); @@ -178,13 +162,9 @@ void remove_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDDe IOReturn tIOReturn = IOHIDManagerOpen( hidManager, kIOHIDOptionsTypeNone ); (void)tIOReturn; - IOHIDManagerRegisterDeviceMatchingCallback( hidManager, add_callback, (__bridge void*)self ); - IOHIDManagerRegisterDeviceRemovalCallback(hidManager, remove_callback, (__bridge void*) self); -// IOHIDManagerRegisterInputValueCallback(hidManager, input_callback, (void*)self); -// register individually so we can find the device more easily - - - + IOHIDManagerRegisterDeviceMatchingCallback(hidManager, add_callback, (__bridge void *)self ); + IOHIDManagerRegisterDeviceRemovalCallback(hidManager, remove_callback, (__bridge void *)self); + // Setup timer for continuous targets CFRunLoopTimerContext ctx = { 0, (__bridge void*)self, NULL, NULL, NULL -- 2.20.1