Moving the "\freeglut_xinput.c" file from the Common directory to the x11 directory...
[freeglut] / src / Common / freeglut_joystick.c
index 416091f..76f8542 100644 (file)
 #    include <sys/param.h>\r
 #endif\r
 \r
-/*\r
- * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"\r
- * interspersed\r
- */\r
-\r
-/* XXX It might be better to poll the operating system for the numbers of buttons and\r
- * XXX axes and then dynamically allocate the arrays.\r
- */\r
-#define _JS_MAX_BUTTONS 32\r
-\r
-#if TARGET_HOST_MACINTOSH\r
-#    define _JS_MAX_AXES  9\r
-#    include <InputSprocket.h>\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-#    define _JS_MAX_AXES 16\r
-#    include <mach/mach.h>\r
-#    include <IOKit/IOkitLib.h>\r
-#    include <IOKit/hid/IOHIDLib.h>\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-#    define _JS_MAX_AXES  8\r
-#    include <windows.h>\r
-#    include <mmsystem.h>\r
-#    include <regstr.h>\r
-\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-#    define _JS_MAX_AXES 16\r
-#    ifdef HAVE_SYS_IOCTL_H\r
-#        include <sys/ioctl.h>\r
-#    endif\r
-#    ifdef HAVE_FCNTL_H\r
-#        include <fcntl.h>\r
-#    endif\r
-#    ifdef HAVE_ERRNO_H\r
-#        include <errno.h>\r
-#        include <string.h>\r
-#    endif\r
-#    if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
-/* XXX The below hack is done until freeglut's autoconf is updated. */\r
-#        define HAVE_USB_JS    1\r
-\r
-#        if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\r
-#            include <sys/joystick.h>\r
-#        else\r
-/*\r
- * XXX NetBSD/amd64 systems may find that they have to steal the\r
- * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.\r
- * XXX I cannot comment whether that works for the interface, but\r
- * XXX it lets you compile...(^&  I do not think that we can do away\r
- * XXX with this header.\r
- */\r
-#            include <machine/joystick.h>         /* For analog joysticks */\r
-#        endif\r
-#        define JS_DATA_TYPE joystick\r
-#        define JS_RETURN (sizeof(struct JS_DATA_TYPE))\r
-#    endif\r
-\r
-#    if defined(__linux__)\r
-#        include <linux/joystick.h>\r
-\r
-/* check the joystick driver version */\r
-#        if defined(JS_VERSION) && JS_VERSION >= 0x010000\r
-#            define JS_NEW\r
-#        endif\r
-#    else  /* Not BSD or Linux */\r
-#        ifndef JS_RETURN\r
-\r
-  /*\r
-   * We'll put these values in and that should\r
-   * allow the code to at least compile when there is\r
-   * no support. The JS open routine should error out\r
-   * and shut off all the code downstream anyway and if\r
-   * the application doesn't use a joystick we'll be fine.\r
-   */\r
-\r
-  struct JS_DATA_TYPE\r
-  {\r
-    int buttons;\r
-    int x;\r
-    int y;\r
-  };\r
-\r
-#            define JS_RETURN (sizeof(struct JS_DATA_TYPE))\r
-#        endif\r
-#    endif\r
-#endif\r
-\r
 #define JS_TRUE  1\r
 #define JS_FALSE 0\r
 \r
@@ -376,65 +284,6 @@ static int fghJoystickInitializeHID(struct os_specific_s *os,
 #endif\r
 \r
 /*\r
- * Definition of "SFG_Joystick" structure -- based on JS's "jsJoystick" object class.\r
- * See "js.h" lines 80-178.\r
- */\r
-typedef struct tagSFG_Joystick SFG_Joystick;\r
-struct tagSFG_Joystick\r
-{\r
-#if TARGET_HOST_MACINTOSH\r
-#define  ISP_NUM_AXIS    9\r
-#define  ISP_NUM_NEEDS  41\r
-    ISpElementReference isp_elem  [ ISP_NUM_NEEDS ];\r
-    ISpNeed             isp_needs [ ISP_NUM_NEEDS ];\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-    IOHIDDeviceInterface ** hidDev;\r
-    IOHIDElementCookie buttonCookies[41];\r
-    IOHIDElementCookie axisCookies[_JS_MAX_AXES];\r
-    long minReport[_JS_MAX_AXES],\r
-         maxReport[_JS_MAX_AXES];\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-    JOYCAPS     jsCaps;\r
-    JOYINFOEX   js;\r
-    UINT        js_id;\r
-#endif\r
-\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-#   if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
-       struct os_specific_s *os;\r
-#   endif\r
-\r
-#   ifdef JS_NEW\r
-       struct js_event     js;\r
-       int          tmp_buttons;\r
-       float        tmp_axes [ _JS_MAX_AXES ];\r
-#   else\r
-       struct JS_DATA_TYPE js;\r
-#   endif\r
-\r
-    char         fname [ 128 ];\r
-    int          fd;\r
-#endif\r
-\r
-    int          id;\r
-    GLboolean    error;\r
-    char         name [ 128 ];\r
-    int          num_axes;\r
-    int          num_buttons;\r
-\r
-    float dead_band[ _JS_MAX_AXES ];\r
-    float saturate [ _JS_MAX_AXES ];\r
-    float center   [ _JS_MAX_AXES ];\r
-    float max      [ _JS_MAX_AXES ];\r
-    float min      [ _JS_MAX_AXES ];\r
-};\r
-\r
-/*\r
  * Functions associated with the "jsJoystick" class in PLIB\r
  */\r
 #if TARGET_HOST_MAC_OSX\r
@@ -456,6 +305,9 @@ static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
 \r
 \r
 /* External function declarations (mostly platform-specific) */\r
+extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );\r
+extern void fgPlatformJoystickOpen( SFG_Joystick* joy );\r
+extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );\r
 extern void fgPlatformJoystickClose ( int ident );\r
 \r
 /*\r
@@ -464,22 +316,11 @@ extern void fgPlatformJoystickClose ( int ident );
 #define MAX_NUM_JOYSTICKS  2\r
 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];\r
 \r
-\r
 /*\r
  * Read the raw joystick data\r
  */\r
 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
 {\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-    MMRESULT status;\r
-#else\r
-    int status;\r
-#endif\r
-\r
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
-    int len;\r
-#endif\r
-\r
     int i;\r
 \r
     /* Defaults */\r
@@ -493,393 +334,109 @@ static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
     if( joy->error )\r
         return;\r
 \r
-#if TARGET_HOST_MACINTOSH\r
-    if ( buttons )\r
+       fgPlatformJoystickRawRead ( joy, buttons, axes );\r
+}\r
+\r
+/*\r
+ * Correct the joystick axis data\r
+ */\r
+static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )\r
+{\r
+    if( value < joy->center[ axis ] )\r
     {\r
-        *buttons = 0;\r
+        float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -\r
+                                                       joy->min[ axis ] );\r
 \r
-        for ( i = 0; i < joy->num_buttons; i++ )\r
-        {\r
-            UInt32 state;\r
-            int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);\r
-            ISP_CHECK_ERR(err)\r
+        if( xx < -joy->saturate[ axis ] )\r
+            return -1.0f;\r
 \r
-            *buttons |= state << i;\r
-        }\r
-    }\r
+        if( xx > -joy->dead_band [ axis ] )\r
+            return 0.0f;\r
 \r
