3b43e4e3249ba57c158e1f1947681d765b87bfdb
[enjoyable.git] / Joystick.m
1 //
2 // Joystick.m
3 // Enjoy
4 //
5 // Created by Sam McCall on 4/05/09.
6 //
7
8 #import "Joystick.h"
9
10 #import "JSAction.h"
11 #import "JSActionAnalog.h"
12 #import "JSActionButton.h"
13 #import "JSActionHat.h"
14
15 static NSArray *ActionsForElement(IOHIDDeviceRef device, id base) {
16 CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
17 NSMutableArray *children = [NSMutableArray arrayWithCapacity:CFArrayGetCount(elements)];
18
19 int buttons = 0;
20 int axes = 0;
21 int hats = 0;
22
23 for (int i = 0; i < CFArrayGetCount(elements); i++) {
24 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
25 int type = IOHIDElementGetType(element);
26 unsigned usage = IOHIDElementGetUsage(element);
27 unsigned usagePage = IOHIDElementGetUsagePage(element);
28 long max = IOHIDElementGetPhysicalMax(element);
29 long min = IOHIDElementGetPhysicalMin(element);
30 CFStringRef elName = IOHIDElementGetName(element);
31
32 JSAction *action = nil;
33
34 if (!(type == kIOHIDElementTypeInput_Misc
35 || type == kIOHIDElementTypeInput_Axis
36 || type == kIOHIDElementTypeInput_Button))
37 continue;
38
39 if (max - min == 1 || usagePage == kHIDPage_Button || type == kIOHIDElementTypeInput_Button) {
40 action = [[JSActionButton alloc] initWithName:(__bridge NSString *)elName
41 idx:++buttons
42 max:max];
43 } else if (usage == kHIDUsage_GD_Hatswitch) {
44 action = [[JSActionHat alloc] initWithIndex:++hats];
45 } else if (usage >= kHIDUsage_GD_X && usage <= kHIDUsage_GD_Rz) {
46 action = [[JSActionAnalog alloc] initWithIndex:++axes
47 rawMin:min
48 rawMax:max];
49 } else {
50 continue;
51 }
52
53 // TODO(jfw): Should be moved into better constructors.
54 action.base = base;
55 action.cookie = IOHIDElementGetCookie(element);
56 [children addObject:action];
57 }
58
59 CFRelease(elements);
60 return children;
61 }
62
63 @implementation Joystick {
64 int vendorId;
65 int productId;
66 }
67
68 - (id)initWithDevice:(IOHIDDeviceRef)dev {
69 if ((self = [super init])) {
70 self.device = dev;
71 self.productName = (__bridge NSString *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductKey));
72 vendorId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey)) intValue];
73 productId = [(__bridge NSNumber *)IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey)) intValue];
74 self.children = ActionsForElement(dev, self);
75 }
76 return self;
77 }
78
79 - (NSString *)name {
80 return [NSString stringWithFormat:@"%@ #%d", _productName, _index];
81 }
82
83 - (id)base {
84 return nil;
85 }
86
87 - (NSString *)uid {
88 return [NSString stringWithFormat: @"%d:%d:%d", vendorId, productId, _index];
89 }
90
91 - (JSAction *)findActionByCookie:(IOHIDElementCookie)cookie {
92 for (JSAction *child in _children)
93 if (child.cookie == cookie)
94 return child;
95 return nil;
96 }
97
98 - (id)handlerForEvent:(IOHIDValueRef) value {
99 JSAction *mainAction = [self actionForEvent:value];
100 return [mainAction findSubActionForValue:value];
101 }
102
103 - (JSAction *)actionForEvent:(IOHIDValueRef)value {
104 IOHIDElementRef elt = IOHIDValueGetElement(value);
105 IOHIDElementCookie cookie = IOHIDElementGetCookie(elt);
106 return [self findActionByCookie:cookie];
107 }
108
109 @end