// // Joystick.m // Enjoy // // Created by Sam McCall on 4/05/09. // #import "Joystick.h" #import "JSAction.h" #import "JSActionAnalog.h" #import "JSActionButton.h" #import "JSActionHat.h" static NSArray *ActionsForElement(IOHIDDeviceRef device, id base) { CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); NSMutableArray *children = [NSMutableArray arrayWithCapacity:CFArrayGetCount(elements)]; int buttons = 0; int axes = 0; int hats = 0; for (int i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); int type = IOHIDElementGetType(element); unsigned usage = IOHIDElementGetUsage(element); unsigned usagePage = IOHIDElementGetUsagePage(element); long max = IOHIDElementGetPhysicalMax(element); long min = IOHIDElementGetPhysicalMin(element); CFStringRef elName = IOHIDElementGetName(element); JSAction *action = nil; if (!(type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis || type == kIOHIDElementTypeInput_Button)) continue; if (max - min == 1 || usagePage == kHIDPage_Button || type == kIOHIDElementTypeInput_Button) { action = [[JSActionButton alloc] initWithName:(__bridge NSString *)elName idx:++buttons max:max]; } else if (usage == kHIDUsage_GD_Hatswitch) { action = [[JSActionHat alloc] initWithIndex:++hats]; } else if (usage >= kHIDUsage_GD_X && usage <= kHIDUsage_GD_Rz) { action = [[JSActionAnalog alloc] initWithIndex:++axes rawMin:min rawMax:max]; } else { continue; } // TODO(jfw): Should be moved into better constructors. action.base = base; action.cookie = IOHIDElementGetCookie(element); [children addObject:action]; } CFRelease(elements); return children; } @implementation Joystick { int vendorId; int productId; } - (id)initWithDevice:(IOHIDDeviceRef)dev { if ((self = [super init])) { self.device = dev; self.productName = (__bridge NSString *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductKey)); vendorId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey)) intValue]; productId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey)) intValue]; self.children = ActionsForElement(dev, self); } return self; } - (NSString *)name { return [NSString stringWithFormat:@"%@ #%d", _productName, _index]; } - (id)base { return nil; } - (NSString *)uid { return [NSString stringWithFormat: @"%d:%d:%d", vendorId, productId, _index]; } - (JSAction *)findActionByCookie:(IOHIDElementCookie)cookie { for (JSAction *child in _children) if (child.cookie == cookie) return child; return nil; } - (id)handlerForEvent:(IOHIDValueRef) value { JSAction *mainAction = [self actionForEvent:value]; return [mainAction findSubActionForValue:value]; } - (JSAction *)actionForEvent:(IOHIDValueRef)value { IOHIDElementRef elt = IOHIDValueGetElement(value); IOHIDElementCookie cookie = IOHIDElementGetCookie(elt); return [self findActionByCookie:cookie]; } @end