-    if ( axes )\r
-    {\r
-        for ( i = 0; i < joy->num_axes; i++ )\r
-        {\r
-            UInt32 state;\r
-            int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );\r
-            ISP_CHECK_ERR(err)\r
+        xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -\r
+                                                 joy->dead_band[ axis ] );\r
 \r
-            axes [i] = (float) state;\r
-        }\r
+        return ( xx < -1.0f ) ? -1.0f : xx;\r
     }\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-    if ( buttons != NULL )\r
+    else\r
     {\r
-        *buttons = 0;\r
+        float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -\r
+                                                        joy->center[ axis ] );\r
 \r
-        for ( i = 0; i < joy->num_buttons; i++ )\r
-        {\r
-            IOHIDEventStruct hidEvent;\r
-            (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );\r
-            if ( hidEvent.value )\r
-                *buttons |= 1 << i;\r
-        }\r
-    }\r
+        if( xx > joy->saturate[ axis ] )\r
+            return 1.0f;\r
 \r
-    if ( axes != NULL )\r
-    {\r
-        for ( i = 0; i < joy->num_axes; i++ )\r
-        {\r
-            IOHIDEventStruct hidEvent;\r
-            (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );\r
-            axes[i] = hidEvent.value;\r
-        }\r
-    }\r
-#endif\r
+        if( xx < joy->dead_band[ axis ] )\r
+            return 0.0f;\r
 \r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-    status = joyGetPosEx( joy->js_id, &joy->js );\r
+        xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -\r
+                                                 joy->dead_band[ axis ] );\r
 \r
-    if ( status != JOYERR_NOERROR )\r
-    {\r
-        joy->error = GL_TRUE;\r
-        return;\r
+        return ( xx > 1.0f ) ? 1.0f : xx;\r
     }\r
+}\r
 \r
-    if ( buttons )\r
-        *buttons = joy->js.dwButtons;\r
+/*\r
+ * Read the corrected joystick data\r
+ */\r
+static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )\r
+{\r
+    float raw_axes[ _JS_MAX_AXES ];\r
+    int  i;\r
 \r
-    if ( axes )\r
+    if( joy->error )\r
     {\r
-        /*\r
-         * WARNING - Fall through case clauses!!\r
-         */\r
-        switch ( joy->num_axes )\r
-        {\r
-        case 8:\r
-            /* Generate two POV axes from the POV hat angle.\r
-             * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in\r
-             *   hundredths of a degree, or 0xFFFF when idle.\r
-             */\r
-            if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )\r
-            {\r
-              axes [ 6 ] = 0.0;\r
-              axes [ 7 ] = 0.0;\r
-            }\r
-            else\r
-            {\r
-              /* This is the contentious bit: how to convert angle to X/Y.\r
-               *    wk: I know of no define for PI that we could use here:\r
-               *    SG_PI would pull in sg, M_PI is undefined for MSVC\r
-               * But the accuracy of the value of PI is very unimportant at\r
-               * this point.\r
-               */\r
-              float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );\r
-              float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );\r
-\r
-              /* Convert to coordinates on a square so that North-East\r
-               * is (1,1) not (.7,.7), etc.\r
-               * s and c cannot both be zero so we won't divide by zero.\r
-               */\r
-              if ( fabs ( s ) < fabs ( c ) )\r
-              {\r
-                axes [ 6 ] = ( c < 0.0 ) ? -s/c  : s/c ;\r
-                axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;\r
-              }\r
-              else\r
-              {\r
-                axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;\r
-                axes [ 7 ] = ( s < 0.0 ) ? -c/s  : c/s ;\r
-              }\r
-            }\r
+        if( buttons )\r
+            *buttons = 0;\r
 \r
-        case 6: axes[5] = (float) joy->js.dwVpos;\r
-        case 5: axes[4] = (float) joy->js.dwUpos;\r
-        case 4: axes[3] = (float) joy->js.dwRpos;\r
-        case 3: axes[2] = (float) joy->js.dwZpos;\r
-        case 2: axes[1] = (float) joy->js.dwYpos;\r
-        case 1: axes[0] = (float) joy->js.dwXpos;\r
-        }\r
+        if( axes )\r
+            for ( i=0; i<joy->num_axes; i++ )\r
+                axes[ i ] = 0.0f;\r
     }\r
-#endif\r
 \r
-#if TARGET_HOST_POSIX_X11\r
-#    if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
-    if ( joy->os->is_analog )\r
-    {\r
-        int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );\r
-        if ( status != sizeof(joy->os->ajs) ) {\r
-            perror ( joy->os->fname );\r
-            joy->error = GL_TRUE;\r
-            return;\r
-        }\r
-        if ( buttons != NULL )\r
-            *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );\r
+    fghJoystickRawRead( joy, buttons, raw_axes );\r
 \r
-        if ( axes != NULL )\r
-        {\r
-            axes[0] = (float) joy->os->ajs.x;\r
-            axes[1] = (float) joy->os->ajs.y;\r
-        }\r
+    if( axes )\r
+        for( i=0; i<joy->num_axes; i++ )\r
+            axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );\r
+}\r
 \r
-        return;\r
-    }\r
+/*\r
+ * Happy happy happy joy joy joy (happy new year toudi :D)\r
+ */\r
 \r
