//========================================================================
// GLFW 3.4 Cocoa – www.glfw.org
//————————————————————————
// Copyright (c) 2009-2019 Camilla Löwy
Copyright By PowCoder代写 加微信 powcoder
// Copyright (c) 2012
// This software is provided ‘as-is’, without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source
// distribution.
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include “internal.h”
#include
#include
#include
#include
#include
#include
#include
// Joystick element information
typedef struct _GLFWjoyelementNS
IOHIDElementRef native;
uint32_t usage;
int index;
long minimum;
long maximum;
} _GLFWjoyelementNS;
// Returns the value of the specified element of the specified joystick
static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
IOHIDValueRef valueRef;
long value = 0;
if (js->ns.device)
if (IOHIDDeviceGetValue(js->ns.device,
element->native,
&valueRef) == kIOReturnSuccess)
value = IOHIDValueGetIntegerValue(valueRef);
return value;
// Comparison function for matching the SDL element order
static CFComparisonResult compareElements(const void* fp,
const void* sp,
void* user)
const _GLFWjoyelementNS* fe = fp;
const _GLFWjoyelementNS* se = sp;
if (fe->usage < se->usage)
return kCFCompareLessThan;
if (fe->usage > se->usage)
return kCFCompareGreaterThan;
if (fe->index < se->index)
return kCFCompareLessThan;
if (fe->index > se->index)
return kCFCompareGreaterThan;
return kCFCompareEqualTo;
// Removes the specified joystick
static void closeJoystick(_GLFWjoystick* js)
if (!js->present)
for (int i = 0; i < CFArrayGetCount(js->ns.axes); i++)
_glfw_free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));
CFRelease(js->ns.axes);
for (int i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
_glfw_free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i));
CFRelease(js->ns.buttons);
for (int i = 0; i < CFArrayGetCount(js->ns.hats); i++)
_glfw_free((void*) CFArrayGetValueAtIndex(js->ns.hats, i));
CFRelease(js->ns.hats);
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
// Callback for user-initiated joystick addition
static void matchCallback(void* context,
IOReturn result,
void* sender,
IOHIDDeviceRef device)
char name[256];
char guid[33];
CFTypeRef property;
uint32_t vendor = 0, product = 0, version = 0;
_GLFWjoystick* js;
CFMutableArrayRef axes, buttons, hats;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
if (_glfw.joysticks[jid].ns.device == device)
axes = CFArrayCreateMutable(NULL, 0, NULL);
buttons = CFArrayCreateMutable(NULL, 0, NULL);
hats = CFArrayCreateMutable(NULL, 0, NULL);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
if (property)
CFStringGetCString(property,
sizeof(name),
kCFStringEncodingUTF8);
strncpy(name, "Unknown", sizeof(name));
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &vendor);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &product);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &version);
// Generate a joystick GUID that matches the SDL 2.0.5+ one
if (vendor && product)
sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000",
(uint8_t) vendor, (uint8_t) (vendor >> 8),
(uint8_t) product, (uint8_t) (product >> 8),
(uint8_t) version, (uint8_t) (version >> 8));
sprintf(guid, “05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02×00”,
name[0], name[1], name[2], name[3],
name[4], name[5], name[6], name[7],
name[8], name[9], name[10]);
CFArrayRef elements =
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
for (CFIndex i = 0; i < CFArrayGetCount(elements); i++)
IOHIDElementRef native = (IOHIDElementRef)
CFArrayGetValueAtIndex(elements, i);
if (CFGetTypeID(native) != IOHIDElementGetTypeID())
const IOHIDElementType type = IOHIDElementGetType(native);
if ((type != kIOHIDElementTypeInput_Axis) &&
(type != kIOHIDElementTypeInput_Button) &&
(type != kIOHIDElementTypeInput_Misc))
CFMutableArrayRef target = NULL;
const uint32_t usage = IOHIDElementGetUsage(native);
const uint32_t page = IOHIDElementGetUsagePage(native);
if (page == kHIDPage_GenericDesktop)
switch (usage)
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
case kHIDUsage_GD_Slider:
case kHIDUsage_GD_Dial:
case kHIDUsage_GD_Wheel:
target = axes;
case kHIDUsage_GD_Hatswitch:
target = hats;
case kHIDUsage_GD_DPadUp:
case kHIDUsage_GD_DPadRight:
case kHIDUsage_GD_DPadDown:
case kHIDUsage_GD_DPadLeft:
case kHIDUsage_GD_SystemMainMenu:
case kHIDUsage_GD_Select:
case kHIDUsage_GD_Start:
target = buttons;
else if (page == kHIDPage_Simulation)
switch (usage)
case kHIDUsage_Sim_Accelerator:
case kHIDUsage_Sim_Brake:
case kHIDUsage_Sim_Throttle:
case kHIDUsage_Sim_Rudder:
case kHIDUsage_Sim_Steering:
target = axes;
else if (page == kHIDPage_Button || page == kHIDPage_Consumer)
target = buttons;
if (target)
_GLFWjoyelementNS* element = _glfw_calloc(1, sizeof(_GLFWjoyelementNS));
element->native = native;
element->usage = usage;
element->index = (int) CFArrayGetCount(target);
element->minimum = IOHIDElementGetLogicalMin(native);
element->maximum = IOHIDElementGetLogicalMax(native);
CFArrayAppendValue(target, element);
CFRelease(elements);
CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)),
compareElements, NULL);
CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)),
compareElements, NULL);
CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)),
compareElements, NULL);
js = _glfwAllocJoystick(name, guid,
(int) CFArrayGetCount(axes),
(int) CFArrayGetCount(buttons),
(int) CFArrayGetCount(hats));
js->ns.device = device;
js->ns.axes = axes;
js->ns.buttons = buttons;
js->ns.hats = hats;
_glfwInputJoystick(js, GLFW_CONNECTED);
// Callback for user-initiated joystick removal
static void removeCallback(void* context,
IOReturn result,
void* sender,
IOHIDDeviceRef device)
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
if (_glfw.joysticks[jid].ns.device == device)
closeJoystick(_glfw.joysticks + jid);
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitJoysticksCocoa(void)
CFMutableArrayRef matching;
const long usages[] =
kHIDUsage_GD_Joystick,
kHIDUsage_GD_GamePad,
kHIDUsage_GD_MultiAxisController
_glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
matching = CFArrayCreateMutable(kCFAllocatorDefault,
&kCFTypeArrayCallBacks);
if (!matching)
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
return GLFW_FALSE;
for (size_t i = 0; i < sizeof(usages) / sizeof(long); i++)
const long page = kHIDPage_GenericDesktop;
CFMutableDictionaryRef dict =
CFDictionaryCreateMutable(kCFAllocatorDefault,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!dict)
CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberLongType,
CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
kCFNumberLongType,
&usages[i]);
if (pageRef && usageRef)
CFDictionarySetValue(dict,
CFSTR(kIOHIDDeviceUsagePageKey),
CFDictionarySetValue(dict,
CFSTR(kIOHIDDeviceUsageKey),
usageRef);
CFArrayAppendValue(matching, dict);
if (pageRef)
CFRelease(pageRef);
if (usageRef)
CFRelease(usageRef);
CFRelease(dict);
IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, matching);
CFRelease(matching);
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager,
&matchCallback, NULL);
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager,
&removeCallback, NULL);
IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager,
CFRunLoopGetMain(),
kCFRunLoopDefaultMode);
IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
// Execute the run loop once in order to register any initially-attached
// joysticks
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
return GLFW_TRUE;
void _glfwTerminateJoysticksCocoa(void)
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
closeJoystick(_glfw.joysticks + jid);
if (_glfw.ns.hidManager)
CFRelease(_glfw.ns.hidManager);
_glfw.ns.hidManager = NULL;
int _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode)
if (mode & _GLFW_POLL_AXES)
for (CFIndex i = 0; i < CFArrayGetCount(js->ns.axes); i++)
_GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.axes, i);
const long raw = getElementValue(js, axis);
// Perform auto calibration
if (raw < axis->minimum)
axis->minimum = raw;
if (raw > axis->maximum)
axis->maximum = raw;
const long size = axis->maximum – axis->minimum;
if (size == 0)
_glfwInputJoystickAxis(js, (int) i, 0.f);
const float value = (2.f * (raw – axis->minimum) / size) – 1.f;
_glfwInputJoystickAxis(js, (int) i, value);
if (mode & _GLFW_POLL_BUTTONS)
for (CFIndex i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.buttons, i);
const char value = getElementValue(js, button) – button->minimum;
const int state = (value > 0) ? GLFW_PRESS : GLFW_RELEASE;
_glfwInputJoystickButton(js, (int) i, state);
for (CFIndex i = 0; i < CFArrayGetCount(js->ns.hats); i++)
const int states[9] =
GLFW_HAT_UP,
GLFW_HAT_RIGHT_UP,
GLFW_HAT_RIGHT,
GLFW_HAT_RIGHT_DOWN,
GLFW_HAT_DOWN,
GLFW_HAT_LEFT_DOWN,
GLFW_HAT_LEFT,
GLFW_HAT_LEFT_UP,
GLFW_HAT_CENTERED
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.hats, i);
long state = getElementValue(js, hat) – hat->minimum;
if (state < 0 || state > 8)
state = 8;
_glfwInputJoystickHat(js, (int) i, states[state]);
return js->present;
const char* _glfwGetMappingNameCocoa(void)
return “Mac OS X”;
void _glfwUpdateGamepadGUIDCocoa(char* guid)
if ((strncmp(guid + 4, “000000000000”, 12) == 0) &&
(strncmp(guid + 20, “000000000000”, 12) == 0))
char original[33];
strncpy(original, guid, sizeof(original) – 1);
sprintf(guid, “03000000%.4s0000%.4s000000000000”,
original, original + 16);
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com