2010-09-07 15:34:51 +00:00
|
|
|
//========================================================================
|
2016-08-18 21:42:15 +00:00
|
|
|
// GLFW 3.3 Cocoa - www.glfw.org
|
2010-09-07 15:34:51 +00:00
|
|
|
//------------------------------------------------------------------------
|
2016-11-21 15:23:59 +00:00
|
|
|
// Copyright (c) 2009-2016 Camilla Löwy <elmindreda@glfw.org>
|
2012-08-14 21:34:26 +00:00
|
|
|
// Copyright (c) 2012 Torsten Walluhn <tw@mad-cad.net>
|
2010-09-07 15:34:51 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//========================================================================
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
|
2011-09-18 19:05:00 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <ctype.h>
|
2016-02-08 19:21:48 +00:00
|
|
|
#include <string.h>
|
2012-01-29 14:38:22 +00:00
|
|
|
|
2011-09-18 19:05:00 +00:00
|
|
|
#include <mach/mach.h>
|
|
|
|
#include <mach/mach_error.h>
|
2012-01-29 14:38:22 +00:00
|
|
|
|
2011-09-18 19:05:00 +00:00
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
|
|
|
|
|
|
|
|
|
|
|
// Joystick element information
|
2016-02-08 08:32:48 +00:00
|
|
|
//
|
2015-12-03 17:16:46 +00:00
|
|
|
typedef struct _GLFWjoyelementNS
|
2012-01-29 14:30:01 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
IOHIDElementRef native;
|
|
|
|
long minimum;
|
|
|
|
long maximum;
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2015-12-03 17:16:46 +00:00
|
|
|
} _GLFWjoyelementNS;
|
2011-09-18 19:05:00 +00:00
|
|
|
|
|
|
|
|
2012-01-29 14:30:01 +00:00
|
|
|
// Returns the value of the specified element of the specified joystick
|
2013-02-04 12:22:10 +00:00
|
|
|
//
|
2017-01-05 18:44:15 +00:00
|
|
|
static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
|
2011-09-18 19:05:00 +00:00
|
|
|
{
|
2012-01-29 14:30:01 +00:00
|
|
|
IOReturn result = kIOReturnSuccess;
|
2015-06-20 18:58:26 +00:00
|
|
|
IOHIDValueRef valueRef;
|
|
|
|
long value = 0;
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
if (js && element && js->ns.device)
|
2012-01-29 14:30:01 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
result = IOHIDDeviceGetValue(js->ns.device,
|
|
|
|
element->native,
|
2015-06-20 18:58:26 +00:00
|
|
|
&valueRef);
|
|
|
|
|
2012-01-29 14:30:01 +00:00
|
|
|
if (kIOReturnSuccess == result)
|
|
|
|
{
|
2015-06-20 18:58:26 +00:00
|
|
|
value = IOHIDValueGetIntegerValue(valueRef);
|
|
|
|
|
2012-08-26 13:38:18 +00:00
|
|
|
// Record min and max for auto calibration
|
2017-01-05 18:44:15 +00:00
|
|
|
if (value < element->minimum)
|
|
|
|
element->minimum = value;
|
|
|
|
if (value > element->maximum)
|
|
|
|
element->maximum = value;
|
2012-01-29 14:30:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-26 13:38:18 +00:00
|
|
|
// Auto user scale
|
2015-06-20 18:58:26 +00:00
|
|
|
return value;
|
2011-09-18 19:05:00 +00:00
|
|
|
}
|
|
|
|
|
2012-01-29 14:30:01 +00:00
|
|
|
// Removes the specified joystick
|
2013-02-04 12:22:10 +00:00
|
|
|
//
|
2017-01-05 18:44:15 +00:00
|
|
|
static void closeJoystick(_GLFWjoystick* js)
|
2011-09-18 19:05:00 +00:00
|
|
|
{
|
2012-01-29 23:02:54 +00:00
|
|
|
int i;
|
|
|
|
|
2016-02-08 08:32:48 +00:00
|
|
|
if (!js->present)
|
2013-04-24 17:25:42 +00:00
|
|
|
return;
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
for (i = 0; i < CFArrayGetCount(js->ns.axes); i++)
|
|
|
|
free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));
|
|
|
|
CFRelease(js->ns.axes);
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
|
|
|
|
free((void*) CFArrayGetValueAtIndex(js->ns.buttons, i));
|
|
|
|
CFRelease(js->ns.buttons);
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
|
|
|
|
free((void*) CFArrayGetValueAtIndex(js->ns.hats, i));
|
|
|
|
CFRelease(js->ns.hats);
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
_glfwFreeJoystick(js);
|
|
|
|
_glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_DISCONNECTED);
|
2011-09-18 19:05:00 +00:00
|
|
|
}
|
|
|
|
|
2015-06-20 18:58:26 +00:00
|
|
|
// Callback for user-initiated joystick addition
|
2013-02-04 12:22:10 +00:00
|
|
|
//
|
2015-06-26 11:31:37 +00:00
|
|
|
static void matchCallback(void* context,
|
|
|
|
IOReturn result,
|
|
|
|
void* sender,
|
2017-01-05 18:44:15 +00:00
|
|
|
IOHIDDeviceRef device)
|
2011-09-18 19:05:00 +00:00
|
|
|
{
|
2016-10-10 01:24:07 +00:00
|
|
|
int jid;
|
2017-01-05 18:44:15 +00:00
|
|
|
char name[256];
|
|
|
|
CFIndex i;
|
|
|
|
CFStringRef productKey;
|
|
|
|
_GLFWjoystick* js;
|
|
|
|
CFMutableArrayRef axes, buttons, hats;
|
2015-06-20 18:58:26 +00:00
|
|
|
|
2017-01-12 04:30:56 +00:00
|
|
|
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
2012-03-26 13:20:31 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
if (_glfw.joysticks[jid].ns.device == device)
|
2015-06-20 18:58:26 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
axes = CFArrayCreateMutable(NULL, 0, NULL);
|
|
|
|
buttons = CFArrayCreateMutable(NULL, 0, NULL);
|
|
|
|
hats = CFArrayCreateMutable(NULL, 0, NULL);
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
productKey = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
|
|
|
if (productKey)
|
2016-02-08 19:21:48 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
CFStringGetCString(productKey,
|
|
|
|
name,
|
|
|
|
sizeof(name),
|
2016-02-08 19:21:48 +00:00
|
|
|
kCFStringEncodingUTF8);
|
|
|
|
}
|
|
|
|
else
|
2017-01-05 18:44:15 +00:00
|
|
|
strncpy(name, "Unknown", sizeof(name));
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
CFArrayRef elements =
|
|
|
|
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
|
|
|
|
|
|
|
|
for (i = 0; i < CFArrayGetCount(elements); i++)
|
|
|
|
{
|
|
|
|
IOHIDElementRef native = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, i);
|
|
|
|
if (CFGetTypeID(native) != IOHIDElementGetTypeID())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const IOHIDElementType type = IOHIDElementGetType(native);
|
|
|
|
if ((type != kIOHIDElementTypeInput_Axis) &&
|
|
|
|
(type != kIOHIDElementTypeInput_Button) &&
|
|
|
|
(type != kIOHIDElementTypeInput_Misc))
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
CFMutableArrayRef target = NULL;
|
2012-08-14 19:58:22 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
switch (IOHIDElementGetUsagePage(native))
|
|
|
|
{
|
|
|
|
case kHIDPage_GenericDesktop:
|
|
|
|
{
|
|
|
|
switch (IOHIDElementGetUsage(native))
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
case kHIDUsage_GD_Hatswitch:
|
|
|
|
target = hats;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case kHIDPage_Button:
|
|
|
|
target = buttons;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target)
|
|
|
|
{
|
|
|
|
_GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS));
|
|
|
|
element->native = native;
|
|
|
|
element->minimum = IOHIDElementGetLogicalMin(native);
|
|
|
|
element->maximum = IOHIDElementGetLogicalMax(native);
|
|
|
|
CFArrayAppendValue(target, element);
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 05:39:21 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
CFRelease(elements);
|
2015-12-13 16:38:50 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
js = _glfwAllocJoystick(name,
|
|
|
|
CFArrayGetCount(axes),
|
|
|
|
CFArrayGetCount(buttons) + CFArrayGetCount(hats) * 4);
|
|
|
|
|
|
|
|
js->ns.device = device;
|
|
|
|
js->ns.axes = axes;
|
|
|
|
js->ns.buttons = buttons;
|
|
|
|
js->ns.hats = hats;
|
|
|
|
|
|
|
|
_glfwInputJoystick(_GLFW_JOYSTICK_ID(js), GLFW_CONNECTED);
|
2015-06-20 18:58:26 +00:00
|
|
|
}
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2015-06-20 18:58:26 +00:00
|
|
|
// Callback for user-initiated joystick removal
|
|
|
|
//
|
2015-06-26 11:31:37 +00:00
|
|
|
static void removeCallback(void* context,
|
|
|
|
IOReturn result,
|
|
|
|
void* sender,
|
2017-01-05 18:44:15 +00:00
|
|
|
IOHIDDeviceRef device)
|
2015-06-20 18:58:26 +00:00
|
|
|
{
|
2016-10-10 01:24:07 +00:00
|
|
|
int jid;
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-12 04:30:56 +00:00
|
|
|
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
2015-06-26 11:31:37 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
if (_glfw.joysticks[jid].ns.device == device)
|
2015-06-26 11:31:37 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
closeJoystick(_glfw.joysticks + jid);
|
2015-06-20 18:58:26 +00:00
|
|
|
break;
|
2014-02-06 17:37:37 +00:00
|
|
|
}
|
2015-06-20 18:58:26 +00:00
|
|
|
}
|
|
|
|
}
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2015-06-26 11:31:37 +00:00
|
|
|
|
2015-06-20 18:58:26 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
////// GLFW internal API //////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2015-06-20 18:58:26 +00:00
|
|
|
// Initialize joystick interface
|
|
|
|
//
|
2015-12-03 17:16:46 +00:00
|
|
|
void _glfwInitJoysticksNS(void)
|
2015-06-20 18:58:26 +00:00
|
|
|
{
|
2017-02-26 21:18:40 +00:00
|
|
|
CFMutableArrayRef matching;
|
|
|
|
const long usages[] =
|
|
|
|
{
|
|
|
|
kHIDUsage_GD_Joystick,
|
|
|
|
kHIDUsage_GD_GamePad,
|
|
|
|
kHIDUsage_GD_MultiAxisController
|
|
|
|
};
|
2015-06-20 18:58:26 +00:00
|
|
|
|
2016-06-07 12:11:54 +00:00
|
|
|
_glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
|
|
|
|
kIOHIDOptionsTypeNone);
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-02-26 21:18:40 +00:00
|
|
|
matching = CFArrayCreateMutable(kCFAllocatorDefault,
|
|
|
|
0,
|
|
|
|
&kCFTypeArrayCallBacks);
|
|
|
|
if (!matching)
|
2015-06-20 18:58:26 +00:00
|
|
|
{
|
2017-02-26 21:18:40 +00:00
|
|
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create array");
|
|
|
|
return;
|
|
|
|
}
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-02-26 21:18:40 +00:00
|
|
|
for (int i = 0; i < sizeof(usages) / sizeof(long); i++)
|
|
|
|
{
|
|
|
|
const long page = kHIDPage_GenericDesktop;
|
|
|
|
|
|
|
|
CFMutableDictionaryRef dict =
|
|
|
|
CFDictionaryCreateMutable(kCFAllocatorDefault,
|
|
|
|
0,
|
|
|
|
&kCFTypeDictionaryKeyCallBacks,
|
|
|
|
&kCFTypeDictionaryValueCallBacks);
|
|
|
|
if (!dict)
|
|
|
|
continue;
|
2013-04-24 17:25:42 +00:00
|
|
|
|
2017-02-26 21:18:40 +00:00
|
|
|
CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault,
|
|
|
|
kCFNumberLongType,
|
|
|
|
&page);
|
|
|
|
CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault,
|
|
|
|
kCFNumberLongType,
|
|
|
|
&usages[i]);
|
|
|
|
if (pageRef && usageRef)
|
2011-09-18 19:05:00 +00:00
|
|
|
{
|
2017-02-26 21:18:40 +00:00
|
|
|
CFDictionarySetValue(dict,
|
|
|
|
CFSTR(kIOHIDDeviceUsagePageKey),
|
|
|
|
pageRef);
|
|
|
|
CFDictionarySetValue(dict,
|
|
|
|
CFSTR(kIOHIDDeviceUsageKey),
|
|
|
|
usageRef);
|
|
|
|
CFArrayAppendValue(matching, dict);
|
2011-09-18 19:05:00 +00:00
|
|
|
}
|
2014-05-29 09:28:22 +00:00
|
|
|
|
2017-02-26 21:18:40 +00:00
|
|
|
if (pageRef)
|
|
|
|
CFRelease(pageRef);
|
|
|
|
if (usageRef)
|
|
|
|
CFRelease(usageRef);
|
|
|
|
|
|
|
|
CFRelease(dict);
|
2015-09-29 02:21:44 +00:00
|
|
|
}
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-02-26 21:18:40 +00:00
|
|
|
IOHIDManagerSetDeviceMatchingMultiple(_glfw.ns.hidManager, matching);
|
|
|
|
CFRelease(matching);
|
|
|
|
|
2016-06-07 12:11:54 +00:00
|
|
|
IOHIDManagerRegisterDeviceMatchingCallback(_glfw.ns.hidManager,
|
2015-06-26 11:31:37 +00:00
|
|
|
&matchCallback, NULL);
|
2016-06-07 12:11:54 +00:00
|
|
|
IOHIDManagerRegisterDeviceRemovalCallback(_glfw.ns.hidManager,
|
2015-06-26 11:31:37 +00:00
|
|
|
&removeCallback, NULL);
|
2016-06-07 12:11:54 +00:00
|
|
|
IOHIDManagerScheduleWithRunLoop(_glfw.ns.hidManager,
|
2015-06-26 11:31:37 +00:00
|
|
|
CFRunLoopGetMain(),
|
|
|
|
kCFRunLoopDefaultMode);
|
2016-06-07 12:11:54 +00:00
|
|
|
IOHIDManagerOpen(_glfw.ns.hidManager, kIOHIDOptionsTypeNone);
|
2015-06-20 18:58:26 +00:00
|
|
|
|
2015-06-26 11:31:37 +00:00
|
|
|
// Execute the run loop once in order to register any initially-attached
|
|
|
|
// joysticks
|
2015-06-20 18:58:26 +00:00
|
|
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
2011-09-18 19:05:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close all opened joystick handles
|
2013-02-04 12:22:10 +00:00
|
|
|
//
|
2015-12-03 17:16:46 +00:00
|
|
|
void _glfwTerminateJoysticksNS(void)
|
2011-09-18 19:05:00 +00:00
|
|
|
{
|
2016-10-10 01:24:07 +00:00
|
|
|
int jid;
|
2012-01-29 23:02:54 +00:00
|
|
|
|
2017-01-12 04:30:56 +00:00
|
|
|
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
|
2017-01-05 18:44:15 +00:00
|
|
|
closeJoystick(_glfw.joysticks + jid);
|
2015-06-20 18:58:26 +00:00
|
|
|
|
2016-06-07 12:11:54 +00:00
|
|
|
CFRelease(_glfw.ns.hidManager);
|
|
|
|
_glfw.ns.hidManager = NULL;
|
2011-09-18 19:05:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-16 01:25:36 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
////// GLFW platform API //////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
2010-09-07 15:34:51 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
int _glfwPlatformPollJoystick(int jid, int mode)
|
2010-09-07 15:34:51 +00:00
|
|
|
{
|
2017-01-05 18:44:15 +00:00
|
|
|
_GLFWjoystick* js = _glfw.joysticks + jid;
|
2010-09-07 15:34:51 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
if (mode == _GLFW_POLL_AXES)
|
|
|
|
{
|
|
|
|
CFIndex i;
|
2012-01-29 14:30:01 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
for (i = 0; i < CFArrayGetCount(js->ns.axes); i++)
|
|
|
|
{
|
|
|
|
_GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
|
|
|
|
CFArrayGetValueAtIndex(js->ns.axes, i);
|
2010-09-07 15:34:51 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
const long value = getElementValue(js, axis);
|
|
|
|
const long delta = axis->maximum - axis->minimum;
|
2012-08-14 19:58:22 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
if (delta == 0)
|
|
|
|
_glfwInputJoystickAxis(jid, i, value);
|
|
|
|
else
|
|
|
|
_glfwInputJoystickAxis(jid, i, (2.f * (value - axis->minimum) / delta) - 1.f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mode == _GLFW_POLL_BUTTONS)
|
|
|
|
{
|
|
|
|
CFIndex i, bi = 0;
|
2012-08-14 19:58:22 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
|
|
|
|
{
|
|
|
|
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
|
|
|
|
CFArrayGetValueAtIndex(js->ns.buttons, i);
|
|
|
|
const char value = getElementValue(js, button) ? 1 : 0;
|
|
|
|
_glfwInputJoystickButton(jid, bi++, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
|
|
|
|
{
|
|
|
|
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
|
|
|
|
CFArrayGetValueAtIndex(js->ns.hats, i);
|
|
|
|
|
|
|
|
// Bit fields of button presses for each direction, including nil
|
|
|
|
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
|
2016-03-29 11:42:11 +00:00
|
|
|
|
2017-01-05 18:44:15 +00:00
|
|
|
long j, state = getElementValue(js, hat);
|
|
|
|
if (state < 0 || state > 8)
|
|
|
|
state = 8;
|
|
|
|
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
{
|
|
|
|
const char value = directions[state] & (1 << j) ? 1 : 0;
|
|
|
|
_glfwInputJoystickButton(jid, bi++, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return js->present;
|
2012-09-06 23:01:34 +00:00
|
|
|
}
|
|
|
|
|