37#include <mach/mach_error.h>
39#include <CoreFoundation/CoreFoundation.h>
40#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
60 IOHIDValueRef valueRef;
65 if (IOHIDDeviceGetValue(js->ns.device,
67 &valueRef) == kIOReturnSuccess)
69 value = IOHIDValueGetIntegerValue(valueRef);
78static CFComparisonResult compareElements(
const void* fp,
85 return kCFCompareLessThan;
87 return kCFCompareGreaterThan;
89 return kCFCompareLessThan;
91 return kCFCompareGreaterThan;
92 return kCFCompareEqualTo;
104 for (i = 0; i < CFArrayGetCount(js->ns.
axes); i++)
105 free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));
106 CFRelease(js->ns.
axes);
108 for (i = 0; i < CFArrayGetCount(js->ns.
buttons); i++)
109 free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i));
112 for (i = 0; i < CFArrayGetCount(js->ns.
hats); i++)
113 free((void*) CFArrayGetValueAtIndex(js->ns.hats, i));
114 CFRelease(js->ns.
hats);
122static void matchCallback(
void* context,
125 IOHIDDeviceRef device)
132 uint32_t vendor = 0, product = 0, version = 0;
134 CFMutableArrayRef axes, buttons, hats;
142 axes = CFArrayCreateMutable(
NULL, 0,
NULL);
143 buttons = CFArrayCreateMutable(
NULL, 0,
NULL);
144 hats = CFArrayCreateMutable(
NULL, 0,
NULL);
146 property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
149 CFStringGetCString(property,
152 kCFStringEncodingUTF8);
155 strncpy(name,
"Unknown",
sizeof(name));
157 property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
159 CFNumberGetValue(property, kCFNumberSInt32Type, &vendor);
161 property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
163 CFNumberGetValue(property, kCFNumberSInt32Type, &product);
165 property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey));
167 CFNumberGetValue(property, kCFNumberSInt32Type, &version);
170 if (vendor && product)
172 sprintf(guid,
"03000000%02x%02x0000%02x%02x0000%02x%02x0000",
179 sprintf(guid,
"05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
180 name[0], name[1], name[2], name[3],
181 name[4], name[5], name[6], name[7],
182 name[8], name[9], name[10]);
185 CFArrayRef elements =
186 IOHIDDeviceCopyMatchingElements(device,
NULL, kIOHIDOptionsTypeNone);
188 for (i = 0; i < CFArrayGetCount(elements); i++)
190 IOHIDElementRef
native = (IOHIDElementRef)
191 CFArrayGetValueAtIndex(elements, i);
192 if (CFGetTypeID(
native) != IOHIDElementGetTypeID())
195 const IOHIDElementType type = IOHIDElementGetType(
native);
196 if ((type != kIOHIDElementTypeInput_Axis) &&
197 (type != kIOHIDElementTypeInput_Button) &&
198 (type != kIOHIDElementTypeInput_Misc))
203 CFMutableArrayRef target =
NULL;
207 if (page == kHIDPage_GenericDesktop)
214 case kHIDUsage_GD_Rx:
215 case kHIDUsage_GD_Ry:
216 case kHIDUsage_GD_Rz:
217 case kHIDUsage_GD_Slider:
218 case kHIDUsage_GD_Dial:
219 case kHIDUsage_GD_Wheel:
222 case kHIDUsage_GD_Hatswitch:
225 case kHIDUsage_GD_DPadUp:
226 case kHIDUsage_GD_DPadRight:
227 case kHIDUsage_GD_DPadDown:
228 case kHIDUsage_GD_DPadLeft:
229 case kHIDUsage_GD_SystemMainMenu:
230 case kHIDUsage_GD_Select:
231 case kHIDUsage_GD_Start:
236 else if (page == kHIDPage_Simulation)
240 case kHIDUsage_Sim_Accelerator:
241 case kHIDUsage_Sim_Brake:
242 case kHIDUsage_Sim_Throttle:
243 case kHIDUsage_Sim_Rudder:
244 case kHIDUsage_Sim_Steering:
249 else if (page == kHIDPage_Button || page == kHIDPage_Consumer)
257 element->
index = (int) CFArrayGetCount(target);
260 CFArrayAppendValue(target, element);
266 CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)),
267 compareElements,
NULL);
268 CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)),
269 compareElements,
NULL);
270 CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)),
271 compareElements,
NULL);
274 (
int) CFArrayGetCount(axes),
275 (
int) CFArrayGetCount(buttons),
276 (
int) CFArrayGetCount(hats));
278 js->ns.device = device;
288static void removeCallback(
void* context,
291 IOHIDDeviceRef device)
299 closeJoystick(_glfw.joysticks + jid);
312 CFMutableArrayRef matching;
313 const long usages[] =
315 kHIDUsage_GD_Joystick,
316 kHIDUsage_GD_GamePad,
317 kHIDUsage_GD_MultiAxisController
320 _glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
321 kIOHIDOptionsTypeNone);
323 matching = CFArrayCreateMutable(kCFAllocatorDefault,
325 &kCFTypeArrayCallBacks);
332 for (
size_t i = 0; i <
sizeof(usages) /
sizeof(
long); i++)
334 const long page = kHIDPage_GenericDesktop;
336 CFMutableDictionaryRef dict =
337 CFDictionaryCreateMutable(kCFAllocatorDefault,
339 &kCFTypeDictionaryKeyCallBacks,
340 &kCFTypeDictionaryValueCallBacks);
344 CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
347 CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
350 if (pageRef && usageRef)
352 CFDictionarySetValue(dict,
353 CFSTR(kIOHIDDeviceUsagePageKey),
355 CFDictionarySetValue(dict,
356 CFSTR(kIOHIDDeviceUsageKey),
358 CFArrayAppendValue(matching, dict);
369 IOHIDManagerSetDeviceMatchingMultiple(
_glfw.ns.hidManager, matching);
372 IOHIDManagerRegisterDeviceMatchingCallback(
_glfw.ns.hidManager,
373 &matchCallback,
NULL);
374 IOHIDManagerRegisterDeviceRemovalCallback(
_glfw.ns.hidManager,
375 &removeCallback,
NULL);
376 IOHIDManagerScheduleWithRunLoop(
_glfw.ns.hidManager,
378 kCFRunLoopDefaultMode);
379 IOHIDManagerOpen(
_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
383 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0,
false);
394 if (
_glfw.ns.hidManager)
396 CFRelease(
_glfw.ns.hidManager);
408 for (i = 0; i < CFArrayGetCount(js->ns.
axes); i++)
411 CFArrayGetValueAtIndex(js->ns.
axes, i);
413 const long raw = getElementValue(js, axis);
425 const float value = (2.f * (raw - axis->
minimum) / size) - 1.f;
435 for (i = 0; i < CFArrayGetCount(js->ns.
buttons); i++)
438 CFArrayGetValueAtIndex(js->ns.
buttons, i);
439 const char value = getElementValue(js, button) - button->
minimum;
444 for (i = 0; i < CFArrayGetCount(js->ns.
hats); i++)
446 const int states[9] =
460 CFArrayGetValueAtIndex(js->ns.
hats, i);
461 long state = getElementValue(js, hat) - hat->
minimum;
462 if (state < 0 || state > 8)
474 if ((strncmp(guid + 4,
"000000000000", 12) == 0) &&
475 (strncmp(guid + 20,
"000000000000", 12) == 0))
478 strncpy(original, guid,
sizeof(original) - 1);
479 sprintf(guid,
"03000000%.4s0000%.4s000000000000",
480 original, original + 16);
void _glfwPlatformTerminateJoysticks(void)
int _glfwPlatformPollJoystick(_GLFWjoystick *js, int mode)
GLFWbool _glfwPlatformInitJoysticks(void)
void _glfwPlatformUpdateGamepadGUID(char *guid)
#define GLFW_DISCONNECTED
#define GLFW_PLATFORM_ERROR
A platform-specific error occurred that does not match any of the more specific categories.
#define GLFW_HAT_LEFT_DOWN
#define GLFW_HAT_RIGHT_UP
#define GLFW_HAT_RIGHT_DOWN
#define GLFW_HAT_CENTERED
#define GLFW_JOYSTICK_LAST
void _glfwInputError(int code, const char *format,...)
#define _GLFW_POLL_BUTTONS
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST+1]