-#        ifdef HAVE_USB_JS\r
-    while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )\r
-    {\r
-        struct hid_item *h;\r
 \r
-        for  ( h = joy->os->hids; h; h = h->next )\r
-        {\r
-            int d = hid_get_data ( joy->os->hid_data_buf, h );\r
+#if TARGET_HOST_MAC_OSX\r
+/** open the IOKit connection, enumerate all the HID devices, add their\r
+interface references to the static array. We then use the array index\r
+as the device number when we come to open() the joystick. */\r
+static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )\r
+{\r
+    CFMutableDictionaryRef hidMatch = NULL;\r
+    IOReturn rv = kIOReturnSuccess;\r
 \r
-            int page = HID_PAGE ( h->usage );\r
-            int usage = HID_USAGE ( h->usage );\r
+    io_iterator_t hidIterator;\r
+    io_object_t ioDev;\r
 \r
-            if ( page == HUP_GENERIC_DESKTOP )\r
-            {\r
-                int i;\r
-                for ( i = 0; i < joy->num_axes; i++ )\r
-                    if (joy->os->axes_usage[i] == usage)\r
-                    {\r
-                        if (usage == HUG_HAT_SWITCH)\r
-                        {\r
-                            if (d < 0 || d > 8)\r
-                                d = 0;  /* safety */\r
-                            joy->os->cache_axes[i] = (float)hatmap_x[d];\r
-                            joy->os->cache_axes[i + 1] = (float)hatmap_y[d];\r
-                        }\r
-                        else\r
-                        {\r
-                            joy->os->cache_axes[i] = (float)d;\r
-                        }\r
-                        break;\r
-                    }\r
-            }\r
-            else if (page == HUP_BUTTON)\r
-            {\r
-               if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)\r
-               {\r
-                   if (d)\r
-                       joy->os->cache_buttons |=  (1 << ( usage - 1 ));\r
-                   else\r
-                       joy->os->cache_buttons &= ~(1 << ( usage - 1 ));\r
-               }\r
-            }\r
-        }\r
-    }\r
-#ifdef HAVE_ERRNO_H\r
-    if ( len < 0 && errno != EAGAIN )\r
-#else\r
-    if ( len < 0 )\r
-#endif\r
-    {\r
-        perror( joy->os->fname );\r
-        joy->error = 1;\r
+    /* build a dictionary matching HID devices */\r
+    hidMatch = IOServiceMatching(kIOHIDDeviceKey);\r
+\r
+    rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);\r
+    if (rv != kIOReturnSuccess || !hidIterator) {\r
+      fgWarning( "no joystick (HID) devices found" );\r
+      return;\r
     }\r
-    if ( buttons != NULL ) *buttons = joy->os->cache_buttons;\r
-    if ( axes    != NULL )\r
-        memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );\r
-#        endif\r
-#    endif\r
 \r
-#    ifdef JS_NEW\r
+    /* iterate */\r
+    while ((ioDev = IOIteratorNext(hidIterator))) {\r
+        /* filter out keyboard and mouse devices */\r
+        CFDictionaryRef properties = getCFProperties(ioDev);\r
+        long usage, page;\r
 \r
-    while ( 1 )\r
-    {\r
-        status = read ( joy->fd, &joy->js, sizeof(struct js_event) );\r
-\r
-        if ( status != sizeof( struct js_event ) )\r
-        {\r
-#ifdef HAVE_ERRNO_H\r
-            if ( errno == EAGAIN )\r
-            {\r
-                /* Use the old values */\r
-                if ( buttons )\r
-                    *buttons = joy->tmp_buttons;\r
-                if ( axes )\r
-                    memcpy( axes, joy->tmp_axes,\r
-                            sizeof( float ) * joy->num_axes );\r
-                return;\r
-            }\r
-#endif\r
-\r
-            fgWarning ( "%s", joy->fname );\r
-            joy->error = GL_TRUE;\r
-            return;\r
-        }\r
-\r
-        switch ( joy->js.type & ~JS_EVENT_INIT )\r
-        {\r
-        case JS_EVENT_BUTTON:\r
-            if( joy->js.value == 0 ) /* clear the flag */\r
-                joy->tmp_buttons &= ~( 1 << joy->js.number );\r
-            else\r
-                joy->tmp_buttons |= ( 1 << joy->js.number );\r
-            break;\r
-\r
-        case JS_EVENT_AXIS:\r
-            if ( joy->js.number < joy->num_axes )\r
-            {\r
-                joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;\r
-\r
-                if( axes )\r
-                    memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );\r
-            }\r
-            break;\r
-\r
-        default:\r
-            fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );\r
-\r
-            /* use the old values */\r
-\r
-            if ( buttons != NULL ) *buttons = joy->tmp_buttons;\r
-            if ( axes    != NULL )\r
-                memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );\r
-\r
-            return;\r
-        }\r
-\r
-        if( buttons )\r
-            *buttons = joy->tmp_buttons;\r
-    }\r
-#    else\r
-\r
-    status = read( joy->fd, &joy->js, JS_RETURN );\r
-\r
-    if ( status != JS_RETURN )\r
-    {\r
-        fgWarning( "%s", joy->fname );\r
-        joy->error = GL_TRUE;\r
-        return;\r
-    }\r
-\r
-    if ( buttons )\r
-#        if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
-        *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 );  /* XXX Should not be here -- BSD is handled earlier */\r
-#        else\r
-        *buttons = joy->js.buttons;\r
-#        endif\r
-\r
-    if ( axes )\r
-    {\r
-        axes[ 0 ] = (float) joy->js.x;\r
-        axes[ 1 ] = (float) joy->js.y;\r
-    }\r
-#    endif\r
-#endif\r
-}\r
-\r
-/*\r
- * Correct the joystick axis data\r
- */\r
-static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )\r
-{\r
-    if( value < joy->center[ axis ] )\r
-    {\r
-        float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -\r
-                                                       joy->min[ axis ] );\r
-\r
-        if( xx < -joy->saturate[ axis ] )\r
-            return -1.0f;\r
-\r
-        if( xx > -joy->dead_band [ axis ] )\r
-            return 0.0f;\r
-\r
-        xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -\r
-                                                 joy->dead_band[ axis ] );\r
-\r
-        return ( xx < -1.0f ) ? -1.0f : xx;\r
-    }\r
-    else\r
-    {\r
-        float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -\r
-                                                        joy->center[ axis ] );\r
-\r
-        if( xx > joy->saturate[ axis ] )\r
-            return 1.0f;\r
-\r
-        if( xx < joy->dead_band[ axis ] )\r
-            return 0.0f;\r
-\r
-        xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -\r
-                                                 joy->dead_band[ axis ] );\r
-\r
-        return ( xx > 1.0f ) ? 1.0f : xx;\r
-    }\r
-}\r
-\r
-/*\r
- * Read the corrected joystick data\r
- */\r
-static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )\r
-{\r
-    float raw_axes[ _JS_MAX_AXES ];\r
-    int  i;\r
-\r
-    if( joy->error )\r
-    {\r
-        if( buttons )\r
-            *buttons = 0;\r
-\r
-        if( axes )\r
-            for ( i=0; i<joy->num_axes; i++ )\r
-                axes[ i ] = 0.0f;\r
-    }\r
-\r
-    fghJoystickRawRead( joy, buttons, raw_axes );\r
-\r
-    if( axes )\r
-        for( i=0; i<joy->num_axes; i++ )\r
-            axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );\r
-}\r
-\r
-/*\r
- * Happy happy happy joy joy joy (happy new year toudi :D)\r
- */\r
-\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-/** open the IOKit connection, enumerate all the HID devices, add their\r
-interface references to the static array. We then use the array index\r
-as the device number when we come to open() the joystick. */\r
-static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )\r
-{\r
-    CFMutableDictionaryRef hidMatch = NULL;\r
-    IOReturn rv = kIOReturnSuccess;\r
-\r
-    io_iterator_t hidIterator;\r
-    io_object_t ioDev;\r
-\r
-    /* build a dictionary matching HID devices */\r
-    hidMatch = IOServiceMatching(kIOHIDDeviceKey);\r
-\r
-    rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);\r
-    if (rv != kIOReturnSuccess || !hidIterator) {\r
-      fgWarning( "no joystick (HID) devices found" );\r
-      return;\r
-    }\r
-\r
-    /* iterate */\r
-    while ((ioDev = IOIteratorNext(hidIterator))) {\r
-        /* filter out keyboard and mouse devices */\r
-        CFDictionaryRef properties = getCFProperties(ioDev);\r
-        long usage, page;\r
-\r
-        CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));\r
-        CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));\r
-        CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);\r
-        CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);\r
+        CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));\r
+        CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));\r
+        CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);\r
+        CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);\r
 \r
         /* keep only joystick devices */\r
         if ( ( page == kHIDPage_GenericDesktop ) && (\r
@@ -961,7 +518,7 @@ static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis
         CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),\r
         kCFNumberLongType, &cookie);\r
 \r
