Added support for joystick button and axis callbacks

The major change is the addition of the inputValueCallback function.  This callback function is registered with the HID Manager using the HIDDeviceRef when a joystick is connected.  Whenever an axis, button, or hat switch value is changed for that HID device, the inputValueCallback function is called: the appropriate value will be updated (which alleviates the need for polling, hence the removal of the polling functions) and, if a user callback has been registered, event notification will be provided.  (Note that in the case of hat switches, which are treated as quad sets of buttons, one for each direction, user notification is provided only if the value for that direction has actually changed).
This commit is contained in:
IntellectualKitty 2016-09-07 15:16:20 -06:00 committed by GitHub
parent ed211f35b5
commit d3eaf9a9fa

View File

@ -37,7 +37,6 @@
#include <CoreFoundation/CoreFoundation.h>
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
// Joystick element information
//
typedef struct _GLFWjoyelementNS
@ -193,20 +192,35 @@ static void removeJoystick(_GLFWjoystickNS* js)
_glfwInputJoystickChange(js - _glfw.ns_js, GLFW_DISCONNECTED);
}
// Polls for joystick axis events and updates GLFW state
// Input value callback
//
static GLFWbool pollJoystickAxisEvents(_GLFWjoystickNS* js)
static void inputValueCallback (void* context,
IOReturn valueResult,
void* deviceRef,
IOHIDValueRef valueRef)
{
_GLFWjoystickNS* js;
CFIndex i;
int buttonIndex = 0;
if (kIOReturnSuccess != valueResult)
return;
js = (_GLFWjoystickNS*)context;
if (!js)
return;
if (!js->present)
return GLFW_FALSE;
return;
IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
for (i = 0; i < CFArrayGetCount(js->axisElements); i++)
{
_GLFWjoyelementNS* axis = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->axisElements, i);
if (elementRef == axis->elementRef)
{
long value = getElementValue(js, axis);
long readScale = axis->maxReport - axis->minReport;
@ -214,37 +228,36 @@ static GLFWbool pollJoystickAxisEvents(_GLFWjoystickNS* js)
js->axes[i] = value;
else
js->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f;
_glfwInputJoystickAxisMoved(js-_glfw.ns_js,i,js->axes[i]);
return;
}
}
return GLFW_TRUE;
}
// Polls for joystick button events and updates GLFW state
//
static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js)
{
CFIndex i;
int buttonIndex = 0;
if (!js->present)
return GLFW_FALSE;
for (i = 0; i < CFArrayGetCount(js->buttonElements); i++)
for (i = 0; i < CFArrayGetCount(js->buttonElements); i++, buttonIndex++)
{
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->buttonElements, i);
if (elementRef == button->elementRef)
{
if (getElementValue(js, button))
js->buttons[buttonIndex++] = GLFW_PRESS;
js->buttons[buttonIndex] = GLFW_PRESS;
else
js->buttons[buttonIndex++] = GLFW_RELEASE;
js->buttons[buttonIndex] = GLFW_RELEASE;
_glfwInputJoystickButtonState(js-_glfw.ns_js,buttonIndex,js->buttons[buttonIndex]);
return;
}
}
for (i = 0; i < CFArrayGetCount(js->hatElements); i++)
for (i = 0; i < CFArrayGetCount(js->hatElements); i++, buttonIndex += 4)
{
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->hatElements, i);
if (elementRef == hat->elementRef)
{
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
@ -254,14 +267,21 @@ static GLFWbool pollJoystickButtonEvents(_GLFWjoystickNS* js)
for (j = 0; j < 4; j++)
{
if (directions[value] & (1 << j))
js->buttons[buttonIndex++] = GLFW_PRESS;
else
js->buttons[buttonIndex++] = GLFW_RELEASE;
}
}
const unsigned char oldValue = js->buttons[buttonIndex+j];
return GLFW_TRUE;
if (directions[value] & (1 << j))
js->buttons[buttonIndex+j] = GLFW_PRESS;
else
js->buttons[buttonIndex+j] = GLFW_RELEASE;
// Since we're treating hat switches as buttons, only send events for
// the values that have actually changed.
if (oldValue != js->buttons[buttonIndex+j])
_glfwInputJoystickButtonState(js-_glfw.ns_js,buttonIndex+j,js->buttons[buttonIndex+j]);
}
}
return;
}
}
// Callback for user-initiated joystick addition
@ -324,6 +344,10 @@ static void matchCallback(void* context,
js->buttons = calloc(CFArrayGetCount(js->buttonElements) +
CFArrayGetCount(js->hatElements) * 4, 1);
IOHIDDeviceRegisterInputValueCallback(deviceRef,
inputValueCallback,
(void*)js);
_glfwInputJoystickChange(joy, GLFW_CONNECTED);
}
@ -399,7 +423,6 @@ void _glfwInitJoysticksNS(void)
_glfw.ns.hidManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
@ -482,7 +505,8 @@ int _glfwPlatformJoystickPresent(int joy)
const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
if (!pollJoystickAxisEvents(js))
if (!js->present)
return NULL;
*count = (int) CFArrayGetCount(js->axisElements);
@ -492,7 +516,8 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count)
const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
_GLFWjoystickNS* js = _glfw.ns_js + joy;
if (!pollJoystickButtonEvents(js))
if (!js->present)
return NULL;
*count = (int) CFArrayGetCount(js->buttonElements) +