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

View File

@ -530,10 +530,6 @@ extern "C" {
#define GLFW_CURSOR_HIDDEN 0x00040002 #define GLFW_CURSOR_HIDDEN 0x00040002
#define GLFW_CURSOR_CAPTURED 0x00040003 #define GLFW_CURSOR_CAPTURED 0x00040003
#define GLFW_PRESENT 0x00050001
#define GLFW_AXES 0x00050002
#define GLFW_BUTTONS 0x00050003
#define GLFW_GAMMA_RAMP_SIZE 256 #define GLFW_GAMMA_RAMP_SIZE 256
#define GLFW_CONNECTED 0x00061000 #define GLFW_CONNECTED 0x00061000
@ -1930,37 +1926,31 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb
* *
* @ingroup input * @ingroup input
*/ */
GLFWAPI int glfwGetJoystickParam(int joy, int param); GLFWAPI int glfwJoystickPresent(int joy);
/*! @brief Returns the values of axes of the specified joystick. /*! @brief Returns the values of all axes of the specified joystick.
*
* This function returns the current positions of axes of the specified
* joystick.
*
* @param[in] joy The joystick to query. * @param[in] joy The joystick to query.
* @param[out] axes The array to hold the values. * @param[out] count The size of the returned array.
* @param[in] numaxes The size of the provided array. * @return An array of axis values, or @c NULL if the joystick is not present.
* @return The number of values written to `axes`, or zero if an error *
* occurred. * @note The returned array is valid only until the next call to @ref
* glfwGetJoystickAxes for that joystick.
* *
* @ingroup input * @ingroup input
*/ */
GLFWAPI int glfwGetJoystickAxes(int joy, float* axes, int numaxes); GLFWAPI float* glfwGetJoystickAxes(int joy, int* count);
/*! @brief Returns the values of buttons of the specified joystick. /*! @brief Returns the values of all buttons of the specified joystick.
*
* This function returns the current state of buttons of the specified
* joystick.
*
* @param[in] joy The joystick to query. * @param[in] joy The joystick to query.
* @param[out] buttons The array to hold the values. * @param[out] count The size of the returned array.
* @param[in] numbuttons The size of the provided array. * @return An array of axis values, or @c NULL if the joystick is not present.
* @return The number of values written to `buttons`, or zero if an error *
* occurred. * @note The returned array is valid only until the next call to @ref
* glfwGetJoystickButtons for that joystick.
* *
* @ingroup input * @ingroup input
*/ */
GLFWAPI int glfwGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons); GLFWAPI unsigned char* glfwGetJoystickButtons(int joy, int* count);
/*! @brief Returns the name of the specified joystick. /*! @brief Returns the name of the specified joystick.
* *

View File

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

View File

@ -83,13 +83,12 @@ typedef struct
IOHIDDeviceInterface** interface; IOHIDDeviceInterface** interface;
int numAxes; CFMutableArrayRef axisElements;
int numButtons; CFMutableArrayRef buttonElements;
int numHats; CFMutableArrayRef hatElements;
CFMutableArrayRef axes; float* axes;
CFMutableArrayRef buttons; unsigned char* buttons;
CFMutableArrayRef hats;
} _GLFWjoy; } _GLFWjoy;

View File

@ -407,20 +407,20 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string);
*/ */
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); const char* _glfwPlatformGetClipboardString(_GLFWwindow* window);
/*! @copydoc glfwGetJoystickParam /*! @copydoc glfwJoystickPresent
* @ingroup platform * @ingroup platform
*/ */
int _glfwPlatformGetJoystickParam(int joy, int param); int _glfwPlatformJoystickPresent(int joy);
/*! @copydoc glfwGetJoystickAxes /*! @copydoc glfwGetJoystickAxes
* @ingroup platform * @ingroup platform
*/ */
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes); float* _glfwPlatformGetJoystickAxes(int joy, int* count);
/*! @copydoc glfwGetJoystickButtons /*! @copydoc glfwGetJoystickButtons
* @ingroup platform * @ingroup platform
*/ */
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons); unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count);
/*! @copydoc glfwGetJoystickName /*! @copydoc glfwGetJoystickName
* @ingroup platform * @ingroup platform

View File

@ -35,7 +35,7 @@
////// GLFW public API ////// ////// GLFW public API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetJoystickParam(int joy, int param) GLFWAPI int glfwJoystickPresent(int joy)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(0); _GLFW_REQUIRE_INIT_OR_RETURN(0);
@ -45,59 +45,37 @@ GLFWAPI int glfwGetJoystickParam(int joy, int param)
return 0; return 0;
} }
return _glfwPlatformGetJoystickParam(joy, param); return _glfwPlatformJoystickPresent(joy);
} }
GLFWAPI int glfwGetJoystickAxes(int joy, float* axes, int numaxes) GLFWAPI float* glfwGetJoystickAxes(int joy, int* count)
{ {
int i; *count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(0); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST) if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
{ {
_glfwInputError(GLFW_INVALID_ENUM, NULL); _glfwInputError(GLFW_INVALID_ENUM, NULL);
return 0; return NULL;
} }
if (axes == NULL || numaxes < 0) return _glfwPlatformGetJoystickAxes(joy, count);
}
GLFWAPI unsigned char* glfwGetJoystickButtons(int joy, int* count)
{ {
_glfwInputError(GLFW_INVALID_VALUE, NULL); *count = 0;
return 0;
}
// Clear positions _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
for (i = 0; i < numaxes; i++)
axes[i] = 0.0f;
return _glfwPlatformGetJoystickAxes(joy, axes, numaxes);
}
GLFWAPI int glfwGetJoystickButtons(int joy,
unsigned char* buttons,
int numbuttons)
{
int i;
_GLFW_REQUIRE_INIT_OR_RETURN(0);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST) if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
{ {
_glfwInputError(GLFW_INVALID_ENUM, NULL); _glfwInputError(GLFW_INVALID_ENUM, NULL);
return 0; return NULL;
} }
if (buttons == NULL || numbuttons < 0) return _glfwPlatformGetJoystickButtons(joy, count);
{
_glfwInputError(GLFW_INVALID_VALUE, NULL);
return 0;
}
// Clear button states
for (i = 0; i < numbuttons; i++)
buttons[i] = GLFW_RELEASE;
return _glfwPlatformGetJoystickButtons(joy, buttons, numbuttons);
} }
GLFWAPI const char* glfwGetJoystickName(int joy) GLFWAPI const char* glfwGetJoystickName(int joy)

View File

@ -37,23 +37,6 @@
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Return GL_TRUE if joystick is present, otherwise GL_FALSE
//
static GLboolean isJoystickPresent(int joy)
{
JOYINFO ji;
// Is it a valid stick ID (Windows don't support more than 16 sticks)?
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_16)
return GL_FALSE;
// Is the joystick present?
if (_glfw_joyGetPos(joy - GLFW_JOYSTICK_1, &ji) != JOYERR_NOERROR)
return GL_FALSE;
return GL_TRUE;
}
// Calculate normalized joystick position // Calculate normalized joystick position
// //
static float calcJoystickPos(DWORD pos, DWORD min, DWORD max) static float calcJoystickPos(DWORD pos, DWORD min, DWORD max)
@ -91,107 +74,68 @@ void _glfwTerminateJoysticks(void)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
int _glfwPlatformGetJoystickParam(int joy, int param) int _glfwPlatformJoystickPresent(int joy)
{ {
JOYCAPS jc; JOYINFO ji;
int hats;
if (!isJoystickPresent(joy)) if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR)
return 0; return GL_FALSE;
// We got this far, the joystick is present
if (param == GLFW_PRESENT)
return GL_TRUE; return GL_TRUE;
// Get joystick capabilities
_glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
hats = (jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR) ? 1 : 0;
switch (param)
{
case GLFW_AXES:
// Return number of joystick axes
return jc.wNumAxes;
case GLFW_BUTTONS:
// Return number of joystick buttons
return jc.wNumButtons + hats * 4;
default:
break;
} }
return 0; float* _glfwPlatformGetJoystickAxes(int joy, int* count)
}
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
{ {
JOYCAPS jc; JOYCAPS jc;
JOYINFOEX ji; JOYINFOEX ji;
int axis; float* axes = _glfw.win32.joystick[joy].axes;
if (!isJoystickPresent(joy)) if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
return 0; return NULL;
// Get joystick capabilities
_glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
// Get joystick state
ji.dwSize = sizeof(JOYINFOEX); ji.dwSize = sizeof(JOYINFOEX);
ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ |
JOY_RETURNR | JOY_RETURNU | JOY_RETURNV; JOY_RETURNR | JOY_RETURNU | JOY_RETURNV;
_glfw_joyGetPosEx(joy - GLFW_JOYSTICK_1, &ji); if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
return NULL;
// Get position values for all axes axes[(*count)++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
axis = 0; axes[(*count)++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
if (axis < numaxes)
axes[axis++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
if (axis < numaxes) if (jc.wCaps & JOYCAPS_HASZ)
axes[axis++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax); axes[(*count)++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASZ) if (jc.wCaps & JOYCAPS_HASR)
axes[axis++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax); axes[(*count)++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASR) if (jc.wCaps & JOYCAPS_HASU)
axes[axis++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax); axes[(*count)++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASU) if (jc.wCaps & JOYCAPS_HASV)
axes[axis++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax); axes[(*count)++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASV) return axes;
axes[axis++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
return axis;
} }
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
int numbuttons)
{ {
JOYCAPS jc; JOYCAPS jc;
JOYINFOEX ji; JOYINFOEX ji;
int button, hats; unsigned char* buttons = _glfw.win32.joystick[joy].buttons;
// Bit fields of button presses for each direction, including nil if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; return NULL;
if (!isJoystickPresent(joy))
return 0;
// Get joystick capabilities
_glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
// Get joystick state
ji.dwSize = sizeof(JOYINFOEX); ji.dwSize = sizeof(JOYINFOEX);
ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV; ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
_glfw_joyGetPosEx(joy - GLFW_JOYSTICK_1, &ji); if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
return NULL;
// Get states of all requested buttons while (*count < jc.wNumButtons)
for (button = 0; button < numbuttons && button < (int) jc.wNumButtons; button++)
{ {
buttons[button] = (unsigned char) buttons[*count] = (unsigned char)
(ji.dwButtons & (1UL << button) ? GLFW_PRESS : GLFW_RELEASE); (ji.dwButtons & (1UL << *count) ? GLFW_PRESS : GLFW_RELEASE);
(*count)++;
} }
// Virtual buttons - Inject data from hats // Virtual buttons - Inject data from hats
@ -199,42 +143,38 @@ int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
// concurrent button presses // concurrent button presses
// NOTE: this API exposes only one hat // NOTE: this API exposes only one hat
hats = (jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR) ? 1 : 0; if ((jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR))
if (hats > 0)
{ {
int j, value = ji.dwPOV / 100 / 45; int i, value = ji.dwPOV / 100 / 45;
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
if (value < 0 || value > 8) if (value < 0 || value > 8)
value = 8; value = 8;
for (j = 0; j < 4 && button < numbuttons; j++) for (i = 0; i < 4; i++)
{ {
if (directions[value] & (1 << j)) if (directions[value] & (1 << i))
buttons[button] = GLFW_PRESS; buttons[(*count)++] = GLFW_PRESS;
else else
buttons[button] = GLFW_RELEASE; buttons[(*count)++] = GLFW_RELEASE;
button++;
} }
} }
return button; return buttons;
} }
const char* _glfwPlatformGetJoystickName(int joy) const char* _glfwPlatformGetJoystickName(int joy)
{ {
JOYCAPS jc; JOYCAPS jc;
const int i = joy - GLFW_JOYSTICK_1;
if (!isJoystickPresent(joy)) if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
return NULL; return NULL;
_glfw_joyGetDevCaps(i, &jc, sizeof(JOYCAPS)); free(_glfw.win32.joystick[joy].name);
_glfw.win32.joystick[joy].name = _glfwCreateUTF8FromWideString(jc.szPname);
free(_glfw.win32.joystick[i].name); return _glfw.win32.joystick[joy].name;
_glfw.win32.joystick[i].name = _glfwCreateUTF8FromWideString(jc.szPname);
return _glfw.win32.joystick[i].name;
} }

View File

@ -200,6 +200,8 @@ typedef struct _GLFWlibraryWin32
} dwmapi; } dwmapi;
struct { struct {
float axes[6];
unsigned char buttons[36]; // 32 buttons plus one hat
char* name; char* name;
} joystick[GLFW_JOYSTICK_LAST + 1]; } joystick[GLFW_JOYSTICK_LAST + 1];

View File

@ -50,7 +50,7 @@
static int openJoystickDevice(int joy, const char* path) static int openJoystickDevice(int joy, const char* path)
{ {
#ifdef __linux__ #ifdef __linux__
char numAxes, numButtons; char axisCount, buttonCount;
char name[256]; char name[256];
int fd, version; int fd, version;
@ -74,14 +74,14 @@ static int openJoystickDevice(int joy, const char* path)
_glfw.x11.joystick[joy].name = strdup(name); _glfw.x11.joystick[joy].name = strdup(name);
ioctl(fd, JSIOCGAXES, &numAxes); ioctl(fd, JSIOCGAXES, &axisCount);
_glfw.x11.joystick[joy].numAxes = (int) numAxes; _glfw.x11.joystick[joy].axisCount = (int) axisCount;
ioctl(fd, JSIOCGBUTTONS, &numButtons); ioctl(fd, JSIOCGBUTTONS, &buttonCount);
_glfw.x11.joystick[joy].numButtons = (int) numButtons; _glfw.x11.joystick[joy].buttonCount = (int) buttonCount;
_glfw.x11.joystick[joy].axis = (float*) calloc(numAxes, sizeof(float)); _glfw.x11.joystick[joy].axes = (float*) calloc(axisCount, sizeof(float));
_glfw.x11.joystick[joy].button = (unsigned char*) calloc(numButtons, 1); _glfw.x11.joystick[joy].buttons = (unsigned char*) calloc(buttonCount, 1);
_glfw.x11.joystick[joy].present = GL_TRUE; _glfw.x11.joystick[joy].present = GL_TRUE;
#endif // __linux__ #endif // __linux__
@ -110,7 +110,12 @@ static void pollJoystickEvents(void)
result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e)); result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e));
if (errno == ENODEV) if (errno == ENODEV)
{
free(_glfw.x11.joystick[i].axes);
free(_glfw.x11.joystick[i].buttons);
free(_glfw.x11.joystick[i].name);
_glfw.x11.joystick[i].present = GL_FALSE; _glfw.x11.joystick[i].present = GL_FALSE;
}
if (result == -1) if (result == -1)
break; break;
@ -121,21 +126,21 @@ static void pollJoystickEvents(void)
switch (e.type) switch (e.type)
{ {
case JS_EVENT_AXIS: case JS_EVENT_AXIS:
_glfw.x11.joystick[i].axis[e.number] = _glfw.x11.joystick[i].axes[e.number] =
(float) e.value / 32767.0f; (float) e.value / 32767.0f;
// We need to change the sign for the Y axes, so that // We need to change the sign for the Y axes, so that
// positive = up/forward, according to the GLFW spec. // positive = up/forward, according to the GLFW spec.
if (e.number & 1) if (e.number & 1)
{ {
_glfw.x11.joystick[i].axis[e.number] = _glfw.x11.joystick[i].axes[e.number] =
-_glfw.x11.joystick[i].axis[e.number]; -_glfw.x11.joystick[i].axes[e.number];
} }
break; break;
case JS_EVENT_BUTTON: case JS_EVENT_BUTTON:
_glfw.x11.joystick[i].button[e.number] = _glfw.x11.joystick[i].buttons[e.number] =
e.value ? GLFW_PRESS : GLFW_RELEASE; e.value ? GLFW_PRESS : GLFW_RELEASE;
break; break;
@ -214,8 +219,8 @@ void _glfwTerminateJoysticks(void)
if (_glfw.x11.joystick[i].present) if (_glfw.x11.joystick[i].present)
{ {
close(_glfw.x11.joystick[i].fd); close(_glfw.x11.joystick[i].fd);
free(_glfw.x11.joystick[i].axis); free(_glfw.x11.joystick[i].axes);
free(_glfw.x11.joystick[i].button); free(_glfw.x11.joystick[i].buttons);
free(_glfw.x11.joystick[i].name); free(_glfw.x11.joystick[i].name);
_glfw.x11.joystick[i].present = GL_FALSE; _glfw.x11.joystick[i].present = GL_FALSE;
@ -229,72 +234,38 @@ void _glfwTerminateJoysticks(void)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
int _glfwPlatformGetJoystickParam(int joy, int param) int _glfwPlatformJoystickPresent(int joy)
{
pollJoystickEvents();
return _glfw.x11.joystick[joy].present;
}
float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{ {
pollJoystickEvents(); pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present) if (!_glfw.x11.joystick[joy].present)
return 0; return NULL;
switch (param) *count = _glfw.x11.joystick[joy].axisCount;
{ return _glfw.x11.joystick[joy].axes;
case GLFW_PRESENT:
return GL_TRUE;
case GLFW_AXES:
return _glfw.x11.joystick[joy].numAxes;
case GLFW_BUTTONS:
return _glfw.x11.joystick[joy].numButtons;
default:
_glfwInputError(GLFW_INVALID_ENUM, NULL);
} }
return 0; unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
}
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numAxes)
{ {
int i;
pollJoystickEvents(); pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present) if (!_glfw.x11.joystick[joy].present)
return 0; return NULL;
if (_glfw.x11.joystick[joy].numAxes < numAxes) *count = _glfw.x11.joystick[joy].buttonCount;
numAxes = _glfw.x11.joystick[joy].numAxes; return _glfw.x11.joystick[joy].buttons;
for (i = 0; i < numAxes; i++)
axes[i] = _glfw.x11.joystick[joy].axis[i];
return numAxes;
}
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
int numButtons)
{
int i;
pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present)
return 0;
if (_glfw.x11.joystick[joy].numButtons < numButtons)
numButtons = _glfw.x11.joystick[joy].numButtons;
for (i = 0; i < numButtons; i++)
buttons[i] = _glfw.x11.joystick[joy].button[i];
return numButtons;
} }
const char* _glfwPlatformGetJoystickName(int joy) const char* _glfwPlatformGetJoystickName(int joy)
{ {
if (!_glfw.x11.joystick[joy].present) pollJoystickEvents();
return NULL;
return _glfw.x11.joystick[joy].name; return _glfw.x11.joystick[joy].name;
} }

View File

@ -189,10 +189,10 @@ typedef struct _GLFWlibraryX11
struct { struct {
int present; int present;
int fd; int fd;
int numAxes; float* axes;
int numButtons; int axisCount;
float* axis; unsigned char* buttons;
unsigned char* button; int buttonCount;
char* name; char* name;
} joystick[GLFW_JOYSTICK_LAST + 1]; } joystick[GLFW_JOYSTICK_LAST + 1];

View File

@ -136,30 +136,32 @@ static void refresh_joysticks(void)
{ {
Joystick* j = joysticks + i; Joystick* j = joysticks + i;
if (glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_PRESENT)) if (glfwJoystickPresent(GLFW_JOYSTICK_1 + i))
{ {
float* axes;
unsigned char* buttons;
int axis_count, button_count; int axis_count, button_count;
free(j->name); free(j->name);
j->name = strdup(glfwGetJoystickName(GLFW_JOYSTICK_1 + i)); j->name = strdup(glfwGetJoystickName(GLFW_JOYSTICK_1 + i));
axis_count = glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_AXES); axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, &axis_count);
if (axis_count != j->axis_count) if (axis_count != j->axis_count)
{ {
j->axis_count = axis_count; j->axis_count = axis_count;
j->axes = realloc(j->axes, j->axis_count * sizeof(float)); j->axes = realloc(j->axes, j->axis_count * sizeof(float));
} }
glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, j->axes, j->axis_count); memcpy(j->axes, axes, axis_count * sizeof(float));
button_count = glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_BUTTONS); buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, &button_count);
if (button_count != j->button_count) if (button_count != j->button_count)
{ {
j->button_count = button_count; j->button_count = button_count;
j->buttons = realloc(j->buttons, j->button_count); j->buttons = realloc(j->buttons, j->button_count);
} }
glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, j->buttons, j->button_count); memcpy(j->buttons, buttons, button_count * sizeof(unsigned char));
if (!j->present) if (!j->present)
{ {