-    axisCookies[index] = (IOHIDElementCookie) cookie;\r
+    joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;\r
 \r
     CFNumberGetValue ((CFNumberRef)\r
         CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),\r
@@ -985,7 +542,7 @@ static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef but
             CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),\r
             kCFNumberLongType, &cookie);\r
 \r
-    joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;\r
+    joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;\r
     /* anything else for buttons? */\r
 }\r
 \r
@@ -996,109 +553,48 @@ static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button
 }\r
 #endif\r
 \r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-/* Inspired by\r
-   http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp\r
+/*\r
+ *  Platform-Specific Code\r
  */\r
-#    if FREEGLUT_LIB_PRAGMAS\r
-#        pragma comment (lib, "advapi32.lib")\r
-#    endif\r
 \r
-static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )\r
+#if TARGET_HOST_MACINTOSH\r
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
 {\r
-    char buffer [ 256 ];\r
-\r
-    char OEMKey [ 256 ];\r
-\r
-    HKEY  hKey;\r
-    DWORD dwcb;\r
-    LONG  lr;\r
-\r
-    if ( joy->error )\r
-        return 0;\r
-\r
-    /* Open .. MediaResources\CurrentJoystickSettings */\r
-    _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",\r
-                REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,\r
-                REGSTR_KEY_JOYCURR );\r
-\r
-    lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);\r
-\r
-    if ( lr != ERROR_SUCCESS ) return 0;\r
-\r
-    /* Get OEM Key name */\r
-    dwcb = sizeof(OEMKey);\r
-\r
-    /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */\r
-    _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );\r
-\r
-    lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);\r
-    RegCloseKey ( hKey );\r
-\r
-    if ( lr != ERROR_SUCCESS ) return 0;\r
-\r
-    /* Open OEM Key from ...MediaProperties */\r
-    _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );\r
-\r
-    lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );\r
+    int i;\r
 \r
-    if ( lr != ERROR_SUCCESS ) return 0;\r
+    if ( buttons )\r
+    {\r
+        *buttons = 0;\r
 \r
-    /* Get OEM Name */\r
-    dwcb = buf_sz;\r
+        for ( i = 0; i < joy->num_buttons; i++ )\r
+        {\r
+            UInt32 state;\r
+            int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);\r
+            ISP_CHECK_ERR(err)\r
 \r
-    lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,\r
-                             &dwcb );\r
-    RegCloseKey ( hKey );\r
+            *buttons |= state << i;\r
+        }\r
+    }\r
 \r
-    if ( lr != ERROR_SUCCESS ) return 0;\r
+    if ( axes )\r
+    {\r
+        for ( i = 0; i < joy->num_axes; i++ )\r
+        {\r
+            UInt32 state;\r
+            int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );\r
+            ISP_CHECK_ERR(err)\r
 \r
-    return 1;\r
+            axes [i] = (float) state;\r
+        }\r
+    }\r
 }\r
-#endif\r
 \r
 \r
-static void fghJoystickOpen( SFG_Joystick* joy )\r
+void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
 {\r
-    int i = 0;\r
-#if TARGET_HOST_MACINTOSH\r
+       int i = 0;\r
     OSStatus err;\r
-#endif\r
-#if TARGET_HOST_MAC_OSX\r
-        IOReturn rv;\r
-        SInt32 score;\r
-        IOCFPlugInInterface **plugin;\r
-\r
-        HRESULT pluginResult;\r
-\r
-        CFDictionaryRef props;\r
-    CFTypeRef topLevelElement;\r
-#endif\r
-#if TARGET_HOST_POSIX_X11\r
-#    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
-       char *cp;\r
-#    endif\r
-#    ifdef JS_NEW\r
-       unsigned char u;\r
-#    else\r
-#      if defined( __linux__ ) || TARGET_HOST_SOLARIS\r
-         int counter = 0;\r
-#      endif\r
-#    endif\r
-#endif\r
-\r
-    /* Silence gcc, the correct #ifdefs would be too fragile... */\r
-    (void)i;\r
-\r
-    /*\r
-     * Default values (for no joystick -- each conditional will reset the\r
-     * error flag)\r
-     */\r
-    joy->error = TRUE;\r
-    joy->num_axes = joy->num_buttons = 0;\r
-    joy->name[ 0 ] = '\0';\r
 \r
-#if TARGET_HOST_MACINTOSH\r
     /* XXX FIXME: get joystick name in Mac */\r
 \r
     err = ISpStartup( );\r
@@ -1110,7 +606,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
         joy->error = GL_TRUE;\r
 \r
         /* initialize the needs structure */\r
-        ISpNeed temp_isp_needs[ isp_num_needs ] =\r
+        ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =\r
         {\r
           { "\pX-Axis",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
           { "\pY-Axis",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
@@ -1156,7 +652,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
           { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
         };\r
 \r
-        memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );\r
+        memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );\r
 \r
 \r
         /* next two calls allow keyboard and mouse to emulate other input\r
@@ -1171,17 +667,17 @@ static void fghJoystickOpen( SFG_Joystick* joy )
           ISP_CHECK_ERR(err)\r
         */\r
 \r
-        err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,\r
-                                              joy->isp_needs, joy->isp_elem,\r
+        err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,\r
+                                              joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,\r
                                               0 );\r
         ISP_CHECK_ERR( err )\r
 \r
-        err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,\r
+        err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,\r
                        'freeglut', nil, 0, 128, 0 );\r
         ISP_CHECK_ERR( err )\r
 \r
