diff --git a/include/GL/glfw3.h b/include/GL/glfw3.h index 27cb119b..aba6a049 100644 --- a/include/GL/glfw3.h +++ b/include/GL/glfw3.h @@ -530,10 +530,6 @@ extern "C" { #define GLFW_CURSOR_HIDDEN 0x00040002 #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_CONNECTED 0x00061000 @@ -1930,37 +1926,31 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb * * @ingroup input */ -GLFWAPI int glfwGetJoystickParam(int joy, int param); +GLFWAPI int glfwJoystickPresent(int joy); -/*! @brief Returns the values of axes of the specified joystick. - * - * This function returns the current positions of axes of the specified - * joystick. - * +/*! @brief Returns the values of all axes of the specified joystick. * @param[in] joy The joystick to query. - * @param[out] axes The array to hold the values. - * @param[in] numaxes The size of the provided array. - * @return The number of values written to `axes`, or zero if an error - * occurred. + * @param[out] count The size of the returned array. + * @return An array of axis values, or @c NULL if the joystick is not present. + * + * @note The returned array is valid only until the next call to @ref + * glfwGetJoystickAxes for that joystick. * * @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. - * - * This function returns the current state of buttons of the specified - * joystick. - * +/*! @brief Returns the values of all buttons of the specified joystick. * @param[in] joy The joystick to query. - * @param[out] buttons The array to hold the values. - * @param[in] numbuttons The size of the provided array. - * @return The number of values written to `buttons`, or zero if an error - * occurred. + * @param[out] count The size of the returned array. + * @return An array of axis values, or @c NULL if the joystick is not present. + * + * @note The returned array is valid only until the next call to @ref + * glfwGetJoystickButtons for that joystick. * * @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. * diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 22a9521e..9795ff90 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -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; } diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 62dc726d..39197b80 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -78,18 +78,17 @@ typedef struct _GLFWwindowNS //------------------------------------------------------------------------ typedef struct { - int present; - char name[256]; + int present; + char name[256]; IOHIDDeviceInterface** interface; - int numAxes; - int numButtons; - int numHats; + CFMutableArrayRef axisElements; + CFMutableArrayRef buttonElements; + CFMutableArrayRef hatElements; - CFMutableArrayRef axes; - CFMutableArrayRef buttons; - CFMutableArrayRef hats; + float* axes; + unsigned char* buttons; } _GLFWjoy; diff --git a/src/internal.h b/src/internal.h index 8121ce93..80c8e388 100644 --- a/src/internal.h +++ b/src/internal.h @@ -407,20 +407,20 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); */ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); -/*! @copydoc glfwGetJoystickParam +/*! @copydoc glfwJoystickPresent * @ingroup platform */ -int _glfwPlatformGetJoystickParam(int joy, int param); +int _glfwPlatformJoystickPresent(int joy); /*! @copydoc glfwGetJoystickAxes * @ingroup platform */ -int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes); +float* _glfwPlatformGetJoystickAxes(int joy, int* count); /*! @copydoc glfwGetJoystickButtons * @ingroup platform */ -int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons); +unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count); /*! @copydoc glfwGetJoystickName * @ingroup platform diff --git a/src/joystick.c b/src/joystick.c index b25719b6..8a8ee73d 100644 --- a/src/joystick.c +++ b/src/joystick.c @@ -35,7 +35,7 @@ ////// GLFW public API ////// ////////////////////////////////////////////////////////////////////////// -GLFWAPI int glfwGetJoystickParam(int joy, int param) +GLFWAPI int glfwJoystickPresent(int joy) { _GLFW_REQUIRE_INIT_OR_RETURN(0); @@ -45,59 +45,37 @@ GLFWAPI int glfwGetJoystickParam(int joy, int param) 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) { _glfwInputError(GLFW_INVALID_ENUM, NULL); - return 0; + return NULL; } - if (axes == NULL || numaxes < 0) - { - _glfwInputError(GLFW_INVALID_VALUE, NULL); - return 0; - } - - // Clear positions - for (i = 0; i < numaxes; i++) - axes[i] = 0.0f; - - return _glfwPlatformGetJoystickAxes(joy, axes, numaxes); + return _glfwPlatformGetJoystickAxes(joy, count); } -GLFWAPI int glfwGetJoystickButtons(int joy, - unsigned char* buttons, - int numbuttons) +GLFWAPI unsigned char* glfwGetJoystickButtons(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) { _glfwInputError(GLFW_INVALID_ENUM, NULL); - return 0; + return NULL; } - if (buttons == NULL || numbuttons < 0) - { - _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); + return _glfwPlatformGetJoystickButtons(joy, count); } GLFWAPI const char* glfwGetJoystickName(int joy) diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 09a97845..8a69fcc8 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -37,23 +37,6 @@ ////// 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 // static float calcJoystickPos(DWORD pos, DWORD min, DWORD max) @@ -91,107 +74,68 @@ void _glfwTerminateJoysticks(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformGetJoystickParam(int joy, int param) +int _glfwPlatformJoystickPresent(int joy) { - JOYCAPS jc; - int hats; + JOYINFO ji; - if (!isJoystickPresent(joy)) - return 0; + if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR) + return GL_FALSE; - // We got this far, the joystick is present - if (param == GLFW_PRESENT) - 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; + return GL_TRUE; } -int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes) +float* _glfwPlatformGetJoystickAxes(int joy, int* count) { JOYCAPS jc; JOYINFOEX ji; - int axis; + float* axes = _glfw.win32.joystick[joy].axes; - if (!isJoystickPresent(joy)) - return 0; + if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + return NULL; - // Get joystick capabilities - _glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS)); - - // Get joystick state ji.dwSize = sizeof(JOYINFOEX); ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | 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 - axis = 0; - if (axis < numaxes) - axes[axis++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax); + axes[(*count)++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax); + axes[(*count)++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax); - if (axis < numaxes) - axes[axis++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax); + if (jc.wCaps & JOYCAPS_HASZ) + axes[(*count)++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax); - if (axis < numaxes && jc.wCaps & JOYCAPS_HASZ) - axes[axis++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax); + if (jc.wCaps & JOYCAPS_HASR) + axes[(*count)++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax); - if (axis < numaxes && jc.wCaps & JOYCAPS_HASR) - axes[axis++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax); + if (jc.wCaps & JOYCAPS_HASU) + axes[(*count)++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax); - if (axis < numaxes && jc.wCaps & JOYCAPS_HASU) - axes[axis++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax); + if (jc.wCaps & JOYCAPS_HASV) + axes[(*count)++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax); - if (axis < numaxes && jc.wCaps & JOYCAPS_HASV) - axes[axis++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax); - - return axis; + return axes; } -int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, - int numbuttons) +unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { JOYCAPS jc; JOYINFOEX ji; - int button, hats; + unsigned char* buttons = _glfw.win32.joystick[joy].buttons; - // Bit fields of button presses for each direction, including nil - const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + 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.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 - for (button = 0; button < numbuttons && button < (int) jc.wNumButtons; button++) + while (*count < jc.wNumButtons) { - buttons[button] = (unsigned char) - (ji.dwButtons & (1UL << button) ? GLFW_PRESS : GLFW_RELEASE); + buttons[*count] = (unsigned char) + (ji.dwButtons & (1UL << *count) ? GLFW_PRESS : GLFW_RELEASE); + (*count)++; } // Virtual buttons - Inject data from hats @@ -199,42 +143,38 @@ int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, // concurrent button presses // NOTE: this API exposes only one hat - hats = (jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR) ? 1 : 0; - - if (hats > 0) + if ((jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR)) { - 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) value = 8; - for (j = 0; j < 4 && button < numbuttons; j++) + for (i = 0; i < 4; i++) { - if (directions[value] & (1 << j)) - buttons[button] = GLFW_PRESS; + if (directions[value] & (1 << i)) + buttons[(*count)++] = GLFW_PRESS; else - buttons[button] = GLFW_RELEASE; - - button++; + buttons[(*count)++] = GLFW_RELEASE; } } - return button; + return buttons; } const char* _glfwPlatformGetJoystickName(int joy) { JOYCAPS jc; - const int i = joy - GLFW_JOYSTICK_1; - if (!isJoystickPresent(joy)) + if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) 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); - _glfw.win32.joystick[i].name = _glfwCreateUTF8FromWideString(jc.szPname); - - return _glfw.win32.joystick[i].name; + return _glfw.win32.joystick[joy].name; } diff --git a/src/win32_platform.h b/src/win32_platform.h index e951c4aa..20a3faed 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -200,6 +200,8 @@ typedef struct _GLFWlibraryWin32 } dwmapi; struct { + float axes[6]; + unsigned char buttons[36]; // 32 buttons plus one hat char* name; } joystick[GLFW_JOYSTICK_LAST + 1]; diff --git a/src/x11_joystick.c b/src/x11_joystick.c index a240df59..17edf8ac 100644 --- a/src/x11_joystick.c +++ b/src/x11_joystick.c @@ -50,7 +50,7 @@ static int openJoystickDevice(int joy, const char* path) { #ifdef __linux__ - char numAxes, numButtons; + char axisCount, buttonCount; char name[256]; int fd, version; @@ -74,14 +74,14 @@ static int openJoystickDevice(int joy, const char* path) _glfw.x11.joystick[joy].name = strdup(name); - ioctl(fd, JSIOCGAXES, &numAxes); - _glfw.x11.joystick[joy].numAxes = (int) numAxes; + ioctl(fd, JSIOCGAXES, &axisCount); + _glfw.x11.joystick[joy].axisCount = (int) axisCount; - ioctl(fd, JSIOCGBUTTONS, &numButtons); - _glfw.x11.joystick[joy].numButtons = (int) numButtons; + ioctl(fd, JSIOCGBUTTONS, &buttonCount); + _glfw.x11.joystick[joy].buttonCount = (int) buttonCount; - _glfw.x11.joystick[joy].axis = (float*) calloc(numAxes, sizeof(float)); - _glfw.x11.joystick[joy].button = (unsigned char*) calloc(numButtons, 1); + _glfw.x11.joystick[joy].axes = (float*) calloc(axisCount, sizeof(float)); + _glfw.x11.joystick[joy].buttons = (unsigned char*) calloc(buttonCount, 1); _glfw.x11.joystick[joy].present = GL_TRUE; #endif // __linux__ @@ -110,7 +110,12 @@ static void pollJoystickEvents(void) result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e)); 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; + } if (result == -1) break; @@ -121,21 +126,21 @@ static void pollJoystickEvents(void) switch (e.type) { case JS_EVENT_AXIS: - _glfw.x11.joystick[i].axis[e.number] = + _glfw.x11.joystick[i].axes[e.number] = (float) e.value / 32767.0f; // We need to change the sign for the Y axes, so that // positive = up/forward, according to the GLFW spec. if (e.number & 1) { - _glfw.x11.joystick[i].axis[e.number] = - -_glfw.x11.joystick[i].axis[e.number]; + _glfw.x11.joystick[i].axes[e.number] = + -_glfw.x11.joystick[i].axes[e.number]; } break; case JS_EVENT_BUTTON: - _glfw.x11.joystick[i].button[e.number] = + _glfw.x11.joystick[i].buttons[e.number] = e.value ? GLFW_PRESS : GLFW_RELEASE; break; @@ -214,8 +219,8 @@ void _glfwTerminateJoysticks(void) if (_glfw.x11.joystick[i].present) { close(_glfw.x11.joystick[i].fd); - free(_glfw.x11.joystick[i].axis); - free(_glfw.x11.joystick[i].button); + 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; @@ -229,72 +234,38 @@ void _glfwTerminateJoysticks(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -int _glfwPlatformGetJoystickParam(int joy, int param) +int _glfwPlatformJoystickPresent(int joy) { pollJoystickEvents(); - if (!_glfw.x11.joystick[joy].present) - return 0; - - switch (param) - { - 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; + return _glfw.x11.joystick[joy].present; } -int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numAxes) +float* _glfwPlatformGetJoystickAxes(int joy, int* count) { - int i; - pollJoystickEvents(); if (!_glfw.x11.joystick[joy].present) - return 0; + return NULL; - if (_glfw.x11.joystick[joy].numAxes < numAxes) - numAxes = _glfw.x11.joystick[joy].numAxes; - - for (i = 0; i < numAxes; i++) - axes[i] = _glfw.x11.joystick[joy].axis[i]; - - return numAxes; + *count = _glfw.x11.joystick[joy].axisCount; + return _glfw.x11.joystick[joy].axes; } -int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, - int numButtons) +unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { - int i; - pollJoystickEvents(); if (!_glfw.x11.joystick[joy].present) - return 0; + return NULL; - 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; + *count = _glfw.x11.joystick[joy].buttonCount; + return _glfw.x11.joystick[joy].buttons; } const char* _glfwPlatformGetJoystickName(int joy) { - if (!_glfw.x11.joystick[joy].present) - return NULL; + pollJoystickEvents(); return _glfw.x11.joystick[joy].name; } diff --git a/src/x11_platform.h b/src/x11_platform.h index ea1b4c7d..172b4d81 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -189,10 +189,10 @@ typedef struct _GLFWlibraryX11 struct { int present; int fd; - int numAxes; - int numButtons; - float* axis; - unsigned char* button; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; char* name; } joystick[GLFW_JOYSTICK_LAST + 1]; diff --git a/tests/joysticks.c b/tests/joysticks.c index 67845586..2f9e64b8 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -136,30 +136,32 @@ static void refresh_joysticks(void) { 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; free(j->name); 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) { j->axis_count = axis_count; 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) { j->button_count = 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) {