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