-        joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;\r
-        joy->num_axes    = joy->isp_num_axis;\r
+        joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;\r
+        joy->num_axes    = ISP_NUM_AXIS;\r
 \r
         for( i = 0; i < joy->num_axes; i++ )\r
         {\r
@@ -1196,42 +692,99 @@ static void fghJoystickOpen( SFG_Joystick* joy )
     }\r
     else\r
         joy->num_buttons = joy->num_axes = 0;\r
+}\r
+\r
+\r
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
+{\r
+    fgJoystick[ ident ]->id = ident;\r
+    snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */\r
+    fgJoystick[ ident ]->error = GL_FALSE;\r
+}\r
+\r
+\r
+void fgPlatformJoystickClose ( int ident )\r
+{\r
+    ISpSuspend( );\r
+    ISpStop( );\r
+    ISpShutdown( );\r
+}\r
 #endif\r
 \r
 #if TARGET_HOST_MAC_OSX\r
-    if( joy->id >= numDevices )\r
-    {\r
-        fgWarning( "device index out of range in fgJoystickOpen()" );\r
-        return;\r
-    }\r
-\r
-    /* create device interface */\r
-    rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],\r
-                                            kIOHIDDeviceUserClientTypeID,\r
-                                            kIOCFPlugInInterfaceID,\r
-                                            &plugin, &score );\r
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
+{\r
+    int i;\r
 \r
-    if( rv != kIOReturnSuccess )\r
+    if ( buttons != NULL )\r
     {\r
-        fgWarning( "error creating plugin for io device" );\r
-        return;\r
-    }\r
+        *buttons = 0;\r
 \r
-    pluginResult = ( *plugin )->QueryInterface(\r
-        plugin,\r
+        for ( i = 0; i < joy->num_buttons; i++ )\r
+        {\r
+            IOHIDEventStruct hidEvent;\r
+            (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );\r
+            if ( hidEvent.value )\r
+                *buttons |= 1 << i;\r
+        }\r
+    }\r
+\r
+    if ( axes != NULL )\r
+    {\r
+        for ( i = 0; i < joy->num_axes; i++ )\r
+        {\r
+            IOHIDEventStruct hidEvent;\r
+            (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );\r
+            axes[i] = hidEvent.value;\r
+        }\r
+    }\r
+}\r
+\r
+\r
+void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
+{\r
+    IOReturn rv;\r
+    SInt32 score;\r
+    IOCFPlugInInterface **plugin;\r
+\r
+    HRESULT pluginResult;\r
+\r
+    CFDictionaryRef props;\r
+    CFTypeRef topLevelElement;\r
+\r
+    if( joy->id >= numDevices )\r
+    {\r
+        fgWarning( "device index out of range in fgJoystickOpen()" );\r
+        return;\r
+    }\r
+\r
+    /* create device interface */\r
+    rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],\r
+                                            kIOHIDDeviceUserClientTypeID,\r
+                                            kIOCFPlugInInterfaceID,\r
+                                            &plugin, &score );\r
+\r
+    if( rv != kIOReturnSuccess )\r
+    {\r
+        fgWarning( "error creating plugin for io device" );\r
+        return;\r
+    }\r
+\r
+    pluginResult = ( *plugin )->QueryInterface(\r
+        plugin,\r
         CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),\r
-        &( LPVOID )joy->hidDev\r
+        &( LPVOID )joy->pJoystick.hidDev\r
     );\r
 \r
     if( pluginResult != S_OK )\r
         fgWarning ( "QI-ing IO plugin to HID Device interface failed" );\r
 \r
     ( *plugin )->Release( plugin ); /* don't leak a ref */\r
-    if( joy->hidDev == NULL )\r
+    if( joy->pJoystick.hidDev == NULL )\r
         return;\r
 \r
     /* store the interface in this instance */\r
-    rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );\r
+    rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );\r
     if( rv != kIOReturnSuccess )\r
     {\r
         fgWarning( "error opening device interface");\r
@@ -1246,92 +799,273 @@ static void fghJoystickOpen( SFG_Joystick* joy )
     enumerateElements( topLevelElement );\r
 \r
     CFRelease( props );\r
+}\r
+\r
+\r
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
+{\r
+    fgJoystick[ ident ]->id = ident;\r
+    fgJoystick[ ident ]->error = GL_FALSE;\r
+    fgJoystick[ ident ]->num_axes = 0;\r
+    fgJoystick[ ident ]->num_buttons = 0;\r
+\r
+    if( numDevices < 0 )\r
+    {\r
+        /* do first-time init (since we can't over-ride jsInit, hmm */\r
+        numDevices = 0;\r
+\r
+        mach_port_t masterPort;\r
+        IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );\r
+        if( rv != kIOReturnSuccess )\r
+        {\r
+            fgWarning( "error getting master Mach port" );\r
+            return;\r
+        }\r
+        fghJoystickFindDevices( masterPort );\r
+    }\r
+\r
+    if ( ident >= numDevices )\r
+    {\r
+        fgJoystick[ ident ]->error = GL_TRUE;\r
+        return;\r
+    }\r
+\r
+    /* get the name now too */\r
+    CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );\r
+    CFTypeRef ref = CFDictionaryGetValue( properties,\r
+                                          CFSTR( kIOHIDProductKey ) );\r
+    if (!ref)\r
+        ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );\r
+\r
+    if( !ref ||\r
+        !CFStringGetCString( ( CFStringRef )ref, name, 128,\r
+                             CFStringGetSystemEncoding( ) ) )\r
+    {\r
+        fgWarning( "error getting device name" );\r
+        name[ 0 ] = '\0';\r
+    }\r
+}\r
+\r
+\r
+void fgPlatformJoystickClose ( int ident )\r
+{\r
+    ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->\r
+        close( fgJoystick[ ident ]->pJoystick.hidDev );\r
+}\r
 #endif\r
 \r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-    joy->js.dwFlags = JOY_RETURNALL;\r
