Clean-up of Joystick class. Refactor constructor to avoid mandatory 'post-constructor...
[enjoyable.git] / Joystick.m
1 //
2 // Joystick.m
3 // Enjoy
4 //
5 // Created by Sam McCall on 4/05/09.
6 //
7
8 static NSArray *ActionsForElement(IOHIDDeviceRef device, id base) {
9 CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
10 NSMutableArray *children = [NSMutableArray arrayWithCapacity:CFArrayGetCount(elements)];
11
12 int buttons = 0;
13 int axes = 0;
14
15 for (int i = 0; i < CFArrayGetCount(elements); i++) {
16 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
17 int type = IOHIDElementGetType(element);
18 int usage = IOHIDElementGetUsage(element);
19 int usagePage = IOHIDElementGetUsagePage(element);
20 int max = IOHIDElementGetPhysicalMax(element);
21 int min = IOHIDElementGetPhysicalMin(element);
22 CFStringRef elName = IOHIDElementGetName(element);
23
24 JSAction *action = NULL;
25
26 if(!(type == kIOHIDElementTypeInput_Misc
27 || type == kIOHIDElementTypeInput_Axis
28 || type == kIOHIDElementTypeInput_Button))
29 continue;
30
31 if (max - min == 1 || usagePage == kHIDPage_Button || type == kIOHIDElementTypeInput_Button) {
32 action = [[JSActionButton alloc] initWithIndex:buttons++ andName:(__bridge NSString *)elName];
33 [(JSActionButton*)action setMax:max];
34 } else if (usage == kHIDUsage_GD_Hatswitch) {
35 action = [[JSActionHat alloc] init];
36 } else {
37 if (usage >= kHIDUsage_GD_X && usage <= kHIDUsage_GD_Rz) {
38 action = [[JSActionAnalog alloc] initWithIndex: axes++];
39 [(JSActionAnalog*)action setOffset:(double)-1.0];
40 [(JSActionAnalog*)action setScale:(double)2.0/(max - min)];
41 } else
42 continue;
43 }
44
45 [action setBase:base];
46 [action setUsage:usage];
47 [action setCookie:IOHIDElementGetCookie(element)];
48 [children addObject:action];
49 }
50 return children;
51 }
52
53 @implementation Joystick
54
55 @synthesize vendorId;
56 @synthesize productId;
57 @synthesize productName;
58 @synthesize index;
59 @synthesize device;
60 @synthesize children;
61
62 - (id)initWithDevice:(IOHIDDeviceRef)dev {
63 if ((self = [super init])) {
64 self.device = dev;
65 self.productName = (__bridge NSString *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductKey));
66 self.vendorId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey)) intValue];
67 self.productId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey)) intValue];
68 self.children = ActionsForElement(dev, self);
69 }
70 return self;
71 }
72
73 - (NSString *)name {
74 return [NSString stringWithFormat:@"%@ #%d", productName, index + 1];
75 }
76
77 - (id)base {
78 // FIXME(jfw): This is a hack because actions get joysticks as their base.
79 return nil;
80 }
81
82 - (NSString *)stringify {
83 return [[NSString alloc] initWithFormat: @"%d~%d~%d", vendorId, productId, index];
84 }
85
86 - (JSAction *)findActionByCookie:(void *)cookie {
87 for (JSAction *child in children)
88 if (child.cookie == cookie)
89 return child;
90 return nil;
91 }
92
93 - (id)handlerForEvent:(IOHIDValueRef) value {
94 JSAction *mainAction = [self actionForEvent:value];
95 return [mainAction findSubActionForValue:value];
96 }
97
98 - (JSAction *)actionForEvent:(IOHIDValueRef)value {
99 IOHIDElementRef elt = IOHIDValueGetElement(value);
100 void *cookie = IOHIDElementGetCookie(elt);
101 return [self findActionByCookie:cookie];
102 }
103
104 @end