|
@@ -27,9 +27,7 @@ static NSApplication *myapp;
|
|
|
static NSWindow *window;
|
|
|
static BasicMTKView *view;
|
|
|
static char language[3];
|
|
|
-#ifdef WITH_GAMEPAD
|
|
|
-static struct HIDManager *hidManager;
|
|
|
-#endif
|
|
|
+static int current_cursor_index = 0;
|
|
|
|
|
|
@implementation BasicMTKView
|
|
|
|
|
@@ -411,9 +409,6 @@ static int getMouseY(NSEvent *event) {
|
|
|
return YES;
|
|
|
}
|
|
|
|
|
|
-- (void)update {
|
|
|
-}
|
|
|
-
|
|
|
- (id)initWithFrame:(NSRect)frameRect {
|
|
|
self = [super initWithFrame:frameRect];
|
|
|
|
|
@@ -466,445 +461,134 @@ void iron_copy_to_clipboard(const char *text) {
|
|
|
[board setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType];
|
|
|
}
|
|
|
|
|
|
-#ifdef WITH_GAMEPAD
|
|
|
-
|
|
|
-static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef);
|
|
|
-static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender);
|
|
|
-static void reset(struct HIDGamepad *gamepad);
|
|
|
-static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements);
|
|
|
-static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex);
|
|
|
-static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex);
|
|
|
+int iron_count_displays(void) {
|
|
|
+ NSArray *screens = [NSScreen screens];
|
|
|
+ return (int)[screens count];
|
|
|
+}
|
|
|
|
|
|
-static void cstringFromCFStringRef(CFStringRef string, char *cstr, size_t clen) {
|
|
|
- cstr[0] = '\0';
|
|
|
- if (string != NULL) {
|
|
|
- char temp[256];
|
|
|
- if (CFStringGetCString(string, temp, 256, kCFStringEncodingUTF8)) {
|
|
|
- temp[iron_mini(255, (int)(clen - 1))] = '\0';
|
|
|
- strncpy(cstr, temp, clen);
|
|
|
+int iron_primary_display(void) {
|
|
|
+ NSArray *screens = [NSScreen screens];
|
|
|
+ NSScreen *mainScreen = [NSScreen mainScreen];
|
|
|
+ int max_displays = 8;
|
|
|
+ for (int i = 0; i < max_displays; ++i) {
|
|
|
+ if (mainScreen == screens[i]) {
|
|
|
+ return i;
|
|
|
}
|
|
|
}
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-void HIDGamepad_init(struct HIDGamepad *gamepad) {
|
|
|
- reset(gamepad);
|
|
|
-}
|
|
|
-
|
|
|
-void HIDGamepad_destroy(struct HIDGamepad *gamepad) {
|
|
|
- HIDGamepad_unbind(gamepad);
|
|
|
-}
|
|
|
-
|
|
|
-void HIDGamepad_bind(struct HIDGamepad *gamepad, IOHIDDeviceRef inDeviceRef, int inPadIndex) {
|
|
|
- gamepad->hidDeviceRef = inDeviceRef;
|
|
|
- gamepad->padIndex = inPadIndex;
|
|
|
-
|
|
|
- IOHIDDeviceOpen(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
|
|
|
- IOHIDDeviceRegisterInputValueCallback(gamepad->hidDeviceRef, inputValueCallback, gamepad);
|
|
|
- IOHIDDeviceScheduleWithRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+void iron_display_init(void) {}
|
|
|
|
|
|
- gamepad->hidQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, gamepad->hidDeviceRef, 32, kIOHIDOptionsTypeNone);
|
|
|
- if (CFGetTypeID(gamepad->hidQueueRef) == IOHIDQueueGetTypeID()) {
|
|
|
- IOHIDQueueStart(gamepad->hidQueueRef);
|
|
|
- IOHIDQueueRegisterValueAvailableCallback(gamepad->hidQueueRef, valueAvailableCallback, gamepad);
|
|
|
- IOHIDQueueScheduleWithRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
- }
|
|
|
+iron_display_mode_t iron_display_current_mode(int display) {
|
|
|
+ NSArray *screens = [NSScreen screens];
|
|
|
+ NSScreen *screen = screens[display];
|
|
|
+ NSRect screenRect = [screen frame];
|
|
|
+ iron_display_mode_t dm;
|
|
|
+ dm.width = screenRect.size.width;
|
|
|
+ dm.height = screenRect.size.height;
|
|
|
+ dm.frequency = 60;
|
|
|
+ dm.bits_per_pixel = 32;
|
|
|
|
|
|
- CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(gamepad->hidDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
|
|
- initDeviceElements(gamepad, elementCFArrayRef);
|
|
|
+ NSDictionary *description = [screen deviceDescription];
|
|
|
+ NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
|
|
|
+ NSNumber *screenNumber = [description objectForKey:@"NSScreenNumber"];
|
|
|
+ CGSize displayPhysicalSize = CGDisplayScreenSize([screenNumber unsignedIntValue]); // in millimeters
|
|
|
+ double ppi = displayPixelSize.width / (displayPhysicalSize.width * 0.039370); // Convert MM to INCH
|
|
|
+ dm.pixels_per_inch = round(ppi);
|
|
|
|
|
|
- {
|
|
|
- CFNumberRef vendorIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDVendorIDKey));
|
|
|
- CFNumberGetValue(vendorIdRef, kCFNumberIntType, &gamepad->hidDeviceVendorID);
|
|
|
+ return dm;
|
|
|
+}
|
|
|
|
|
|
- CFNumberRef productIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductIDKey));
|
|
|
- CFNumberGetValue(productIdRef, kCFNumberIntType, &gamepad->hidDeviceProductID);
|
|
|
+void iron_internal_mouse_lock() {
|
|
|
+ iron_mouse_hide();
|
|
|
+}
|
|
|
|
|
|
- CFStringRef vendorRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDManufacturerKey));
|
|
|
- cstringFromCFStringRef(vendorRef, gamepad->hidDeviceVendor, sizeof(gamepad->hidDeviceVendor));
|
|
|
+void iron_internal_mouse_unlock(void) {
|
|
|
+ iron_mouse_show();
|
|
|
+}
|
|
|
|
|
|
- CFStringRef productRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductKey));
|
|
|
- cstringFromCFStringRef(productRef, gamepad->hidDeviceProduct, sizeof(gamepad->hidDeviceProduct));
|
|
|
- }
|
|
|
+bool iron_mouse_can_lock(void) {
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
-static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements) {
|
|
|
+void iron_mouse_show(void) {
|
|
|
+ CGDisplayShowCursor(kCGDirectMainDisplay);
|
|
|
+}
|
|
|
|
|
|
- for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i) {
|
|
|
- IOHIDElementRef elementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
|
|
- IOHIDElementType elemType = IOHIDElementGetType(elementRef);
|
|
|
+void iron_mouse_hide(void) {
|
|
|
+ CGDisplayHideCursor(kCGDirectMainDisplay);
|
|
|
+}
|
|
|
|
|
|
- IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
|
|
|
+void iron_mouse_set_position(int x, int y) {
|
|
|
+ NSWindow *window = windows[0].handle;
|
|
|
+ float scale = [window backingScaleFactor];
|
|
|
+ NSRect rect = [[NSScreen mainScreen] frame];
|
|
|
|
|
|
- uint32_t usagePage = IOHIDElementGetUsagePage(elementRef);
|
|
|
- uint32_t usage = IOHIDElementGetUsage(elementRef);
|
|
|
+ CGPoint point;
|
|
|
+ point.x = window.frame.origin.x + (x / scale);
|
|
|
+ point.y = rect.size.height - (window.frame.origin.y + (y / scale));
|
|
|
|
|
|
- // Match up items
|
|
|
- switch (usagePage) {
|
|
|
- case kHIDPage_GenericDesktop:
|
|
|
- switch (usage) {
|
|
|
- case kHIDUsage_GD_X: // Left stick X
|
|
|
- gamepad->axis[0] = cookie;
|
|
|
- break;
|
|
|
- case kHIDUsage_GD_Y: // Left stick Y
|
|
|
- gamepad->axis[1] = cookie;
|
|
|
- break;
|
|
|
- case kHIDUsage_GD_Z: // Left trigger
|
|
|
- gamepad->axis[4] = cookie;
|
|
|
- break;
|
|
|
- case kHIDUsage_GD_Rx: // Right stick X
|
|
|
- gamepad->axis[2] = cookie;
|
|
|
- break;
|
|
|
- case kHIDUsage_GD_Ry: // Right stick Y
|
|
|
- gamepad->axis[3] = cookie;
|
|
|
- break;
|
|
|
- case kHIDUsage_GD_Rz: // Right trigger
|
|
|
- gamepad->axis[5] = cookie;
|
|
|
- break;
|
|
|
- case kHIDUsage_GD_Hatswitch:
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- break;
|
|
|
- case kHIDPage_Button:
|
|
|
- if ((usage >= 1) && (usage <= 15)) {
|
|
|
- // Button 1-11
|
|
|
- gamepad->buttons[usage - 1] = cookie;
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
+ CGDisplayMoveCursorToPoint(0, point);
|
|
|
+ CGAssociateMouseAndMouseCursorPosition(true);
|
|
|
+}
|
|
|
|
|
|
- if (elemType == kIOHIDElementTypeInput_Misc || elemType == kIOHIDElementTypeInput_Button || elemType == kIOHIDElementTypeInput_Axis) {
|
|
|
- if (!IOHIDQueueContainsElement(gamepad->hidQueueRef, elementRef))
|
|
|
- IOHIDQueueAddElement(gamepad->hidQueueRef, elementRef);
|
|
|
- }
|
|
|
- }
|
|
|
+void iron_mouse_get_position(int *x, int *y) {
|
|
|
+ NSWindow *window = windows[0].handle;
|
|
|
+ NSPoint point = [window mouseLocationOutsideOfEventStream];
|
|
|
+ *x = (int)point.x;
|
|
|
+ *y = (int)point.y;
|
|
|
}
|
|
|
|
|
|
-void HIDGamepad_unbind(struct HIDGamepad *gamepad) {
|
|
|
- if (gamepad->hidQueueRef) {
|
|
|
- IOHIDQueueStop(gamepad->hidQueueRef);
|
|
|
- IOHIDQueueUnscheduleFromRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
- }
|
|
|
- if (gamepad->hidDeviceRef) {
|
|
|
- IOHIDDeviceUnscheduleFromRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
- IOHIDDeviceClose(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
|
|
|
- }
|
|
|
- reset(gamepad);
|
|
|
+void iron_mouse_set_cursor(int cursor_index) {
|
|
|
}
|
|
|
|
|
|
-static void reset(struct HIDGamepad *gamepad) {
|
|
|
- gamepad->padIndex = -1;
|
|
|
- gamepad->hidDeviceRef = NULL;
|
|
|
- gamepad->hidQueueRef = NULL;
|
|
|
- gamepad->hidDeviceVendor[0] = '\0';
|
|
|
- gamepad->hidDeviceProduct[0] = '\0';
|
|
|
- gamepad->hidDeviceVendorID = 0;
|
|
|
- gamepad->hidDeviceProductID = 0;
|
|
|
- memset(gamepad->axis, 0, sizeof(gamepad->axis));
|
|
|
- memset(gamepad->buttons, 0, sizeof(gamepad->buttons));
|
|
|
+void iron_keyboard_show(void) {
|
|
|
+ keyboardShown = true;
|
|
|
}
|
|
|
|
|
|
-static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex) {
|
|
|
- double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
|
|
|
- double min = IOHIDElementGetLogicalMin(elementRef);
|
|
|
- double max = IOHIDElementGetLogicalMax(elementRef);
|
|
|
- double normalize = (rawValue - min) / (max - min);
|
|
|
- iron_internal_gamepad_trigger_button(gamepad->padIndex, buttonIndex, normalize);
|
|
|
+void iron_keyboard_hide(void) {
|
|
|
+ keyboardShown = false;
|
|
|
}
|
|
|
|
|
|
-static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex) {
|
|
|
- double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
|
|
|
- double min = IOHIDElementGetPhysicalMin(elementRef);
|
|
|
- double max = IOHIDElementGetPhysicalMax(elementRef);
|
|
|
- double normalize = normalize = (((rawValue - min) / (max - min)) * 2) - 1;
|
|
|
- if (axisIndex % 2 == 1) {
|
|
|
- normalize = -normalize;
|
|
|
- }
|
|
|
- iron_internal_gamepad_trigger_axis(gamepad->padIndex, axisIndex, normalize);
|
|
|
+bool iron_keyboard_active(void) {
|
|
|
+ return keyboardShown;
|
|
|
}
|
|
|
|
|
|
-static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef) {}
|
|
|
+const char *iron_system_id(void) {
|
|
|
+ return "macOS";
|
|
|
+}
|
|
|
|
|
|
-static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender) {
|
|
|
- struct HIDGamepad *pad = (struct HIDGamepad *)inContext;
|
|
|
- do {
|
|
|
- IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout((IOHIDQueueRef)inSender, 0.);
|
|
|
- if (!valueRef) {
|
|
|
- break;
|
|
|
- }
|
|
|
+const char **iron_video_formats(void) {
|
|
|
+ return videoFormats;
|
|
|
+}
|
|
|
|
|
|
- IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
|
|
|
- IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
|
|
|
+void iron_set_keep_screen_on(bool on) {}
|
|
|
|
|
|
- for (int i = 0, c = sizeof(pad->buttons); i < c; ++i) {
|
|
|
- if (cookie == pad->buttons[i]) {
|
|
|
- buttonChanged(pad, elementRef, valueRef, i);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+double iron_frequency(void) {
|
|
|
+ mach_timebase_info_data_t info;
|
|
|
+ mach_timebase_info(&info);
|
|
|
+ return (double)info.denom / (double)info.numer / 1e-9;
|
|
|
+}
|
|
|
|
|
|
- for (int i = 0, c = sizeof(pad->axis); i < c; ++i) {
|
|
|
- if (cookie == pad->axis[i]) {
|
|
|
- axisChanged(pad, elementRef, valueRef, i);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
+uint64_t iron_timestamp(void) {
|
|
|
+ return mach_absolute_time();
|
|
|
+}
|
|
|
|
|
|
- CFRelease(valueRef);
|
|
|
- } while (1);
|
|
|
+bool with_autoreleasepool(bool (*f)(void)) {
|
|
|
+ @autoreleasepool {
|
|
|
+ return f();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-const char *iron_gamepad_vendor(int gamepad) {
|
|
|
- return "unknown";
|
|
|
+const char *iron_get_resource_path(void) {
|
|
|
+ return [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding];
|
|
|
}
|
|
|
|
|
|
-const char *iron_gamepad_product_name(int gamepad) {
|
|
|
- return "unknown";
|
|
|
+@interface IronApplication : NSApplication {
|
|
|
}
|
|
|
-
|
|
|
-static int initHIDManager(struct HIDManager *manager);
|
|
|
-static bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef);
|
|
|
-static CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage);
|
|
|
-static void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
|
|
|
-static void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
|
|
|
-
|
|
|
-void HIDManager_init(struct HIDManager *manager) {
|
|
|
- manager->managerRef = 0x0;
|
|
|
- initHIDManager(manager);
|
|
|
-}
|
|
|
-
|
|
|
-void HIDManager_destroy(struct HIDManager *manager) {
|
|
|
- if (manager->managerRef) {
|
|
|
- IOHIDManagerUnscheduleFromRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
- IOHIDManagerClose(manager->managerRef, kIOHIDOptionsTypeNone);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int initHIDManager(struct HIDManager *manager) {
|
|
|
- manager->managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
|
|
- if (CFGetTypeID(manager->managerRef) == IOHIDManagerGetTypeID()) {
|
|
|
-
|
|
|
- CFMutableArrayRef matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
|
|
- if (matchingCFArrayRef) {
|
|
|
- CFDictionaryRef matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
|
|
- addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
|
|
|
- matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
|
|
|
- addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
|
|
|
- }
|
|
|
- else {
|
|
|
- iron_error("%s: CFArrayCreateMutable failed.", __PRETTY_FUNCTION__);
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- IOHIDManagerSetDeviceMatchingMultiple(manager->managerRef, matchingCFArrayRef);
|
|
|
- CFRelease(matchingCFArrayRef);
|
|
|
- IOHIDManagerOpen(manager->managerRef, kIOHIDOptionsTypeNone);
|
|
|
- IOHIDManagerRegisterDeviceMatchingCallback(manager->managerRef, deviceConnected, manager);
|
|
|
- IOHIDManagerRegisterDeviceRemovalCallback(manager->managerRef, deviceRemoved, manager);
|
|
|
- IOHIDManagerScheduleWithRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef) {
|
|
|
- if (matchingCFDictRef) {
|
|
|
- CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
|
|
- CFRelease(matchingCFDictRef);
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage) {
|
|
|
- CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
- if (result) {
|
|
|
- if (inUsagePage) {
|
|
|
- CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage);
|
|
|
- if (pageCFNumberRef) {
|
|
|
- CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsagePageKey), pageCFNumberRef);
|
|
|
- CFRelease(pageCFNumberRef);
|
|
|
- if (inUsage) {
|
|
|
- CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage);
|
|
|
- if (usageCFNumberRef) {
|
|
|
- CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
|
|
|
- CFRelease(usageCFNumberRef);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
|
- struct HIDManager *manager = (struct HIDManager *)inContext;
|
|
|
- struct HIDManagerDeviceRecord *device = &manager->devices[0];
|
|
|
- for (int i = 0; i < IRON_MAX_HID_DEVICES; ++i, ++device) {
|
|
|
- if (!device->connected) {
|
|
|
- device->connected = true;
|
|
|
- device->device = inIOHIDDeviceRef;
|
|
|
- HIDGamepad_bind(&device->pad, inIOHIDDeviceRef, i);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
|
- struct HIDManager *manager = (struct HIDManager *)inContext;
|
|
|
- struct HIDManagerDeviceRecord *device = &manager->devices[0];
|
|
|
- for (int i = 0; i < IRON_MAX_HID_DEVICES; ++i, ++device) {
|
|
|
- if (device->connected && device->device == inIOHIDDeviceRef) {
|
|
|
- device->connected = false;
|
|
|
- device->device = NULL;
|
|
|
- HIDGamepad_unbind(&device->pad);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#endif
|
|
|
-
|
|
|
-int iron_count_displays(void) {
|
|
|
- NSArray *screens = [NSScreen screens];
|
|
|
- return (int)[screens count];
|
|
|
-}
|
|
|
-
|
|
|
-int iron_primary_display(void) {
|
|
|
- NSArray *screens = [NSScreen screens];
|
|
|
- NSScreen *mainScreen = [NSScreen mainScreen];
|
|
|
- int max_displays = 8;
|
|
|
- for (int i = 0; i < max_displays; ++i) {
|
|
|
- if (mainScreen == screens[i]) {
|
|
|
- return i;
|
|
|
- }
|
|
|
- }
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_display_init(void) {}
|
|
|
-
|
|
|
-iron_display_mode_t iron_display_current_mode(int display) {
|
|
|
- NSArray *screens = [NSScreen screens];
|
|
|
- NSScreen *screen = screens[display];
|
|
|
- NSRect screenRect = [screen frame];
|
|
|
- iron_display_mode_t dm;
|
|
|
- dm.width = screenRect.size.width;
|
|
|
- dm.height = screenRect.size.height;
|
|
|
- dm.frequency = 60;
|
|
|
- dm.bits_per_pixel = 32;
|
|
|
-
|
|
|
- NSDictionary *description = [screen deviceDescription];
|
|
|
- NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
|
|
|
- NSNumber *screenNumber = [description objectForKey:@"NSScreenNumber"];
|
|
|
- CGSize displayPhysicalSize = CGDisplayScreenSize([screenNumber unsignedIntValue]); // in millimeters
|
|
|
- double ppi = displayPixelSize.width / (displayPhysicalSize.width * 0.039370); // Convert MM to INCH
|
|
|
- dm.pixels_per_inch = round(ppi);
|
|
|
-
|
|
|
- return dm;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_internal_mouse_lock() {
|
|
|
- iron_mouse_hide();
|
|
|
-}
|
|
|
-
|
|
|
-void iron_internal_mouse_unlock(void) {
|
|
|
- iron_mouse_show();
|
|
|
-}
|
|
|
-
|
|
|
-bool iron_mouse_can_lock(void) {
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_mouse_show(void) {
|
|
|
- CGDisplayShowCursor(kCGDirectMainDisplay);
|
|
|
-}
|
|
|
-
|
|
|
-void iron_mouse_hide(void) {
|
|
|
- CGDisplayHideCursor(kCGDirectMainDisplay);
|
|
|
-}
|
|
|
-
|
|
|
-void iron_mouse_set_position(int x, int y) {
|
|
|
- NSWindow *window = windows[0].handle;
|
|
|
- float scale = [window backingScaleFactor];
|
|
|
- NSRect rect = [[NSScreen mainScreen] frame];
|
|
|
-
|
|
|
- CGPoint point;
|
|
|
- point.x = window.frame.origin.x + (x / scale);
|
|
|
- point.y = rect.size.height - (window.frame.origin.y + (y / scale));
|
|
|
-
|
|
|
- CGDisplayMoveCursorToPoint(0, point);
|
|
|
- CGAssociateMouseAndMouseCursorPosition(true);
|
|
|
-}
|
|
|
-
|
|
|
-void iron_mouse_get_position(int *x, int *y) {
|
|
|
- NSWindow *window = windows[0].handle;
|
|
|
- NSPoint point = [window mouseLocationOutsideOfEventStream];
|
|
|
- *x = (int)point.x;
|
|
|
- *y = (int)point.y;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_mouse_set_cursor(int cursor_index) {}
|
|
|
-
|
|
|
-void iron_keyboard_show(void) {
|
|
|
- keyboardShown = true;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_keyboard_hide(void) {
|
|
|
- keyboardShown = false;
|
|
|
-}
|
|
|
-
|
|
|
-bool iron_keyboard_active(void) {
|
|
|
- return keyboardShown;
|
|
|
-}
|
|
|
-
|
|
|
-const char *iron_system_id(void) {
|
|
|
- return "macOS";
|
|
|
-}
|
|
|
-
|
|
|
-const char **iron_video_formats(void) {
|
|
|
- return videoFormats;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_set_keep_screen_on(bool on) {}
|
|
|
-
|
|
|
-double iron_frequency(void) {
|
|
|
- mach_timebase_info_data_t info;
|
|
|
- mach_timebase_info(&info);
|
|
|
- return (double)info.denom / (double)info.numer / 1e-9;
|
|
|
-}
|
|
|
-
|
|
|
-uint64_t iron_timestamp(void) {
|
|
|
- return mach_absolute_time();
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef WITH_GAMEPAD
|
|
|
-
|
|
|
-bool iron_gamepad_connected(int num) {
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-void iron_gamepad_rumble(int gamepad, float left, float right) {}
|
|
|
-
|
|
|
-#endif
|
|
|
-
|
|
|
-bool with_autoreleasepool(bool (*f)(void)) {
|
|
|
- @autoreleasepool {
|
|
|
- return f();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const char *iron_get_resource_path(void) {
|
|
|
- return [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding];
|
|
|
-}
|
|
|
-
|
|
|
-@interface IronApplication : NSApplication {
|
|
|
-}
|
|
|
-- (void)terminate:(id)sender;
|
|
|
-@end
|
|
|
+- (void)terminate:(id)sender;
|
|
|
+@end
|
|
|
|
|
|
@interface IronAppDelegate : NSObject <NSWindowDelegate> {
|
|
|
}
|
|
@@ -1178,3 +862,313 @@ iron_window_mode_t iron_window_get_mode() {
|
|
|
int iron_window_display() {
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef WITH_GAMEPAD
|
|
|
+
|
|
|
+static struct HIDManager *hidManager;
|
|
|
+
|
|
|
+bool iron_gamepad_connected(int num) {
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void iron_gamepad_rumble(int gamepad, float left, float right) {}
|
|
|
+
|
|
|
+static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef);
|
|
|
+static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender);
|
|
|
+static void reset(struct HIDGamepad *gamepad);
|
|
|
+static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements);
|
|
|
+static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex);
|
|
|
+static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex);
|
|
|
+
|
|
|
+static void cstringFromCFStringRef(CFStringRef string, char *cstr, size_t clen) {
|
|
|
+ cstr[0] = '\0';
|
|
|
+ if (string != NULL) {
|
|
|
+ char temp[256];
|
|
|
+ if (CFStringGetCString(string, temp, 256, kCFStringEncodingUTF8)) {
|
|
|
+ temp[iron_mini(255, (int)(clen - 1))] = '\0';
|
|
|
+ strncpy(cstr, temp, clen);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void HIDGamepad_init(struct HIDGamepad *gamepad) {
|
|
|
+ reset(gamepad);
|
|
|
+}
|
|
|
+
|
|
|
+void HIDGamepad_destroy(struct HIDGamepad *gamepad) {
|
|
|
+ HIDGamepad_unbind(gamepad);
|
|
|
+}
|
|
|
+
|
|
|
+void HIDGamepad_bind(struct HIDGamepad *gamepad, IOHIDDeviceRef inDeviceRef, int inPadIndex) {
|
|
|
+ gamepad->hidDeviceRef = inDeviceRef;
|
|
|
+ gamepad->padIndex = inPadIndex;
|
|
|
+
|
|
|
+ IOHIDDeviceOpen(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
|
|
|
+ IOHIDDeviceRegisterInputValueCallback(gamepad->hidDeviceRef, inputValueCallback, gamepad);
|
|
|
+ IOHIDDeviceScheduleWithRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+
|
|
|
+ gamepad->hidQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, gamepad->hidDeviceRef, 32, kIOHIDOptionsTypeNone);
|
|
|
+ if (CFGetTypeID(gamepad->hidQueueRef) == IOHIDQueueGetTypeID()) {
|
|
|
+ IOHIDQueueStart(gamepad->hidQueueRef);
|
|
|
+ IOHIDQueueRegisterValueAvailableCallback(gamepad->hidQueueRef, valueAvailableCallback, gamepad);
|
|
|
+ IOHIDQueueScheduleWithRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+ }
|
|
|
+
|
|
|
+ CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(gamepad->hidDeviceRef, NULL, kIOHIDOptionsTypeNone);
|
|
|
+ initDeviceElements(gamepad, elementCFArrayRef);
|
|
|
+
|
|
|
+ {
|
|
|
+ CFNumberRef vendorIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDVendorIDKey));
|
|
|
+ CFNumberGetValue(vendorIdRef, kCFNumberIntType, &gamepad->hidDeviceVendorID);
|
|
|
+
|
|
|
+ CFNumberRef productIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductIDKey));
|
|
|
+ CFNumberGetValue(productIdRef, kCFNumberIntType, &gamepad->hidDeviceProductID);
|
|
|
+
|
|
|
+ CFStringRef vendorRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDManufacturerKey));
|
|
|
+ cstringFromCFStringRef(vendorRef, gamepad->hidDeviceVendor, sizeof(gamepad->hidDeviceVendor));
|
|
|
+
|
|
|
+ CFStringRef productRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductKey));
|
|
|
+ cstringFromCFStringRef(productRef, gamepad->hidDeviceProduct, sizeof(gamepad->hidDeviceProduct));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements) {
|
|
|
+
|
|
|
+ for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i) {
|
|
|
+ IOHIDElementRef elementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
|
|
+ IOHIDElementType elemType = IOHIDElementGetType(elementRef);
|
|
|
+
|
|
|
+ IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
|
|
|
+
|
|
|
+ uint32_t usagePage = IOHIDElementGetUsagePage(elementRef);
|
|
|
+ uint32_t usage = IOHIDElementGetUsage(elementRef);
|
|
|
+
|
|
|
+ // Match up items
|
|
|
+ switch (usagePage) {
|
|
|
+ case kHIDPage_GenericDesktop:
|
|
|
+ switch (usage) {
|
|
|
+ case kHIDUsage_GD_X: // Left stick X
|
|
|
+ gamepad->axis[0] = cookie;
|
|
|
+ break;
|
|
|
+ case kHIDUsage_GD_Y: // Left stick Y
|
|
|
+ gamepad->axis[1] = cookie;
|
|
|
+ break;
|
|
|
+ case kHIDUsage_GD_Z: // Left trigger
|
|
|
+ gamepad->axis[4] = cookie;
|
|
|
+ break;
|
|
|
+ case kHIDUsage_GD_Rx: // Right stick X
|
|
|
+ gamepad->axis[2] = cookie;
|
|
|
+ break;
|
|
|
+ case kHIDUsage_GD_Ry: // Right stick Y
|
|
|
+ gamepad->axis[3] = cookie;
|
|
|
+ break;
|
|
|
+ case kHIDUsage_GD_Rz: // Right trigger
|
|
|
+ gamepad->axis[5] = cookie;
|
|
|
+ break;
|
|
|
+ case kHIDUsage_GD_Hatswitch:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case kHIDPage_Button:
|
|
|
+ if ((usage >= 1) && (usage <= 15)) {
|
|
|
+ // Button 1-11
|
|
|
+ gamepad->buttons[usage - 1] = cookie;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (elemType == kIOHIDElementTypeInput_Misc || elemType == kIOHIDElementTypeInput_Button || elemType == kIOHIDElementTypeInput_Axis) {
|
|
|
+ if (!IOHIDQueueContainsElement(gamepad->hidQueueRef, elementRef))
|
|
|
+ IOHIDQueueAddElement(gamepad->hidQueueRef, elementRef);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void HIDGamepad_unbind(struct HIDGamepad *gamepad) {
|
|
|
+ if (gamepad->hidQueueRef) {
|
|
|
+ IOHIDQueueStop(gamepad->hidQueueRef);
|
|
|
+ IOHIDQueueUnscheduleFromRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+ }
|
|
|
+ if (gamepad->hidDeviceRef) {
|
|
|
+ IOHIDDeviceUnscheduleFromRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+ IOHIDDeviceClose(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
|
|
|
+ }
|
|
|
+ reset(gamepad);
|
|
|
+}
|
|
|
+
|
|
|
+static void reset(struct HIDGamepad *gamepad) {
|
|
|
+ gamepad->padIndex = -1;
|
|
|
+ gamepad->hidDeviceRef = NULL;
|
|
|
+ gamepad->hidQueueRef = NULL;
|
|
|
+ gamepad->hidDeviceVendor[0] = '\0';
|
|
|
+ gamepad->hidDeviceProduct[0] = '\0';
|
|
|
+ gamepad->hidDeviceVendorID = 0;
|
|
|
+ gamepad->hidDeviceProductID = 0;
|
|
|
+ memset(gamepad->axis, 0, sizeof(gamepad->axis));
|
|
|
+ memset(gamepad->buttons, 0, sizeof(gamepad->buttons));
|
|
|
+}
|
|
|
+
|
|
|
+static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex) {
|
|
|
+ double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
|
|
|
+ double min = IOHIDElementGetLogicalMin(elementRef);
|
|
|
+ double max = IOHIDElementGetLogicalMax(elementRef);
|
|
|
+ double normalize = (rawValue - min) / (max - min);
|
|
|
+ iron_internal_gamepad_trigger_button(gamepad->padIndex, buttonIndex, normalize);
|
|
|
+}
|
|
|
+
|
|
|
+static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex) {
|
|
|
+ double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
|
|
|
+ double min = IOHIDElementGetPhysicalMin(elementRef);
|
|
|
+ double max = IOHIDElementGetPhysicalMax(elementRef);
|
|
|
+ double normalize = normalize = (((rawValue - min) / (max - min)) * 2) - 1;
|
|
|
+ if (axisIndex % 2 == 1) {
|
|
|
+ normalize = -normalize;
|
|
|
+ }
|
|
|
+ iron_internal_gamepad_trigger_axis(gamepad->padIndex, axisIndex, normalize);
|
|
|
+}
|
|
|
+
|
|
|
+static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef) {}
|
|
|
+
|
|
|
+static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender) {
|
|
|
+ struct HIDGamepad *pad = (struct HIDGamepad *)inContext;
|
|
|
+ do {
|
|
|
+ IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout((IOHIDQueueRef)inSender, 0.);
|
|
|
+ if (!valueRef) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
|
|
|
+ IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
|
|
|
+
|
|
|
+ for (int i = 0, c = sizeof(pad->buttons); i < c; ++i) {
|
|
|
+ if (cookie == pad->buttons[i]) {
|
|
|
+ buttonChanged(pad, elementRef, valueRef, i);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0, c = sizeof(pad->axis); i < c; ++i) {
|
|
|
+ if (cookie == pad->axis[i]) {
|
|
|
+ axisChanged(pad, elementRef, valueRef, i);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CFRelease(valueRef);
|
|
|
+ } while (1);
|
|
|
+}
|
|
|
+
|
|
|
+const char *iron_gamepad_vendor(int gamepad) {
|
|
|
+ return "unknown";
|
|
|
+}
|
|
|
+
|
|
|
+const char *iron_gamepad_product_name(int gamepad) {
|
|
|
+ return "unknown";
|
|
|
+}
|
|
|
+
|
|
|
+static int initHIDManager(struct HIDManager *manager);
|
|
|
+static bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef);
|
|
|
+static CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage);
|
|
|
+static void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
|
|
|
+static void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
|
|
|
+
|
|
|
+void HIDManager_init(struct HIDManager *manager) {
|
|
|
+ manager->managerRef = 0x0;
|
|
|
+ initHIDManager(manager);
|
|
|
+}
|
|
|
+
|
|
|
+void HIDManager_destroy(struct HIDManager *manager) {
|
|
|
+ if (manager->managerRef) {
|
|
|
+ IOHIDManagerUnscheduleFromRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+ IOHIDManagerClose(manager->managerRef, kIOHIDOptionsTypeNone);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int initHIDManager(struct HIDManager *manager) {
|
|
|
+ manager->managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
|
|
+ if (CFGetTypeID(manager->managerRef) == IOHIDManagerGetTypeID()) {
|
|
|
+
|
|
|
+ CFMutableArrayRef matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
|
|
+ if (matchingCFArrayRef) {
|
|
|
+ CFDictionaryRef matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
|
|
+ addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
|
|
|
+ matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
|
|
|
+ addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ iron_error("%s: CFArrayCreateMutable failed.", __PRETTY_FUNCTION__);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ IOHIDManagerSetDeviceMatchingMultiple(manager->managerRef, matchingCFArrayRef);
|
|
|
+ CFRelease(matchingCFArrayRef);
|
|
|
+ IOHIDManagerOpen(manager->managerRef, kIOHIDOptionsTypeNone);
|
|
|
+ IOHIDManagerRegisterDeviceMatchingCallback(manager->managerRef, deviceConnected, manager);
|
|
|
+ IOHIDManagerRegisterDeviceRemovalCallback(manager->managerRef, deviceRemoved, manager);
|
|
|
+ IOHIDManagerScheduleWithRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef) {
|
|
|
+ if (matchingCFDictRef) {
|
|
|
+ CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
|
|
+ CFRelease(matchingCFDictRef);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage) {
|
|
|
+ CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
+ if (result) {
|
|
|
+ if (inUsagePage) {
|
|
|
+ CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage);
|
|
|
+ if (pageCFNumberRef) {
|
|
|
+ CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsagePageKey), pageCFNumberRef);
|
|
|
+ CFRelease(pageCFNumberRef);
|
|
|
+ if (inUsage) {
|
|
|
+ CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage);
|
|
|
+ if (usageCFNumberRef) {
|
|
|
+ CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
|
|
|
+ CFRelease(usageCFNumberRef);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
|
+ struct HIDManager *manager = (struct HIDManager *)inContext;
|
|
|
+ struct HIDManagerDeviceRecord *device = &manager->devices[0];
|
|
|
+ for (int i = 0; i < IRON_MAX_HID_DEVICES; ++i, ++device) {
|
|
|
+ if (!device->connected) {
|
|
|
+ device->connected = true;
|
|
|
+ device->device = inIOHIDDeviceRef;
|
|
|
+ HIDGamepad_bind(&device->pad, inIOHIDDeviceRef, i);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
|
|
|
+ struct HIDManager *manager = (struct HIDManager *)inContext;
|
|
|
+ struct HIDManagerDeviceRecord *device = &manager->devices[0];
|
|
|
+ for (int i = 0; i < IRON_MAX_HID_DEVICES; ++i, ++device) {
|
|
|
+ if (device->connected && device->device == inIOHIDDeviceRef) {
|
|
|
+ device->connected = false;
|
|
|
+ device->device = NULL;
|
|
|
+ HIDGamepad_unbind(&device->pad);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|