-    joy->js.dwSize  = sizeof( joy->js );\r
+#if TARGET_HOST_POSIX_X11\r
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
+{\r
+    int status;\r
 \r
-    memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );\r
+    int i;\r
 \r
-    joy->error =\r
-        ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=\r
-          JOYERR_NOERROR );\r
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
+    int len;\r
 \r
-    if( joy->jsCaps.wNumAxes == 0 )\r
+    if ( joy->pJoystick.os->is_analog )\r
     {\r
-        joy->num_axes = 0;\r
-        joy->error = GL_TRUE;\r
+        int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) );\r
+        if ( status != sizeof(joy->pJoystick.os->ajs) ) {\r
+            perror ( joy->pJoystick.os->fname );\r
+            joy->error = GL_TRUE;\r
+            return;\r
+        }\r
+        if ( buttons != NULL )\r
+            *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );\r
+\r
+        if ( axes != NULL )\r
+        {\r
+            axes[0] = (float) joy->pJoystick.os->ajs.x;\r
+            axes[1] = (float) joy->pJoystick.os->ajs.y;\r
+        }\r
+\r
+        return;\r
     }\r
-    else\r
+\r
+#  ifdef HAVE_USB_JS\r
+    while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen )\r
     {\r
-        /* Device name from jsCaps is often "Microsoft PC-joystick driver",\r
-         * at least for USB.  Try to get the real name from the registry.\r
-         */\r
-        if ( ! fghJoystickGetOEMProductName( joy, joy->name,\r
-                                             sizeof( joy->name ) ) )\r
+        struct hid_item *h;\r
+\r
+        for  ( h = joy->pJoystick.os->hids; h; h = h->next )\r
         {\r
-            fgWarning( "JS: Failed to read joystick name from registry" );\r
-            strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );\r
+            int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );\r
+\r
+            int page = HID_PAGE ( h->usage );\r
+            int usage = HID_USAGE ( h->usage );\r
+\r
+            if ( page == HUP_GENERIC_DESKTOP )\r
+            {\r
+                int i;\r
+                for ( i = 0; i < joy->num_axes; i++ )\r
+                    if (joy->pJoystick.os->axes_usage[i] == usage)\r
+                    {\r
+                        if (usage == HUG_HAT_SWITCH)\r
+                        {\r
+                            if (d < 0 || d > 8)\r
+                                d = 0;  /* safety */\r
+                            joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d];\r
+                            joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d];\r
+                        }\r
+                        else\r
+                        {\r
+                            joy->pJoystick.os->cache_axes[i] = (float)d;\r
+                        }\r
+                        break;\r
+                    }\r
+            }\r
+            else if (page == HUP_BUTTON)\r
+            {\r
+               if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)\r
+               {\r
+                   if (d)\r
+                       joy->pJoystick.os->cache_buttons |=  (1 << ( usage - 1 ));\r
+                   else\r
+                       joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));\r
+               }\r
+            }\r
         }\r
+    }\r
+#    ifdef HAVE_ERRNO_H\r
+    if ( len < 0 && errno != EAGAIN )\r
+#    else\r
+    if ( len < 0 )\r
+#    endif\r
+    {\r
+        perror( joy->pJoystick.os->fname );\r
+        joy->error = 1;\r
+    }\r
+    if ( buttons != NULL ) *buttons = joy->pJoystick.os->cache_buttons;\r
+    if ( axes    != NULL )\r
+        memcpy ( axes, joy->pJoystick.os->cache_axes, sizeof(float) * joy->num_axes );\r
+#  endif\r
+#endif\r
 \r
-        /* Windows joystick drivers may provide any combination of\r
-         * X,Y,Z,R,U,V,POV - not necessarily the first n of these.\r
-         */\r
-        if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )\r
+#ifdef JS_NEW\r
+\r
+    while ( 1 )\r
+    {\r
+        status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) );\r
+\r
+        if ( status != sizeof( struct js_event ) )\r
         {\r
-            joy->num_axes = _JS_MAX_AXES;\r
-            joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0;  /* POV Y */\r
-            joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0;  /* POV X */\r
+#  ifdef HAVE_ERRNO_H\r
+            if ( errno == EAGAIN )\r
+            {\r
+                /* Use the old values */\r
+                if ( buttons )\r
+                    *buttons = joy->pJoystick.tmp_buttons;\r
+                if ( axes )\r
+                    memcpy( axes, joy->pJoystick.tmp_axes,\r
+                            sizeof( float ) * joy->num_axes );\r
+                return;\r
+            }\r
+#  endif\r
+\r
+            fgWarning ( "%s", joy->pJoystick.fname );\r
+            joy->error = GL_TRUE;\r
+            return;\r
         }\r
-        else\r
-            joy->num_axes = 6;\r
-\r
-        joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;\r
-        joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;\r
-        joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;\r
-        joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;\r
-        joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;\r
-        joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;\r
-        joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;\r
-        joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;\r
-        joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;\r
-        joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;\r
-        joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;\r
-        joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;\r
+\r
+        switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT )\r
+        {\r
+        case JS_EVENT_BUTTON:\r
+            if( joy->pJoystick.js.value == 0 ) /* clear the flag */\r
+                joy->pJoystick.tmp_buttons &= ~( 1 << joy->pJoystick.js.number );\r
+            else\r
+                joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number );\r
+            break;\r
+\r
+        case JS_EVENT_AXIS:\r
+            if ( joy->pJoystick.js.number < joy->num_axes )\r
+            {\r
+                joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value;\r
+\r
+                if( axes )\r
+                    memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );\r
+            }\r
+            break;\r
+\r
+        default:\r
+            fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );\r
+\r
+            /* use the old values */\r
+\r
+            if ( buttons != NULL ) *buttons = joy->pJoystick.tmp_buttons;\r
+            if ( axes    != NULL )\r
+                memcpy ( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );\r
+\r
+            return;\r
+        }\r
+\r
+        if( buttons )\r
+            *buttons = joy->pJoystick.tmp_buttons;\r
     }\r
+#else\r
+\r
+    status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN );\r
 \r
