#import "JoystickController.h"
-#import "ApplicationController.h"
#import "Config.h"
#import "ConfigsController.h"
#import "Joystick.h"
@implementation JoystickController {
IOHIDManagerRef hidManager;
- BOOL programmaticallySelecting;
NSTimer *continuousTimer;
+ NSMutableArray *runningTargets;
+ NSMutableArray *_joysticks;
}
-@synthesize joysticks;
-@synthesize runningTargets;
-@synthesize selectedAction;
-@synthesize frontWindowOnly;
-@synthesize mouseLoc;
-
- (id)init {
if ((self = [super init])) {
- joysticks = [[NSMutableArray alloc] initWithCapacity:16];
+ _joysticks = [[NSMutableArray alloc] initWithCapacity:16];
runningTargets = [[NSMutableArray alloc] initWithCapacity:32];
}
return self;
CFRelease(hidManager);
}
-- (void)expandRecursive:(id)handler {
- if ([handler base])
- [self expandRecursive:[handler base]];
- [outlineView expandItem:handler];
+- (void)expandRecursive:(id <NJActionPathElement>)pathElement {
+ if (pathElement) {
+ [self expandRecursive:pathElement.base];
+ [outlineView expandItem:pathElement];
+ }
}
- (void)addRunningTarget:(Target *)target {
- if (![runningTargets containsObject:target])
+ if (![runningTargets containsObject:target]) {
[runningTargets addObject:target];
+ }
if (!continuousTimer) {
continuousTimer = [NSTimer scheduledTimerWithTimeInterval:1.f/60.f
target:self
}
}
+- (void)runTargetForDevice:(IOHIDDeviceRef)device value:(IOHIDValueRef)value {
+ Joystick *js = [self findJoystickByRef:device];
+ JSAction *mainAction = [js actionForEvent:value];
+ [mainAction notifyEvent:value];
+ NSArray *children = mainAction.children ? mainAction.children : mainAction ? @[mainAction] : @[];
+ for (JSAction *subaction in children) {
+ Target *target = configsController.currentConfig[subaction];
+ target.magnitude = mainAction.magnitude;
+ target.running = subaction.active;
+ if (target.running && target.isContinuous)
+ [self addRunningTarget:target];
+ }
+}
+
+- (void)showTargetForDevice:(IOHIDDeviceRef)device value:(IOHIDValueRef)value {
+ Joystick *js = [self findJoystickByRef:device];
+ JSAction *handler = [js handlerForEvent:value];
+ if (!handler)
+ return;
+
+ [self expandRecursive:handler];
+ [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[outlineView rowForItem:handler]] byExtendingSelection: NO];
+ [targetController focusKey];
+}
+
static void input_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDValueRef value) {
JoystickController *controller = (__bridge JoystickController *)ctx;
IOHIDDeviceRef device = IOHIDQueueGetDevice(inSender);
- Joystick *js = [controller findJoystickByRef:device];
- if (((ApplicationController *)[NSApplication sharedApplication].delegate).active) {
- JSAction *mainAction = [js actionForEvent:value];
- [mainAction notifyEvent:value];
- NSArray *children = mainAction.children ? mainAction.children : mainAction ? @[mainAction] : @[];
- for (JSAction *subaction in children) {
- Target *target = controller.currentConfig[subaction];
- target.magnitude = mainAction.magnitude;
- target.running = subaction.active;
- if (target.running && target.isContinuous)
- [controller addRunningTarget:target];
- }
- } else if ([NSApplication sharedApplication].isActive
- && [NSApplication sharedApplication].mainWindow.isVisible) {
- // joysticks not active, use it to select stuff
- JSAction *handler = [js handlerForEvent:value];
- if (!handler)
- return;
-
- [controller expandRecursive:handler];
- controller->programmaticallySelecting = YES;
- [controller->outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[controller->outlineView rowForItem:handler]] byExtendingSelection: NO];
+ if (controller.sendingRealEvents) {
+ [controller runTargetForDevice:device value:value];
+ } else if ([NSApplication sharedApplication].mainWindow.isVisible) {
+ [controller showTargetForDevice:device value:value];
}
}
}
}
+- (void)addJoystickForDevice:(IOHIDDeviceRef)device {
+ IOHIDDeviceRegisterInputValueCallback(device, input_callback, (__bridge void*)self);
+ Joystick *js = [[Joystick alloc] initWithDevice:device];
+ js.index = findAvailableIndex(_joysticks, js);
+ [_joysticks addObject:js];
+ [outlineView reloadData];
+}
+
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);
- [[controller joysticks] addObject:js];
- [controller->outlineView reloadData];
+ [controller addJoystickForDevice:device];
}
- (Joystick *)findJoystickByRef:(IOHIDDeviceRef)device {
- for (Joystick *js in joysticks)
+ for (Joystick *js in _joysticks)
if (js.device == device)
return js;
return nil;
static void remove_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDDeviceRef device) {
JoystickController *controller = (__bridge JoystickController *)ctx;
- Joystick *match = [controller findJoystickByRef:device];
+ [controller removeJoystickForDevice:device];
+}
+
+- (void)removeJoystickForDevice:(IOHIDDeviceRef)device {
+ Joystick *match = [self findJoystickByRef:device];
IOHIDDeviceRegisterInputValueCallback(device, NULL, NULL);
if (match) {
- [controller.joysticks removeObject:match];
- [controller->outlineView reloadData];
+ [_joysticks removeObject:match];
+ [outlineView reloadData];
}
+
}
- (void)updateContinuousActions:(NSTimer *)timer {
self.mouseLoc = [NSEvent mouseLocation];
- for (Target *target in [self.runningTargets copy]) {
- if (![target update:self])
- [self.runningTargets removeObject:target];
+ for (Target *target in [runningTargets copy]) {
+ if (![target update:self]) {
+ [runningTargets removeObject:target];
+ }
}
- if (!self.runningTargets.count) {
+ if (!runningTargets.count) {
[continuousTimer invalidate];
continuousTimer = nil;
NSLog(@"Unscheduled continuous target timer.");
IOHIDManagerSetDeviceMatchingMultiple(hidManager, (__bridge CFArrayRef)criteria);
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); // FIXME: If an error happens, report it!
+ IOReturn ret = IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
+ if (ret != kIOReturnSuccess) {
+ [[NSAlert alertWithMessageText:@"Input devices are unavailable"
+ defaultButton:nil
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:@"Error 0x%08x occured trying to access your devices. "
+ @"Input may not be correctly detected or mapped.",
+ ret]
+ beginSheetModalForWindow:outlineView.window
+ modalDelegate:nil
+ didEndSelector:nil
+ contextInfo:nil];
+ }
IOHIDManagerRegisterDeviceMatchingCallback(hidManager, add_callback, (__bridge void *)self);
IOHIDManagerRegisterDeviceRemovalCallback(hidManager, remove_callback, (__bridge void *)self);
}
-- (Config *)currentConfig {
- return configsController.currentConfig;
-}
-
- (JSAction *)selectedAction {
- id item = [outlineView itemAtRow:outlineView.selectedRow];
- return [item children] ? nil : item;
+ id <NJActionPathElement> item = [outlineView itemAtRow:outlineView.selectedRow];
+ return (!item.children && item.base) ? item : nil;
}
-- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
- return item ? [[item children] count] : [joysticks count];
+- (NSInteger)outlineView:(NSOutlineView *)outlineView
+ numberOfChildrenOfItem:(id <NJActionPathElement>)item {
+ return item ? item.children.count : _joysticks.count;
}
-- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
+- (BOOL)outlineView:(NSOutlineView *)outlineView
+ isItemExpandable:(id <NJActionPathElement>)item {
return item ? [[item children] count] > 0: YES;
}
-- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item {
- return item ? [item children][index] : joysticks[index];
+- (id)outlineView:(NSOutlineView *)outlineView
+ child:(NSInteger)index
+ ofItem:(id <NJActionPathElement>)item {
+ return item ? item.children[index] : _joysticks[index];
}
-- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
- if(item == nil)
- return @"root";
- return [item name];
+- (id)outlineView:(NSOutlineView *)outlineView
+objectValueForTableColumn:(NSTableColumn *)tableColumn
+ byItem:(id <NJActionPathElement>)item {
+ return item ? item.name : @"root";
}
-- (void)outlineViewSelectionDidChange: (NSNotification*) notification {
- [targetController reset];
- [targetController load];
- if (programmaticallySelecting)
- [targetController focusKey];
- programmaticallySelecting = NO;
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification {
+ [targetController loadCurrent];
}
@end