From 0b8e8ad4f2067313d677d3c05b65b404670a8838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 1 Feb 2023 20:23:46 +0800 Subject: [PATCH] Gamepad (macOS): add support --- CMakeLists.txt | 2 +- src/detection/gamepad/gamepad_apple.c | 41 +++++++++++++++++++++++++++ src/util/apple/cf_helpers.h | 13 +++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/detection/gamepad/gamepad_apple.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a97a77fe..27853f760 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,7 +464,7 @@ elseif(APPLE) src/detection/gpu/gpu_apple.c src/detection/host/host_apple.c src/detection/localip/localip_linux.c - src/detection/gamepad/gamepad_nosupport.c + src/detection/gamepad/gamepad_apple.c src/detection/media/media_apple.m src/detection/memory/memory_apple.c src/detection/opengl/opengl_apple.c diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c new file mode 100644 index 000000000..154f1c587 --- /dev/null +++ b/src/detection/gamepad/gamepad_apple.c @@ -0,0 +1,41 @@ +#include "gamepad.h" +#include "util/apple/cf_helpers.h" + +#include +#include + +static void enumSet(const void* value, void *context) +{ + CFStringRef product = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDProductKey)); + CFStringRef serialNumber = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDSerialNumberKey)); + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd((FFlist*) context); + ffStrbufInit(&device->identifier); + ffCfStrGetString(serialNumber, &device->identifier); + ffStrbufInit(&device->name); + ffCfStrGetString(product, &device->name); +} + +const char* ffDetectGamepad(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* devices /* List of FFGamepadDevice */) +{ + IOHIDManagerRef FF_CFTYPE_AUTO_RELEASE manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone) != kIOReturnSuccess) + return "IOHIDManagerOpen() failed"; + + CFNumberRef FF_CFTYPE_AUTO_RELEASE genericDesktop = ffCfCreateInt(kHIDPage_GenericDesktop); + CFNumberRef FF_CFTYPE_AUTO_RELEASE gamePad = ffCfCreateInt(kHIDUsage_GD_GamePad); + CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){ + CFSTR(kIOHIDDeviceUsagePageKey), + CFSTR(kIOHIDDeviceUsageKey) + }, (const void **)(CFNumberRef[]){ + genericDesktop, + gamePad + }, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + IOHIDManagerSetDeviceMatching(manager, matching); + + CFSetRef FF_CFTYPE_AUTO_RELEASE set = IOHIDManagerCopyDevices(manager); + if (set) + CFSetApplyFunction(set, &enumSet, devices); + IOHIDManagerClose(manager, 0); + + return NULL; +} diff --git a/src/util/apple/cf_helpers.h b/src/util/apple/cf_helpers.h index d3cb66d43..52755bb8b 100644 --- a/src/util/apple/cf_helpers.h +++ b/src/util/apple/cf_helpers.h @@ -13,4 +13,17 @@ const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result); const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result); +static inline CFNumberRef ffCfCreateInt(int value) +{ + return CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value); +} + +static inline void cfReleaseWrapper(void* type) +{ + if (*(CFTypeRef*) type) + CFRelease(*(CFTypeRef*) type); +} + +#define FF_CFTYPE_AUTO_RELEASE __attribute__((__cleanup__(cfReleaseWrapper))) + #endif