-    /* Guess all the rest judging on the axes extremals */\r
-    for( i = 0; i < joy->num_axes; i++ )\r
+    if ( status != JS_RETURN )\r
     {\r
-        joy->center   [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;\r
-        joy->dead_band[ i ] = 0.0f;\r
-        joy->saturate [ i ] = 1.0f;\r
+        fgWarning( "%s", joy->pJoystick.fname );\r
+        joy->error = GL_TRUE;\r
+        return;\r
+    }\r
+\r
+    if ( buttons )\r
+#    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
+        *buttons = ( joy->pJoystick.js.b1 ? 1 : 0 ) | ( joy->pJoystick.js.b2 ? 2 : 0 );  /* XXX Should not be here -- BSD is handled earlier */\r
+#    else\r
+        *buttons = joy->pJoystick.js.buttons;\r
+#    endif\r
+\r
+    if ( axes )\r
+    {\r
+        axes[ 0 ] = (float) joy->pJoystick.js.x;\r
+        axes[ 1 ] = (float) joy->pJoystick.js.y;\r
     }\r
 #endif\r
+}\r
+\r
+\r
+void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
+{\r
+#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
+       int i = 0;\r
+       char *cp;\r
+#endif\r
+#ifdef JS_NEW\r
+       unsigned char u;\r
+#else\r
+#  if defined( __linux__ ) || TARGET_HOST_SOLARIS\r
+       int i = 0;\r
+    int counter = 0;\r
+#  endif\r
+#endif\r
 \r
-#if TARGET_HOST_POSIX_X11\r
 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
     for( i = 0; i < _JS_MAX_AXES; i++ )\r
-        joy->os->cache_axes[ i ] = 0.0f;\r
+        joy->pJoystick.os->cache_axes[ i ] = 0.0f;\r
 \r
-    joy->os->cache_buttons = 0;\r
+    joy->pJoystick.os->cache_buttons = 0;\r
 \r
-    joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);\r
+    joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK);\r
 \r
 #ifdef HAVE_ERRNO_H\r
-    if( joy->os->fd < 0 && errno == EACCES )\r
-        fgWarning ( "%s exists but is not readable by you", joy->os->fname );\r
+    if( joy->pJoystick.os->fd < 0 && errno == EACCES )\r
+        fgWarning ( "%s exists but is not readable by you", joy->pJoystick.os->fname );\r
 #endif\r
 \r
-    joy->error =( joy->os->fd < 0 );\r
+    joy->error =( joy->pJoystick.os->fd < 0 );\r
 \r
     if( joy->error )\r
         return;\r
 \r
     joy->num_axes = 0;\r
     joy->num_buttons = 0;\r
-    if( joy->os->is_analog )\r
+    if( joy->pJoystick.os->is_analog )\r
     {\r
         FILE *joyfile;\r
         char joyfname[ 1024 ];\r
@@ -1373,15 +1107,15 @@ static void fghJoystickOpen( SFG_Joystick* joy )
     }\r
 \r
 #    ifdef HAVE_USB_JS\r
-    if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,\r
+    if( ! fghJoystickInitializeHID( joy->pJoystick.os, &joy->num_axes,\r
                                     &joy->num_buttons ) )\r
     {\r
-        close( joy->os->fd );\r
+        close( joy->pJoystick.os->fd );\r
         joy->error = GL_TRUE;\r
         return;\r
     }\r
 \r
