// 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;
}
[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;
[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
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;
}
}
-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 {
- (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;
}