mirror of
https://github.com/gwm17/glfw.git
synced 2024-11-27 04:28:52 -05:00
Add support for joystick hot swapping on OS X.
This commit is contained in:
parent
19a28e2c9f
commit
1a96c294ee
|
@ -33,17 +33,17 @@
|
||||||
#include <IOKit/hid/IOHIDKeys.h>
|
#include <IOKit/hid/IOHIDKeys.h>
|
||||||
|
|
||||||
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
|
||||||
_GLFWjoystickIOKit iokit_js[GLFW_JOYSTICK_LAST + 1]
|
_GLFWjoystickIOKit iokit_js
|
||||||
|
|
||||||
|
|
||||||
// IOKit-specific per-joystick data
|
// IOKit-specific per-joystick data
|
||||||
//
|
//
|
||||||
typedef struct _GLFWjoystickIOKit
|
typedef struct _GLFWjoydevice
|
||||||
{
|
{
|
||||||
int present;
|
int present;
|
||||||
char name[256];
|
char name[256];
|
||||||
|
|
||||||
IOHIDDeviceInterface** interface;
|
IOHIDDeviceRef deviceRef;
|
||||||
|
|
||||||
CFMutableArrayRef axisElements;
|
CFMutableArrayRef axisElements;
|
||||||
CFMutableArrayRef buttonElements;
|
CFMutableArrayRef buttonElements;
|
||||||
|
@ -51,7 +51,16 @@ typedef struct _GLFWjoystickIOKit
|
||||||
|
|
||||||
float* axes;
|
float* axes;
|
||||||
unsigned char* buttons;
|
unsigned char* buttons;
|
||||||
|
} _GLFWjoydevice;
|
||||||
|
|
||||||
|
|
||||||
|
// IOKit-specific joystick API data
|
||||||
|
//
|
||||||
|
typedef struct _GLFWjoystickIOKit
|
||||||
|
{
|
||||||
|
_GLFWjoydevice devices[GLFW_JOYSTICK_LAST + 1];
|
||||||
|
|
||||||
|
IOHIDManagerRef managerRef;
|
||||||
} _GLFWjoystickIOKit;
|
} _GLFWjoystickIOKit;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IOHIDElementCookie cookie;
|
IOHIDElementRef elementRef;
|
||||||
|
|
||||||
long min;
|
long min;
|
||||||
long max;
|
long max;
|
||||||
|
@ -55,20 +55,17 @@ typedef struct
|
||||||
|
|
||||||
static void getElementsCFArrayHandler(const void* value, void* parameter);
|
static void getElementsCFArrayHandler(const void* value, void* parameter);
|
||||||
|
|
||||||
|
|
||||||
// Adds an element to the specified joystick
|
// Adds an element to the specified joystick
|
||||||
//
|
//
|
||||||
static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRef)
|
static void addJoystickElement(_GLFWjoydevice* joystick, IOHIDElementRef elementRef)
|
||||||
{
|
{
|
||||||
long elementType, usagePage, usage;
|
IOHIDElementType elementType;
|
||||||
|
long usagePage, usage;
|
||||||
CFMutableArrayRef elementsArray = NULL;
|
CFMutableArrayRef elementsArray = NULL;
|
||||||
|
|
||||||
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementTypeKey)),
|
elementType = IOHIDElementGetType(elementRef);
|
||||||
kCFNumberLongType, &elementType);
|
usagePage = IOHIDElementGetUsagePage(elementRef);
|
||||||
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsagePageKey)),
|
usage = IOHIDElementGetUsage(elementRef);
|
||||||
kCFNumberLongType, &usagePage);
|
|
||||||
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsageKey)),
|
|
||||||
kCFNumberLongType, &usage);
|
|
||||||
|
|
||||||
if ((elementType == kIOHIDElementTypeInput_Axis) ||
|
if ((elementType == kIOHIDElementTypeInput_Axis) ||
|
||||||
(elementType == kIOHIDElementTypeInput_Button) ||
|
(elementType == kIOHIDElementTypeInput_Button) ||
|
||||||
|
@ -108,28 +105,19 @@ static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRe
|
||||||
|
|
||||||
if (elementsArray)
|
if (elementsArray)
|
||||||
{
|
{
|
||||||
long number;
|
|
||||||
CFTypeRef numberRef;
|
|
||||||
_GLFWjoyelement* element = calloc(1, sizeof(_GLFWjoyelement));
|
_GLFWjoyelement* element = calloc(1, sizeof(_GLFWjoyelement));
|
||||||
|
|
||||||
CFArrayAppendValue(elementsArray, element);
|
CFArrayAppendValue(elementsArray, element);
|
||||||
|
|
||||||
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementCookieKey));
|
element->elementRef = elementRef;
|
||||||
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
|
|
||||||
element->cookie = (IOHIDElementCookie) number;
|
|
||||||
|
|
||||||
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMinKey));
|
element->minReport = IOHIDElementGetLogicalMin(elementRef);
|
||||||
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
|
element->maxReport = IOHIDElementGetLogicalMax(elementRef);
|
||||||
element->minReport = element->min = number;
|
|
||||||
|
|
||||||
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMaxKey));
|
|
||||||
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
|
|
||||||
element->maxReport = element->max = number;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CFTypeRef array = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementKey));
|
CFArrayRef array = IOHIDElementGetChildren(elementRef);
|
||||||
if (array)
|
if (array)
|
||||||
{
|
{
|
||||||
if (CFGetTypeID(array) == CFArrayGetTypeID())
|
if (CFGetTypeID(array) == CFArrayGetTypeID())
|
||||||
|
@ -145,40 +133,43 @@ static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRe
|
||||||
//
|
//
|
||||||
static void getElementsCFArrayHandler(const void* value, void* parameter)
|
static void getElementsCFArrayHandler(const void* value, void* parameter)
|
||||||
{
|
{
|
||||||
if (CFGetTypeID(value) == CFDictionaryGetTypeID())
|
if (CFGetTypeID(value) == IOHIDElementGetTypeID())
|
||||||
addJoystickElement((_GLFWjoystickIOKit*) parameter, (CFTypeRef) value);
|
addJoystickElement((_GLFWjoydevice*) parameter, (IOHIDElementRef) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the value of the specified element of the specified joystick
|
// Returns the value of the specified element of the specified joystick
|
||||||
//
|
//
|
||||||
static long getElementValue(_GLFWjoystickIOKit* joystick, _GLFWjoyelement* element)
|
static long getElementValue(_GLFWjoydevice* joystick, _GLFWjoyelement* element)
|
||||||
{
|
{
|
||||||
IOReturn result = kIOReturnSuccess;
|
IOReturn result = kIOReturnSuccess;
|
||||||
IOHIDEventStruct hidEvent;
|
IOHIDValueRef valueRef;
|
||||||
hidEvent.value = 0;
|
long value = 0;
|
||||||
|
|
||||||
if (joystick && element && joystick->interface)
|
if (joystick && element && joystick->deviceRef)
|
||||||
{
|
{
|
||||||
result = (*(joystick->interface))->getElementValue(joystick->interface,
|
result = IOHIDDeviceGetValue(joystick->deviceRef,
|
||||||
element->cookie,
|
element->elementRef,
|
||||||
&hidEvent);
|
&valueRef);
|
||||||
|
|
||||||
if (kIOReturnSuccess == result)
|
if (kIOReturnSuccess == result)
|
||||||
{
|
{
|
||||||
|
value = IOHIDValueGetIntegerValue(valueRef);
|
||||||
|
|
||||||
// Record min and max for auto calibration
|
// Record min and max for auto calibration
|
||||||
if (hidEvent.value < element->minReport)
|
if (value < element->minReport)
|
||||||
element->minReport = hidEvent.value;
|
element->minReport = value;
|
||||||
if (hidEvent.value > element->maxReport)
|
if (value > element->maxReport)
|
||||||
element->maxReport = hidEvent.value;
|
element->maxReport = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto user scale
|
// Auto user scale
|
||||||
return (long) hidEvent.value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the specified joystick
|
// Removes the specified joystick
|
||||||
//
|
//
|
||||||
static void removeJoystick(_GLFWjoystickIOKit* joystick)
|
static void removeJoystick(_GLFWjoydevice* joystick)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -188,29 +179,22 @@ static void removeJoystick(_GLFWjoystickIOKit* joystick)
|
||||||
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
|
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
|
||||||
free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i));
|
free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i));
|
||||||
CFArrayRemoveAllValues(joystick->axisElements);
|
CFArrayRemoveAllValues(joystick->axisElements);
|
||||||
|
CFRelease(joystick->axisElements);
|
||||||
|
|
||||||
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
|
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
|
||||||
free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i));
|
free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i));
|
||||||
CFArrayRemoveAllValues(joystick->buttonElements);
|
CFArrayRemoveAllValues(joystick->buttonElements);
|
||||||
|
CFRelease(joystick->buttonElements);
|
||||||
|
|
||||||
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
|
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
|
||||||
free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i));
|
free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i));
|
||||||
CFArrayRemoveAllValues(joystick->hatElements);
|
CFArrayRemoveAllValues(joystick->hatElements);
|
||||||
|
CFRelease(joystick->hatElements);
|
||||||
|
|
||||||
free(joystick->axes);
|
free(joystick->axes);
|
||||||
free(joystick->buttons);
|
free(joystick->buttons);
|
||||||
|
|
||||||
(*(joystick->interface))->close(joystick->interface);
|
memset(joystick, 0, sizeof(_GLFWjoydevice));
|
||||||
(*(joystick->interface))->Release(joystick->interface);
|
|
||||||
|
|
||||||
memset(joystick, 0, sizeof(_GLFWjoystickIOKit));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback for user-initiated joystick removal
|
|
||||||
//
|
|
||||||
static void removalCallback(void* target, IOReturn result, void* refcon, void* sender)
|
|
||||||
{
|
|
||||||
removeJoystick((_GLFWjoystickIOKit*) refcon);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polls for joystick events and updates GLFW state
|
// Polls for joystick events and updates GLFW state
|
||||||
|
@ -223,7 +207,7 @@ static void pollJoystickEvents(void)
|
||||||
{
|
{
|
||||||
CFIndex i;
|
CFIndex i;
|
||||||
int buttonIndex = 0;
|
int buttonIndex = 0;
|
||||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||||
|
|
||||||
if (!joystick->present)
|
if (!joystick->present)
|
||||||
continue;
|
continue;
|
||||||
|
@ -276,6 +260,107 @@ static void pollJoystickEvents(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback for user-initiated joystick addition
|
||||||
|
//
|
||||||
|
static void matchCallback(void* context, IOReturn result, void* sender, IOHIDDeviceRef deviceRef)
|
||||||
|
{
|
||||||
|
_GLFWjoydevice* joystick;
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
joystick = _glfw.iokit_js.devices + joy;
|
||||||
|
|
||||||
|
if (!joystick->present)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (joystick->deviceRef == deviceRef)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
|
{
|
||||||
|
joystick = _glfw.iokit_js.devices + joy;
|
||||||
|
|
||||||
|
if (!joystick->present)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (joy > GLFW_JOYSTICK_LAST)
|
||||||
|
return;
|
||||||
|
|
||||||
|
joystick->present = GL_TRUE;
|
||||||
|
joystick->deviceRef = deviceRef;
|
||||||
|
|
||||||
|
CFStringRef name = IOHIDDeviceGetProperty(deviceRef, CFSTR(kIOHIDProductKey));
|
||||||
|
CFStringGetCString(name,
|
||||||
|
joystick->name,
|
||||||
|
sizeof(joystick->name),
|
||||||
|
kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||||
|
joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||||
|
joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
|
||||||
|
|
||||||
|
CFArrayRef arrayRef = IOHIDDeviceCopyMatchingElements(deviceRef, NULL, kIOHIDOptionsTypeNone);
|
||||||
|
CFRange range = { 0, CFArrayGetCount(arrayRef) };
|
||||||
|
CFArrayApplyFunction(arrayRef,
|
||||||
|
range,
|
||||||
|
getElementsCFArrayHandler,
|
||||||
|
(void*) joystick);
|
||||||
|
|
||||||
|
CFRelease(arrayRef);
|
||||||
|
|
||||||
|
joystick->axes = calloc(CFArrayGetCount(joystick->axisElements),
|
||||||
|
sizeof(float));
|
||||||
|
joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) +
|
||||||
|
CFArrayGetCount(joystick->hatElements) * 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback for user-initiated joystick removal
|
||||||
|
//
|
||||||
|
static void removeCallback(void* context, IOReturn result, void* sender, IOHIDDeviceRef deviceRef)
|
||||||
|
{
|
||||||
|
int joy;
|
||||||
|
|
||||||
|
for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) {
|
||||||
|
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||||
|
|
||||||
|
if (joystick->deviceRef == deviceRef) {
|
||||||
|
removeJoystick(joystick);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a dictionary to match against devices with the specified usage page and usage
|
||||||
|
//
|
||||||
|
static CFMutableDictionaryRef createMatchingDictionary(long usagePage, long usage)
|
||||||
|
{
|
||||||
|
CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||||
|
0,
|
||||||
|
&kCFTypeDictionaryKeyCallBacks,
|
||||||
|
&kCFTypeDictionaryValueCallBacks);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage);
|
||||||
|
if (pageRef)
|
||||||
|
{
|
||||||
|
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsagePageKey), pageRef);
|
||||||
|
CFRelease(pageRef);
|
||||||
|
|
||||||
|
CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
|
||||||
|
if (usageRef)
|
||||||
|
{
|
||||||
|
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageRef);
|
||||||
|
CFRelease(usageRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
////// GLFW internal API //////
|
////// GLFW internal API //////
|
||||||
|
@ -285,177 +370,64 @@ static void pollJoystickEvents(void)
|
||||||
//
|
//
|
||||||
void _glfwInitJoysticks(void)
|
void _glfwInitJoysticks(void)
|
||||||
{
|
{
|
||||||
int joy = 0;
|
CFMutableArrayRef matchingCFArrayRef;
|
||||||
IOReturn result = kIOReturnSuccess;
|
|
||||||
mach_port_t masterPort = 0;
|
|
||||||
io_iterator_t objectIterator = 0;
|
|
||||||
CFMutableDictionaryRef hidMatchDictionary = NULL;
|
|
||||||
io_object_t ioHIDDeviceObject = 0;
|
|
||||||
|
|
||||||
result = IOMasterPort(bootstrap_port, &masterPort);
|
_glfw.iokit_js.managerRef = IOHIDManagerCreate(kCFAllocatorDefault,
|
||||||
hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
|
kIOHIDOptionsTypeNone);
|
||||||
if (kIOReturnSuccess != result || !hidMatchDictionary)
|
|
||||||
|
matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||||
|
if (matchingCFArrayRef)
|
||||||
{
|
{
|
||||||
if (hidMatchDictionary)
|
CFDictionaryRef matchingCFDictRef = createMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
||||||
CFRelease(hidMatchDictionary);
|
if (matchingCFDictRef)
|
||||||
|
{
|
||||||
|
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||||
|
CFRelease(matchingCFDictRef);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
matchingCFDictRef = createMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
|
||||||
|
if (matchingCFDictRef)
|
||||||
|
{
|
||||||
|
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||||
|
CFRelease(matchingCFDictRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingCFDictRef = createMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController);
|
||||||
|
if (matchingCFDictRef)
|
||||||
|
{
|
||||||
|
CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
|
||||||
|
CFRelease(matchingCFDictRef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result = IOServiceGetMatchingServices(masterPort,
|
IOHIDManagerSetDeviceMatchingMultiple(_glfw.iokit_js.managerRef, matchingCFArrayRef);
|
||||||
hidMatchDictionary,
|
CFRelease(matchingCFArrayRef);
|
||||||
&objectIterator);
|
|
||||||
if (result != kIOReturnSuccess)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!objectIterator)
|
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.iokit_js.managerRef, &matchCallback, NULL);
|
||||||
{
|
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.iokit_js.managerRef, &removeCallback, NULL);
|
||||||
// There are no joysticks
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ioHIDDeviceObject = IOIteratorNext(objectIterator)))
|
IOHIDManagerScheduleWithRunLoop(_glfw.iokit_js.managerRef, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
|
||||||
{
|
|
||||||
CFMutableDictionaryRef propsRef = NULL;
|
|
||||||
CFTypeRef valueRef = NULL;
|
|
||||||
kern_return_t result;
|
|
||||||
|
|
||||||
IOCFPlugInInterface** ppPlugInInterface = NULL;
|
IOHIDManagerOpen(_glfw.iokit_js.managerRef, kIOHIDOptionsTypeNone);
|
||||||
HRESULT plugInResult = S_OK;
|
|
||||||
SInt32 score = 0;
|
|
||||||
|
|
||||||
long usagePage = 0;
|
// Execute the run loop once in order to register any initially-attached joysticks
|
||||||
long usage = 0;
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||||
|
|
||||||
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
|
|
||||||
CFSTR(kIOHIDPrimaryUsagePageKey),
|
|
||||||
kCFAllocatorDefault, kNilOptions);
|
|
||||||
if (valueRef)
|
|
||||||
{
|
|
||||||
CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage);
|
|
||||||
CFRelease(valueRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
|
|
||||||
CFSTR(kIOHIDPrimaryUsageKey),
|
|
||||||
kCFAllocatorDefault, kNilOptions);
|
|
||||||
if (valueRef)
|
|
||||||
{
|
|
||||||
CFNumberGetValue(valueRef, kCFNumberLongType, &usage);
|
|
||||||
CFRelease(valueRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usagePage != kHIDPage_GenericDesktop)
|
|
||||||
{
|
|
||||||
// This device is not relevant to GLFW
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((usage != kHIDUsage_GD_Joystick &&
|
|
||||||
usage != kHIDUsage_GD_GamePad &&
|
|
||||||
usage != kHIDUsage_GD_MultiAxisController))
|
|
||||||
{
|
|
||||||
// This device is not relevant to GLFW
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = IORegistryEntryCreateCFProperties(ioHIDDeviceObject,
|
|
||||||
&propsRef,
|
|
||||||
kCFAllocatorDefault,
|
|
||||||
kNilOptions);
|
|
||||||
|
|
||||||
if (result != kIOReturnSuccess)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
|
||||||
joystick->present = GL_TRUE;
|
|
||||||
|
|
||||||
result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject,
|
|
||||||
kIOHIDDeviceUserClientTypeID,
|
|
||||||
kIOCFPlugInInterfaceID,
|
|
||||||
&ppPlugInInterface,
|
|
||||||
&score);
|
|
||||||
|
|
||||||
if (kIOReturnSuccess != result)
|
|
||||||
{
|
|
||||||
CFRelease(propsRef);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
plugInResult = (*ppPlugInInterface)->QueryInterface(
|
|
||||||
ppPlugInInterface,
|
|
||||||
CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
|
|
||||||
(void *) &(joystick->interface));
|
|
||||||
|
|
||||||
if (plugInResult != S_OK)
|
|
||||||
{
|
|
||||||
CFRelease(propsRef);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*ppPlugInInterface)->Release(ppPlugInInterface);
|
|
||||||
|
|
||||||
(*(joystick->interface))->open(joystick->interface, 0);
|
|
||||||
(*(joystick->interface))->setRemovalCallback(joystick->interface,
|
|
||||||
removalCallback,
|
|
||||||
joystick,
|
|
||||||
joystick);
|
|
||||||
|
|
||||||
// Get product string
|
|
||||||
valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDProductKey));
|
|
||||||
if (valueRef)
|
|
||||||
{
|
|
||||||
CFStringGetCString(valueRef,
|
|
||||||
joystick->name,
|
|
||||||
sizeof(joystick->name),
|
|
||||||
kCFStringEncodingUTF8);
|
|
||||||
}
|
|
||||||
|
|
||||||
joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
|
|
||||||
joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
|
|
||||||
joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
|
|
||||||
|
|
||||||
valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDElementKey));
|
|
||||||
if (CFGetTypeID(valueRef) == CFArrayGetTypeID())
|
|
||||||
{
|
|
||||||
CFRange range = { 0, CFArrayGetCount(valueRef) };
|
|
||||||
CFArrayApplyFunction(valueRef,
|
|
||||||
range,
|
|
||||||
getElementsCFArrayHandler,
|
|
||||||
(void*) joystick);
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(propsRef);
|
|
||||||
|
|
||||||
joystick->axes = calloc(CFArrayGetCount(joystick->axisElements),
|
|
||||||
sizeof(float));
|
|
||||||
joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) +
|
|
||||||
CFArrayGetCount(joystick->hatElements) * 4, 1);
|
|
||||||
|
|
||||||
joy++;
|
|
||||||
if (joy > GLFW_JOYSTICK_LAST)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close all opened joystick handles
|
// Close all opened joystick handles
|
||||||
//
|
//
|
||||||
void _glfwTerminateJoysticks(void)
|
void _glfwTerminateJoysticks(void)
|
||||||
{
|
{
|
||||||
int i;
|
int joy;
|
||||||
|
|
||||||
for (i = 0; i < GLFW_JOYSTICK_LAST + 1; i++)
|
for (joy = 0; joy <= GLFW_JOYSTICK_LAST; joy++)
|
||||||
{
|
{
|
||||||
_GLFWjoystickIOKit* joystick = &_glfw.iokit_js[i];
|
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||||
removeJoystick(joystick);
|
removeJoystick(joystick);
|
||||||
|
|
||||||
if (joystick->axisElements)
|
|
||||||
CFRelease(joystick->axisElements);
|
|
||||||
if (joystick->buttonElements)
|
|
||||||
CFRelease(joystick->buttonElements);
|
|
||||||
if (joystick->hatElements)
|
|
||||||
CFRelease(joystick->hatElements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFRelease(_glfw.iokit_js.managerRef);
|
||||||
|
_glfw.iokit_js.managerRef = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -467,12 +439,12 @@ int _glfwPlatformJoystickPresent(int joy)
|
||||||
{
|
{
|
||||||
pollJoystickEvents();
|
pollJoystickEvents();
|
||||||
|
|
||||||
return _glfw.iokit_js[joy].present;
|
return _glfw.iokit_js.devices[joy].present;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||||
{
|
{
|
||||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||||
|
|
||||||
pollJoystickEvents();
|
pollJoystickEvents();
|
||||||
|
|
||||||
|
@ -485,7 +457,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
|
||||||
|
|
||||||
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
|
||||||
{
|
{
|
||||||
_GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy;
|
_GLFWjoydevice* joystick = _glfw.iokit_js.devices + joy;
|
||||||
|
|
||||||
pollJoystickEvents();
|
pollJoystickEvents();
|
||||||
|
|
||||||
|
@ -501,6 +473,6 @@ const char* _glfwPlatformGetJoystickName(int joy)
|
||||||
{
|
{
|
||||||
pollJoystickEvents();
|
pollJoystickEvents();
|
||||||
|
|
||||||
return _glfw.iokit_js[joy].name;
|
return _glfw.iokit_js.devices[joy].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user