SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
JoyKit/JOYElement.m
1 #import "JOYElement.h"
2 #import <IOKit/hid/IOHIDLib.h>
3 #import <objc/runtime.h>
4
5 @implementation JOYElement
6 {
7 id _element;
8 IOHIDDeviceRef _device;
9 int32_t _min, _max;
10 }
11
12 - (int32_t)min
13 {
14 return MIN(_min, _max);
15 }
16
17 - (int32_t)max
18 {
19 return MAX(_max, _min);
20 }
21
22 -(void)setMin:(int32_t)min
23 {
24 _min = min;
25 }
26
27 - (void)setMax:(int32_t)max
28 {
29 _max = max;
30 }
31
32 /* Ugly hack because IOHIDDeviceCopyMatchingElements is slow */
33 + (NSArray *) cookiesToSkipForDevice:(IOHIDDeviceRef)device
34 {
35 id _device = (__bridge id)device;
36 NSMutableArray *ret = objc_getAssociatedObject(_device, _cmd);
37 if (ret) return ret;
38
39 ret = [NSMutableArray array];
40 NSArray *nones = CFBridgingRelease(IOHIDDeviceCopyMatchingElements(device,
41 (__bridge CFDictionaryRef)@{@(kIOHIDElementTypeKey): @(kIOHIDElementTypeInput_NULL)},
42 0));
43 for (id none in nones) {
44 [ret addObject:@(IOHIDElementGetCookie((__bridge IOHIDElementRef)none))];
45 }
46 objc_setAssociatedObject(_device, _cmd, ret, OBJC_ASSOCIATION_RETAIN);
47 return ret;
48 }
49
50 - (instancetype)initWithElement:(IOHIDElementRef)element
51 {
52 if ((self = [super init])) {
53 _element = (__bridge id)element;
54 _usage = IOHIDElementGetUsage(element);
55 _usagePage = IOHIDElementGetUsagePage(element);
56 _uniqueID = (uint32_t)IOHIDElementGetCookie(element);
57 _min = (int32_t) IOHIDElementGetLogicalMin(element);
58 _max = (int32_t) IOHIDElementGetLogicalMax(element);
59 _reportID = IOHIDElementGetReportID(element);
60 IOHIDElementRef parent = IOHIDElementGetParent(element);
61 _parentID = parent? (uint32_t)IOHIDElementGetCookie(parent) : -1;
62 _device = IOHIDElementGetDevice(element);
63
64 /* Catalina added a new input type in a way that breaks cookie consistency across macOS versions,
65 we shall adjust our cookies to to compensate */
66 unsigned cookieShift = 0, parentCookieShift = 0;
67
68 for (NSNumber *none in [JOYElement cookiesToSkipForDevice:_device]) {
69 if (none.unsignedIntValue < _uniqueID) {
70 cookieShift++;
71 }
72 if (none.unsignedIntValue < (int32_t)_parentID) {
73 parentCookieShift++;
74 }
75 }
76
77 _uniqueID -= cookieShift;
78 _parentID -= parentCookieShift;
79 }
80 return self;
81 }
82
83 - (int32_t)value
84 {
85 IOHIDValueRef value = NULL;
86 IOHIDDeviceGetValue(_device, (__bridge IOHIDElementRef)_element, &value);
87 if (!value) return 0;
88 CFRelease(CFRetain(value)); // For some reason, this is required to prevent leaks.
89 return (int32_t)IOHIDValueGetIntegerValue(value);
90 }
91
92 - (NSData *)dataValue
93 {
94 IOHIDValueRef value = NULL;
95 IOHIDDeviceGetValue(_device, (__bridge IOHIDElementRef)_element, &value);
96 if (!value) return 0;
97 CFRelease(CFRetain(value)); // For some reason, this is required to prevent leaks.
98 return [NSData dataWithBytes:IOHIDValueGetBytePtr(value) length:IOHIDValueGetLength(value)];
99 }
100
101 - (IOReturn)setValue:(uint32_t)value
102 {
103 IOHIDValueRef ivalue = IOHIDValueCreateWithIntegerValue(NULL, (__bridge IOHIDElementRef)_element, 0, value);
104 IOReturn ret = IOHIDDeviceSetValue(_device, (__bridge IOHIDElementRef)_element, ivalue);
105 CFRelease(ivalue);
106 return ret;
107 }
108
109 - (IOReturn)setDataValue:(NSData *)value
110 {
111 IOHIDValueRef ivalue = IOHIDValueCreateWithBytes(NULL, (__bridge IOHIDElementRef)_element, 0, value.bytes, value.length);
112 IOReturn ret = IOHIDDeviceSetValue(_device, (__bridge IOHIDElementRef)_element, ivalue);
113 CFRelease(ivalue);
114 return ret;
115 }
116
117 /* For use as a dictionary key */
118
119 - (NSUInteger)hash
120 {
121 return self.uniqueID;
122 }
123
124 - (BOOL)isEqual:(id)object
125 {
126 return self->_element == object;
127 }
128
129 - (id)copyWithZone:(NSZone *)zone;
130 {
131 return self;
132 }
133 @end
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.