Browse Source

New joystick API.

Camilla Berglund 12 years ago
parent
commit
7f2eb7b15b
10 changed files with 279 additions and 460 deletions
  1. 15 25
      include/GL/glfw3.h
  2. 153 216
      src/cocoa_joystick.m
  3. 7 8
      src/cocoa_platform.h
  4. 4 4
      src/internal.h
  5. 12 34
      src/joystick.c
  6. 46 106
      src/win32_joystick.c
  7. 2 0
      src/win32_platform.h
  8. 29 58
      src/x11_joystick.c
  9. 4 4
      src/x11_platform.h
  10. 7 5
      tests/joysticks.c

+ 15 - 25
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.
  *

+ 153 - 216
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 (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 < joystick->numHats;  j++)
+            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;
             }
-        }
 
-        _GLFWjoy* joystick = &_glfw.ns.joysticks[deviceCounter];
+            CFRelease(valueRef);
+        }
 
+        _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);
-
-        CFTypeRef refTopElement;
-
-        refTopElement = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
-                                                        CFSTR(kIOHIDElementKey),
-                                                        kCFAllocatorDefault,
-                                                        kNilOptions);
-        CFTypeID type = CFGetTypeID(refTopElement);
-        if (type == CFArrayGetTypeID())
+        joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
+        joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
+        joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
+
+        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;
-    }
+    pollJoystickEvents();
 
-    return GL_FALSE;
+    return _glfw.ns.joysticks[joy].present;
 }
 
-int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
+float* _glfwPlatformGetJoystickAxes(int joy, int* count)
 {
-    int i;
-
-    if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
-        return 0;
-
-    _GLFWjoy joystick = _glfw.ns.joysticks[joy];
+    _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 (!joystick->present)
+        return NULL;
 
-        if (i & 1)
-            axes[i] = -axes[i];
-    }
-
-    return numaxes;
+    *count = (int) CFArrayGetCount(joystick->axisElements);
+    return joystick->axes;
 }
 
-int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
-                                    int numbuttons)
+unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
 {
-    int i, j, button;
-
-    if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
-        return 0;
-
-    _GLFWjoy joystick = _glfw.ns.joysticks[joy];
-
-    if (!joystick.present)
-        return 0;
+    _GLFWjoy* joystick = _glfw.ns.joysticks + joy;
 
-    // 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;
-    }
-
-    // Virtual buttons - Inject data from hats
-    // 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);
-
-        int value = hat->value;
-        if (value < 0 || value > 8)
-            value = 8;
-
-        for (j = 0;  j < 4 && button < numbuttons;  j++)
-        {
-            if (directions[value] & (1 << j))
-                buttons[button] = GLFW_PRESS;
-            else
-                buttons[button] = GLFW_RELEASE;
+    if (!joystick->present)
+        return NULL;
 
-            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;
 }
 

+ 7 - 8
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;
 

+ 4 - 4
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

+ 12 - 34
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;
-    }
-
-    if (axes == NULL || numaxes < 0)
-    {
-        _glfwInputError(GLFW_INVALID_VALUE, NULL);
-        return 0;
+        return NULL;
     }
 
-    // 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;
-    }
-
-    if (buttons == NULL || numbuttons < 0)
-    {
-        _glfwInputError(GLFW_INVALID_VALUE, NULL);
-        return 0;
+        return NULL;
     }
 
-    // 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)

+ 46 - 106
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;
-
-    if (!isJoystickPresent(joy))
-        return 0;
-
-    // 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;
+    JOYINFO ji;
 
-        default:
-            break;
-    }
+    if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR)
+        return GL_FALSE;
 
-    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;
-
-    // Get joystick capabilities
-    _glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
+    if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
+        return NULL;
 
-    // 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);
-
-    // Get position values for all axes
-    axis = 0;
-    if (axis < numaxes)
-        axes[axis++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
+    if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
+        return NULL;
 
-    if (axis < numaxes)
-        axes[axis++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
+    axes[(*count)++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
+    axes[(*count)++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
 
-    if (axis < numaxes && jc.wCaps & JOYCAPS_HASZ)
-        axes[axis++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
+    if (jc.wCaps & JOYCAPS_HASZ)
+        axes[(*count)++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
 
-    if (axis < numaxes && jc.wCaps & JOYCAPS_HASR)
-        axes[axis++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
+    if (jc.wCaps & JOYCAPS_HASR)
+        axes[(*count)++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
 
-    if (axis < numaxes && jc.wCaps & JOYCAPS_HASU)
-        axes[axis++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
+    if (jc.wCaps & JOYCAPS_HASU)
+        axes[(*count)++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
 
-    if (axis < numaxes && jc.wCaps & JOYCAPS_HASV)
-        axes[axis++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
+    if (jc.wCaps & JOYCAPS_HASV)
+        axes[(*count)++] = -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 (!isJoystickPresent(joy))
-        return 0;
-
-    // Get joystick capabilities
-    _glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
+    if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
+        return NULL;
 
-    // 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[i].name);
-    _glfw.win32.joystick[i].name = _glfwCreateUTF8FromWideString(jc.szPname);
+    free(_glfw.win32.joystick[joy].name);
+    _glfw.win32.joystick[joy].name = _glfwCreateUTF8FromWideString(jc.szPname);
 
-    return _glfw.win32.joystick[i].name;
+    return _glfw.win32.joystick[joy].name;
 }
 

+ 2 - 0
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];
 

+ 29 - 58
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;
-
-    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 NULL;
 
-    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;
-
-    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 NULL;
 
-    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;
 }

+ 4 - 4
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];
 

+ 7 - 5
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)
             {