New joystick API.

This commit is contained in:
Camilla Berglund
2013-04-24 19:25:42 +02:00
parent c4d856bcb2
commit 7f2eb7b15b
10 changed files with 280 additions and 461 deletions
+154 -217
View File
@@ -47,8 +47,6 @@ typedef struct
{
IOHIDElementCookie cookie;
long value;
long min;
long max;
@@ -63,20 +61,17 @@ static void getElementsCFArrayHandler(const void* value, void* parameter);
// Adds an element to the specified joystick
//
static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef elementRef)
{
long elementType, usagePage, usage;
CFTypeRef refElementType, refUsagePage, refUsage;
refElementType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementTypeKey));
refUsagePage = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsagePageKey));
refUsage = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsageKey));
CFMutableArrayRef elementsArray = NULL;
CFNumberGetValue(refElementType, kCFNumberLongType, &elementType);
CFNumberGetValue(refUsagePage, kCFNumberLongType, &usagePage);
CFNumberGetValue(refUsage, kCFNumberLongType, &usage);
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementTypeKey)),
kCFNumberLongType, &elementType);
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsagePageKey)),
kCFNumberLongType, &usagePage);
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsageKey)),
kCFNumberLongType, &usage);
if ((elementType == kIOHIDElementTypeInput_Axis) ||
(elementType == kIOHIDElementTypeInput_Button) ||
@@ -97,12 +92,10 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
case kHIDUsage_GD_Slider:
case kHIDUsage_GD_Dial:
case kHIDUsage_GD_Wheel:
joystick->numAxes++;
elementsArray = joystick->axes;
elementsArray = joystick->axisElements;
break;
case kHIDUsage_GD_Hatswitch:
joystick->numHats++;
elementsArray = joystick->hats;
elementsArray = joystick->hatElements;
break;
}
@@ -110,8 +103,7 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
}
case kHIDPage_Button:
joystick->numButtons++;
elementsArray = joystick->buttons;
elementsArray = joystick->buttonElements;
break;
default:
break;
@@ -120,35 +112,33 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
if (elementsArray)
{
long number;
CFTypeRef refType;
CFTypeRef numberRef;
_GLFWjoyelement* element = (_GLFWjoyelement*) malloc(sizeof(_GLFWjoyelement));
CFArrayAppendValue(elementsArray, element);
refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementCookieKey));
if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementCookieKey));
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
element->cookie = (IOHIDElementCookie) number;
refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMinKey));
if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMinKey));
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
element->minReport = element->min = number;
refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMaxKey));
if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMaxKey));
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
element->maxReport = element->max = number;
}
}
else
{
CFTypeRef refElementTop = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementKey));
if (refElementTop)
CFTypeRef array = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementKey));
if (array)
{
CFTypeID type = CFGetTypeID (refElementTop);
if (type == CFArrayGetTypeID())
if (CFGetTypeID(array) == CFArrayGetTypeID())
{
CFRange range = {0, CFArrayGetCount (refElementTop)};
CFArrayApplyFunction(refElementTop, range, getElementsCFArrayHandler, joystick);
CFRange range = { 0, CFArrayGetCount(array) };
CFArrayApplyFunction(array, range, getElementsCFArrayHandler, joystick);
}
}
}
@@ -195,42 +185,28 @@ static void removeJoystick(_GLFWjoy* joystick)
{
int i;
if (joystick->present)
{
joystick->present = GL_FALSE;
if (!joystick->present)
return;
for (i = 0; i < joystick->numAxes; i++)
{
_GLFWjoyelement* axes =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axes, i);
free(axes);
}
CFArrayRemoveAllValues(joystick->axes);
joystick->numAxes = 0;
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i));
CFArrayRemoveAllValues(joystick->axisElements);
for (i = 0; i < joystick->numButtons; i++)
{
_GLFWjoyelement* button =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttons, i);
free(button);
}
CFArrayRemoveAllValues(joystick->buttons);
joystick->numButtons = 0;
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i));
CFArrayRemoveAllValues(joystick->buttonElements);
for (i = 0; i < joystick->numHats; i++)
{
_GLFWjoyelement* hat =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hats, i);
free(hat);
}
CFArrayRemoveAllValues(joystick->hats);
joystick->hats = 0;
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i));
CFArrayRemoveAllValues(joystick->hatElements);
(*(joystick->interface))->close(joystick->interface);
(*(joystick->interface))->Release(joystick->interface);
free(joystick->axes);
free(joystick->buttons);
joystick->interface = NULL;
}
(*(joystick->interface))->close(joystick->interface);
(*(joystick->interface))->Release(joystick->interface);
memset(joystick, 0, sizeof(_GLFWjoy));
}
// Callback for user-initiated joystick removal
@@ -244,34 +220,63 @@ static void removalCallback(void* target, IOReturn result, void* refcon, void* s
//
static void pollJoystickEvents(void)
{
int i;
CFIndex j;
int joy;
for (i = 0; i < GLFW_JOYSTICK_LAST + 1; i++)
for (joy = 0; joy <= GLFW_JOYSTICK_LAST; joy++)
{
_GLFWjoy* joystick = &_glfw.ns.joysticks[i];
CFIndex i;
int buttonIndex = 0;
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
if (joystick->present)
if (!joystick->present)
continue;
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
{
for (j = 0; j < joystick->numButtons; j++)
{
_GLFWjoyelement* button =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttons, j);
button->value = getElementValue(joystick, button);
}
_GLFWjoyelement* button =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttonElements, i);
for (j = 0; j < joystick->numAxes; j++)
{
_GLFWjoyelement* axes =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axes, j);
axes->value = getElementValue(joystick, axes);
}
if (getElementValue(joystick, button))
joystick->buttons[buttonIndex++] = GLFW_PRESS;
else
joystick->buttons[buttonIndex++] = GLFW_RELEASE;
}
for (j = 0; j < joystick->numHats; j++)
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
{
_GLFWjoyelement* axis =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axisElements, i);
long value = getElementValue(joystick, axis);
long readScale = axis->maxReport - axis->minReport;
if (readScale == 0)
joystick->axes[i] = value;
else
joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f;
if (i & 1)
joystick->axes[i] = -joystick->axes[i];
}
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
{
_GLFWjoyelement* hat =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hatElements, i);
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
long j, value = getElementValue(joystick, hat);
if (value < 0 || value > 8)
value = 8;
for (j = 0; j < 4; j++)
{
_GLFWjoyelement* hat =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hats, j);
hat->value = getElementValue(joystick, hat);
if (directions[value] & (1 << j))
joystick->buttons[buttonIndex++] = GLFW_PRESS;
else
joystick->buttons[buttonIndex++] = GLFW_RELEASE;
}
}
}
@@ -286,7 +291,7 @@ static void pollJoystickEvents(void)
//
void _glfwInitJoysticks(void)
{
int deviceCounter = 0;
int joy = 0;
IOReturn result = kIOReturnSuccess;
mach_port_t masterPort = 0;
io_iterator_t objectIterator = 0;
@@ -318,7 +323,7 @@ void _glfwInitJoysticks(void)
while ((ioHIDDeviceObject = IOIteratorNext(objectIterator)))
{
kern_return_t result;
CFTypeRef refCF = 0;
CFTypeRef valueRef = 0;
IOCFPlugInInterface** ppPlugInInterface = NULL;
HRESULT plugInResult = S_OK;
@@ -327,27 +332,29 @@ void _glfwInitJoysticks(void)
long usagePage, usage;
// Check device type
refCF = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsagePageKey),
kCFAllocatorDefault,
kNilOptions);
if (refCF)
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsagePageKey),
kCFAllocatorDefault,
kNilOptions);
if (valueRef)
{
CFNumberGetValue(refCF, kCFNumberLongType, &usagePage);
CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage);
if (usagePage != kHIDPage_GenericDesktop)
{
// This device is not relevant to GLFW
continue;
}
CFRelease(valueRef);
}
refCF = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsageKey),
kCFAllocatorDefault,
kNilOptions);
if (refCF)
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsageKey),
kCFAllocatorDefault,
kNilOptions);
if (valueRef)
{
CFNumberGetValue(refCF, kCFNumberLongType, &usage);
CFNumberGetValue(valueRef, kCFNumberLongType, &usage);
if ((usage != kHIDUsage_GD_Joystick &&
usage != kHIDUsage_GD_GamePad &&
@@ -356,10 +363,11 @@ void _glfwInitJoysticks(void)
// This device is not relevant to GLFW
continue;
}
CFRelease(valueRef);
}
_GLFWjoy* joystick = &_glfw.ns.joysticks[deviceCounter];
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
joystick->present = GL_TRUE;
result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject,
@@ -388,42 +396,45 @@ void _glfwInitJoysticks(void)
joystick);
// Get product string
refCF = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDProductKey),
kCFAllocatorDefault,
kNilOptions);
if (refCF)
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDProductKey),
kCFAllocatorDefault,
kNilOptions);
if (valueRef)
{
CFStringGetCString(refCF,
CFStringGetCString(valueRef,
joystick->name,
sizeof(joystick->name),
kCFStringEncodingUTF8);
CFRelease(valueRef);
}
joystick->numAxes = 0;
joystick->numButtons = 0;
joystick->numHats = 0;
joystick->axes = CFArrayCreateMutable(NULL, 0, NULL);
joystick->buttons = CFArrayCreateMutable(NULL, 0, NULL);
joystick->hats = CFArrayCreateMutable(NULL, 0, NULL);
joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
CFTypeRef refTopElement;
refTopElement = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDElementKey),
kCFAllocatorDefault,
kNilOptions);
CFTypeID type = CFGetTypeID(refTopElement);
if (type == CFArrayGetTypeID())
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDElementKey),
kCFAllocatorDefault,
kNilOptions);
if (CFGetTypeID(valueRef) == CFArrayGetTypeID())
{
CFRange range = { 0, CFArrayGetCount(refTopElement) };
CFArrayApplyFunction(refTopElement,
CFRange range = { 0, CFArrayGetCount(valueRef) };
CFArrayApplyFunction(valueRef,
range,
getElementsCFArrayHandler,
(void*) joystick);
CFRelease(valueRef);
}
deviceCounter++;
joystick->axes = (float*) calloc(CFArrayGetCount(joystick->axisElements),
sizeof(float));
joystick->buttons = (unsigned char*) calloc(CFArrayGetCount(joystick->buttonElements) +
CFArrayGetCount(joystick->hatElements) * 4, 1);
joy++;
if (joy > GLFW_JOYSTICK_LAST)
break;
}
}
@@ -445,118 +456,44 @@ void _glfwTerminateJoysticks(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformGetJoystickParam(int joy, int param)
int _glfwPlatformJoystickPresent(int joy)
{
if (!_glfw.ns.joysticks[joy].present)
return GL_FALSE;
switch (param)
{
case GLFW_PRESENT:
return GL_TRUE;
case GLFW_AXES:
return (int) CFArrayGetCount(_glfw.ns.joysticks[joy].axes);
case GLFW_BUTTONS:
return (int) CFArrayGetCount(_glfw.ns.joysticks[joy].buttons) +
(int) CFArrayGetCount(_glfw.ns.joysticks[joy].hats) * 4;
default:
break;
}
return GL_FALSE;
}
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
{
int i;
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
return 0;
_GLFWjoy joystick = _glfw.ns.joysticks[joy];
if (!joystick.present)
return 0;
numaxes = numaxes < joystick.numAxes ? numaxes : joystick.numAxes;
// Update joystick state
pollJoystickEvents();
for (i = 0; i < numaxes; i++)
{
_GLFWjoyelement* elements =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick.axes, i);
long readScale = elements->maxReport - elements->minReport;
if (readScale == 0)
axes[i] = elements->value;
else
axes[i] = (2.0f * (elements->value - elements->minReport) / readScale) - 1.0f;
if (i & 1)
axes[i] = -axes[i];
}
return numaxes;
return _glfw.ns.joysticks[joy].present;
}
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
int numbuttons)
float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
int i, j, button;
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
return 0;
_GLFWjoy joystick = _glfw.ns.joysticks[joy];
if (!joystick.present)
return 0;
// Update joystick state
pollJoystickEvents();
for (button = 0; button < numbuttons && button < joystick.numButtons; button++)
{
_GLFWjoyelement* element = (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick.buttons, button);
buttons[button] = element->value ? GLFW_PRESS : GLFW_RELEASE;
}
if (!joystick->present)
return NULL;
// Virtual buttons - Inject data from hats
// Each hat is exposed as 4 buttons which exposes 8 directions with concurrent button presses
*count = (int) CFArrayGetCount(joystick->axisElements);
return joystick->axes;
}
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
for (i = 0; i < joystick.numHats; i++)
{
_GLFWjoyelement* hat = (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick.hats, i);
pollJoystickEvents();
int value = hat->value;
if (value < 0 || value > 8)
value = 8;
if (!joystick->present)
return NULL;
for (j = 0; j < 4 && button < numbuttons; j++)
{
if (directions[value] & (1 << j))
buttons[button] = GLFW_PRESS;
else
buttons[button] = GLFW_RELEASE;
button++;
}
}
return button;
*count = (int) CFArrayGetCount(joystick->buttonElements) +
(int) CFArrayGetCount(joystick->hatElements) * 4;
return joystick->buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
{
pollJoystickEvents();
return _glfw.ns.joysticks[joy].name;
}