git.y1.nz

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.