X-Git-Url: https://git.yukkurigames.com/?p=enjoyable.git;a=blobdiff_plain;f=JoystickController.m;h=51c2a378d33f5473bbf03842a679456f340be085;hp=b510848f89bea27c42d2f4712392be06803055ef;hb=d2b45b2c32dcc7c3cc553b62252ca48842e08d48;hpb=530009447c5bbd360ac5023979cffc6d32a28df3 diff --git a/JoystickController.m b/JoystickController.m index b510848..51c2a37 100644 --- a/JoystickController.m +++ b/JoystickController.m @@ -5,32 +5,35 @@ // Created by Sam McCall on 4/05/09. // +#import "CoreFoundation/CoreFoundation.h" + @implementation JoystickController -@synthesize joysticks, selectedAction; +@synthesize joysticks, runningTargets, selectedAction, frontWindowOnly; -(id) init { if(self=[super init]) { joysticks = [[NSMutableArray alloc]init]; + runningTargets = [[NSMutableArray alloc]init]; programmaticallySelecting = NO; + mouseLoc.x = mouseLoc.y = 0; } return self; } --(void) finalize { +-(void) dealloc { for(int i=0; i<[joysticks count]; i++) { - [[joysticks objectAtIndex:i] invalidate]; + [joysticks[i] invalidate]; } IOHIDManagerClose(hidManager, kIOHIDOptionsTypeNone); CFRelease(hidManager); - [super finalize]; } static NSMutableDictionary* create_criterion( UInt32 inUsagePage, UInt32 inUsage ) { NSMutableDictionary* dict = [[NSMutableDictionary alloc] init]; - [dict setObject: [NSNumber numberWithInt: inUsagePage] forKey: (NSString*)CFSTR(kIOHIDDeviceUsagePageKey)]; - [dict setObject: [NSNumber numberWithInt: inUsage] forKey: (NSString*)CFSTR(kIOHIDDeviceUsageKey)]; + dict[(NSString*)CFSTR(kIOHIDDeviceUsagePageKey)] = @(inUsagePage); + dict[(NSString*)CFSTR(kIOHIDDeviceUsageKey)] = @(inUsage); return dict; } @@ -40,13 +43,20 @@ static NSMutableDictionary* create_criterion( UInt32 inUsagePage, UInt32 inUsage [outlineView expandItem: handler]; } -void input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef value) { - JoystickController* self = (JoystickController*)inContext; - IOHIDDeviceRef device = IOHIDQueueGetDevice((IOHIDQueueRef) inSender); +static void timer_callback(CFRunLoopTimerRef timer, void *ctx) { + JoystickController *jc = (__bridge JoystickController *)ctx; + jc->mouseLoc = [NSEvent mouseLocation]; + for (Target *target in [jc runningTargets]) { + [target update: jc]; + } +} + +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]; - if([[[NSApplication sharedApplication] delegate] active]) { - // for reals + Joystick *js = [controller findJoystickByRef:device]; + if([(ApplicationController *)[[NSApplication sharedApplication] delegate] active]) { JSAction* mainAction = [js actionForEvent: value]; if(!mainAction) return; @@ -54,15 +64,34 @@ void input_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDVal [mainAction notifyEvent: value]; NSArray* subactions = [mainAction subActions]; if(!subactions) - subactions = [NSArray arrayWithObject:mainAction]; + 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 */ - [target setRunning: [subaction active]]; - [target setInputValue: IOHIDValueGetIntegerValue(value)]; + if ([target running] != [subaction active]) { + if ([subaction active]) { + [target trigger: controller]; + } + else { + [target untrigger: controller]; + } + [target setRunning: [subaction active]]; + } + + if ([mainAction isKindOfClass: [JSActionAnalog class]]) { + double realValue = [(JSActionAnalog*)mainAction getRealValue: IOHIDValueGetIntegerValue(value)]; + [target setInputValue: realValue]; + + // Add to list of running targets + if ([target isContinuous] && [target running]) { + if (![controller.runningTargets containsObject:target]) { + [[controller runningTargets] addObject: target]; + } + } + } } } else if([[NSApplication sharedApplication] isActive] && [[[NSApplication sharedApplication]mainWindow]isVisible]) { // joysticks not active, use it to select stuff @@ -70,19 +99,19 @@ 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++) { available = YES; for(int i=0; i<[list count]; i++) { - js2 = [list objectAtIndex: i]; + js2 = list[i]; if([js2 vendorId] == [js vendorId] && [js2 productId] == [js productId] && [js index] == index) { available = NO; break; @@ -93,60 +122,57 @@ int findAvailableIndex(id list, Joystick* js) { } } -void add_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef device) { - JoystickController* self = (JoystickController*)inContext; - - IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); - IOHIDDeviceRegisterInputValueCallback(device, input_callback, (void*) 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 { - for(int i=0; i<[joysticks count]; i++) - if([[joysticks objectAtIndex:i] device] == device) - return [joysticks objectAtIndex:i]; - return NULL; +- (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 = (JoystickController*)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 = [NSArray arrayWithObjects: - create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick), - create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad), - create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController), - create_criterion(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard), - nil]; - - IOHIDManagerSetDeviceMatchingMultiple(hidManager, (CFArrayRef)criteria); + 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)); + IOHIDManagerScheduleWithRunLoop( hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); IOReturn tIOReturn = IOHIDManagerOpen( hidManager, kIOHIDOptionsTypeNone ); (void)tIOReturn; - IOHIDManagerRegisterDeviceMatchingCallback( hidManager, add_callback, (void*)self ); - IOHIDManagerRegisterDeviceRemovalCallback(hidManager, remove_callback, (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 + }; + CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, + CFAbsoluteTimeGetCurrent(), 1.0/80.0, + 0, 0, timer_callback, &ctx); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); } -(id) determineSelectedAction { @@ -184,13 +210,13 @@ void remove_callback(void* inContext, IOReturn inResult, void* inSender, IOHIDDe - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item { if(item == nil) - return [joysticks objectAtIndex: index]; + return joysticks[index]; if([item isKindOfClass: [Joystick class]]) - return [[item children] objectAtIndex: index]; + return [item children][index]; if([item isKindOfClass: [JSAction class]]) - return [[item subActions] objectAtIndex:index]; + return [item subActions][index]; return NULL; }