-    cp = strrchr( joy->os->fname, '/' );\r
+    cp = strrchr( joy->pJoystick.os->fname, '/' );\r
     if( cp )\r
     {\r
         if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==\r
@@ -1398,7 +1132,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
          * to be quite unreliable for analog-to-USB converters. Punt for\r
          * now.\r
          */\r
-        if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )\r
+        if( joy->pJoystick.os->axes_usage[ i ] == HUG_HAT_SWITCH )\r
         {\r
             joy->max   [ i ] = 1.0f;\r
             joy->center[ i ] = 0.0f;\r
@@ -1424,14 +1158,14 @@ static void fghJoystickOpen( SFG_Joystick* joy )
 \r
 #    ifdef JS_NEW\r
     for( i = 0; i < _JS_MAX_AXES; i++ )\r
-        joy->tmp_axes[ i ] = 0.0f;\r
+        joy->pJoystick.tmp_axes[ i ] = 0.0f;\r
 \r
-    joy->tmp_buttons = 0;\r
+    joy->pJoystick.tmp_buttons = 0;\r
 #    endif\r
 \r
-    joy->fd = open( joy->fname, O_RDONLY );\r
+    joy->pJoystick.fd = open( joy->pJoystick.fname, O_RDONLY );\r
 \r
-    joy->error =( joy->fd < 0 );\r
+    joy->error =( joy->pJoystick.fd < 0 );\r
 \r
     if( joy->error )\r
         return;\r
@@ -1442,12 +1176,12 @@ static void fghJoystickOpen( SFG_Joystick* joy )
      *  to the upper byte of an uninitialized word doesn't work.\r
      *  9 April 2003\r
      */\r
-    ioctl( joy->fd, JSIOCGAXES, &u );\r
+    ioctl( joy->pJoystick.fd, JSIOCGAXES, &u );\r
     joy->num_axes = u;\r
-    ioctl( joy->fd, JSIOCGBUTTONS, &u );\r
+    ioctl( joy->pJoystick.fd, JSIOCGBUTTONS, &u );\r
     joy->num_buttons = u;\r
-    ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );\r
-    fcntl( joy->fd, F_SETFL, O_NONBLOCK );\r
+    ioctl( joy->pJoystick.fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );\r
+    fcntl( joy->pJoystick.fd, F_SETFL, O_NONBLOCK );\r
 #    endif\r
 \r
     /*\r
@@ -1488,7 +1222,75 @@ static void fghJoystickOpen( SFG_Joystick* joy )
         joy->saturate [ i ] = 1.0f;\r
     }\r
 #endif\r
+}\r
+\r
+\r
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
+{\r
+#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
+    fgJoystick[ ident ]->id = ident;\r
+    fgJoystick[ ident ]->error = GL_FALSE;\r
+\r
+    fgJoystick[ ident ]->pJoystick.os = calloc( 1, sizeof( struct os_specific_s ) );\r
+    memset( fgJoystick[ ident ]->pJoystick.os, 0, sizeof( struct os_specific_s ) );\r
+    if( ident < USB_IDENT_OFFSET )\r
+        fgJoystick[ ident ]->pJoystick.os->is_analog = 1;\r
+    if( fgJoystick[ ident ]->pJoystick.os->is_analog )\r
+        snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", AJSDEV, ident );\r
+    else\r
+        snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", UHIDDEV,\r
+                 ident - USB_IDENT_OFFSET );\r
+#elif defined( __linux__ )\r
+    fgJoystick[ ident ]->id = ident;\r
+    fgJoystick[ ident ]->error = GL_FALSE;\r
+\r
+    snprintf( fgJoystick[ident]->pJoystick.fname, sizeof(fgJoystick[ident]->pJoystick.fname), "/dev/input/js%d", ident );\r
+\r
+    if( access( fgJoystick[ ident ]->pJoystick.fname, F_OK ) != 0 )\r
+        snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident );\r
+#endif\r
+}\r
+\r
+\r
+void fgPlatformJoystickClose ( int ident )\r
+{\r
+#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
+    if( fgJoystick[ident]->pJoystick.os )\r
+    {\r
+        if( ! fgJoystick[ ident ]->error )\r
+            close( fgJoystick[ ident ]->pJoystick.os->fd );\r
+#ifdef HAVE_USB_JS\r
+        if( fgJoystick[ ident ]->pJoystick.os->hids )\r
+            free (fgJoystick[ ident ]->pJoystick.os->hids);\r
+        if( fgJoystick[ ident ]->pJoystick.os->hid_data_buf )\r
+            free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf );\r
+#endif\r
+        free( fgJoystick[ident]->pJoystick.os );\r
+       }\r
 #endif\r
+\r
+    if( ! fgJoystick[ident]->error )\r
+         close( fgJoystick[ ident ]->pJoystick.fd );\r
+}\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+static void fghJoystickOpen( SFG_Joystick* joy )\r
+{\r
+    /*\r
+     * Default values (for no joystick -- each conditional will reset the\r
+     * error flag)\r
+     */\r
+    joy->error = TRUE;\r
+    joy->num_axes = joy->num_buttons = 0;\r
+    joy->name[ 0 ] = '\0';\r
+\r
+       fgPlatformJoystickOpen ( joy );\r
+\r
 }\r
 \r
 /*\r
@@ -1509,97 +1311,7 @@ static void fghJoystickInit( int ident )
     fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;\r
     fgJoystick[ ident ]->error = GL_TRUE;\r
 \r
-#if TARGET_HOST_MACINTOSH\r
-    fgJoystick[ ident ]->id = ident;\r
-    snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */\r
-    fgJoystick[ ident ]->error = GL_FALSE;\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-    fgJoystick[ ident ]->id = ident;\r
-    fgJoystick[ ident ]->error = GL_FALSE;\r
-    fgJoystick[ ident ]->num_axes = 0;\r
-    fgJoystick[ ident ]->num_buttons = 0;\r
-\r
-    if( numDevices < 0 )\r
-    {\r
-        /* do first-time init (since we can't over-ride jsInit, hmm */\r
-        numDevices = 0;\r
-\r
-        mach_port_t masterPort;\r
-        IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );\r
-        if( rv != kIOReturnSuccess )\r
-        {\r
-            fgWarning( "error getting master Mach port" );\r
-            return;\r
-        }\r
-        fghJoystickFindDevices( masterPort );\r
-    }\r
-\r
-    if ( ident >= numDevices )\r
-    {\r
-        fgJoystick[ ident ]->error = GL_TRUE;\r
-        return;\r
-    }\r
-\r
-    /* get the name now too */\r
-    CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );\r
-    CFTypeRef ref = CFDictionaryGetValue( properties,\r
-                                          CFSTR( kIOHIDProductKey ) );\r
-    if (!ref)\r
-        ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );\r
-\r
-    if( !ref ||\r
-        !CFStringGetCString( ( CFStringRef )ref, name, 128,\r
-                             CFStringGetSystemEncoding( ) ) )\r
-    {\r
-        fgWarning( "error getting device name" );\r
-        name[ 0 ] = '\0';\r
-    }\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-    switch( ident )\r
-    {\r
-    case 0:\r
-        fgJoystick[ ident ]->js_id = JOYSTICKID1;\r
-        fgJoystick[ ident ]->error = GL_FALSE;\r
-        break;\r
-    case 1:\r
-        fgJoystick[ ident ]->js_id = JOYSTICKID2;\r
-        fgJoystick[ ident ]->error = GL_FALSE;\r
-        break;\r
-    default:\r
-        fgJoystick[ ident ]->num_axes = 0;\r
-        fgJoystick[ ident ]->error = GL_TRUE;\r
-        return;\r
-    }\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-#    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
-    fgJoystick[ ident ]->id = ident;\r
-    fgJoystick[ ident ]->error = GL_FALSE;\r
-\r
-    fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );\r
-    memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );\r
-    if( ident < USB_IDENT_OFFSET )\r
-        fgJoystick[ ident ]->os->is_analog = 1;\r
-    if( fgJoystick[ ident ]->os->is_analog )\r
-        snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );\r
-    else\r
-        snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,\r
-                 ident - USB_IDENT_OFFSET );\r
-#    elif defined( __linux__ )\r
-    fgJoystick[ ident ]->id = ident;\r
-    fgJoystick[ ident ]->error = GL_FALSE;\r
-\r
-    snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );\r
-\r
-    if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )\r
-        snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );\r
-#    endif\r
-#endif\r
+       fgPlatformJoystickInit( fgJoystick, ident );\r
 \r
     fghJoystickOpen( fgJoystick[ ident  ] );\r
 }\r
@@ -1619,50 +1331,6 @@ void fgInitialiseJoysticks ( void )
     }\r
 }\r
 \r
-/*\r
- *\r
- */\r
-\r
-#if TARGET_HOST_MACINTOSH\r
-void fgPlatformJoystickClose ( int ident )\r
-{\r
-    ISpSuspend( );\r
-    ISpStop( );\r
-    ISpShutdown( );\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-void fgPlatformJoystickClose ( int ident )\r
-{\r
-    ( *( fgJoystick[ ident ]->hidDev ) )->\r
-        close( fgJoystick[ ident ]->hidDev );\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-void fgPlatformJoystickClose ( int ident )\r
-{\r
-#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
-    if( fgJoystick[ident]->os )\r
-    {\r
-        if( ! fgJoystick[ ident ]->error )\r
-            close( fgJoystick[ ident ]->os->fd );\r
-#ifdef HAVE_USB_JS\r
-        if( fgJoystick[ ident ]->os->hids )\r
-            free (fgJoystick[ ident ]->os->hids);\r
-        if( fgJoystick[ ident ]->os->hid_data_buf )\r
-            free( fgJoystick[ ident ]->os->hid_data_buf );\r
-#endif\r
-        free( fgJoystick[ident]->os );\r
-       }\r
-#endif\r
-\r
-    if( ! fgJoystick[ident]->error )\r
-         close( fgJoystick[ ident ]->fd );\r
-}\r
-#endif\r
-\r
 \r
 void fgJoystickClose( void )\r
 {\r