Setting the line endings and keywords on a bunch of new text files
[freeglut] / src / Common / freeglut_joystick.c
index c2190da..f6edc26 100644 (file)
-/*\r
- * freeglut_joystick.c\r
- *\r
- * Joystick handling code\r
- *\r
- * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
- * Written by Steve Baker, <sjbaker1@airmail.net>\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a\r
- * copy of this software and associated documentation files (the "Software"),\r
- * to deal in the Software without restriction, including without limitation\r
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
- * and/or sell copies of the Software, and to permit persons to whom the\r
- * Software is furnished to do so, subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included\r
- * in all copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
- * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- */\r
-\r
-/*\r
- * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>\r
- *\r
- * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.\r
- *  Many thanks for Steve Baker for permission to pull from that library.\r
- */\r
-\r
-#include <GL/freeglut.h>\r
-#include "freeglut_internal.h"\r
-#ifdef HAVE_SYS_PARAM_H\r
-#    include <sys/param.h>\r
-#endif\r
-\r
-#define JS_TRUE  1\r
-#define JS_FALSE 0\r
-\r
-/* BSD defines from "jsBSD.cxx" around lines 42-270 */\r
-\r
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\r
-\r
-#    ifdef HAVE_USB_JS\r
-#        if defined(__NetBSD__)\r
-/* XXX The below hack is done until freeglut's autoconf is updated. */\r
-#            define HAVE_USBHID_H 1\r
-#            ifdef HAVE_USBHID_H\r
-#                include <usbhid.h>\r
-#            else\r
-#                include <usb.h>\r
-#            endif\r
-#        elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\r
-#            ifdef HAVE_USBHID_H\r
-#                include <usbhid.h>\r
-#            else\r
-#                include <libusbhid.h>\r
-#            endif\r
-#        endif\r
-#        include <legacy/dev/usb/usb.h>\r
-#        include <dev/usb/usbhid.h>\r
-\r
-/* Compatibility with older usb.h revisions */\r
-#        if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)\r
-#            define USB_MAX_DEVNAMES MAXDEVNAMES\r
-#        endif\r
-#    endif\r
-\r
-static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };\r
-static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };\r
-struct os_specific_s {\r
-  char             fname [128 ];\r
-  int              fd;\r
-  int              is_analog;\r
-  /* The following structure members are specific to analog joysticks */\r
-  struct joystick  ajs;\r
-#    ifdef HAVE_USB_JS\r
-  /* The following structure members are specific to USB joysticks */\r
-  struct hid_item *hids;\r
-  int              hid_dlen;\r
-  int              hid_offset;\r
-  char            *hid_data_buf;\r
-  int              axes_usage [ _JS_MAX_AXES ];\r
-#    endif\r
-  /* We keep button and axes state ourselves, as they might not be updated\r
-   * on every read of a USB device\r
-   */\r
-  int              cache_buttons;\r
-  float            cache_axes [ _JS_MAX_AXES ];\r
-};\r
-\r
-/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */\r
-#    define USB_IDENT_OFFSET    2\r
-\r
-#    define USBDEV "/dev/usb"\r
-#    define UHIDDEV "/dev/uhid"\r
-#    define AJSDEV "/dev/joy"\r
-\r
-#    ifdef HAVE_USB_JS\r
-/*\r
- * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate\r
- * the full name of a USB device. If /dev/usbN isn't readable, we punt and\r
- * return the uhidN device name. We warn the user of this situation once.\r
- */\r
-static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)\r
-{\r
-  struct usb_device_info di;\r
-  int i, a;\r
-  char *cp;\r
-\r
-  for (a = 1; a < USB_MAX_DEVICES; a++) {\r
-    di.udi_addr = a;\r
-    if (ioctl(f, USB_DEVICEINFO, &di) != 0)\r
-      return NULL;\r
-    for (i = 0; i < USB_MAX_DEVNAMES; i++)\r
-      if (di.udi_devnames[i][0] &&\r
-          strcmp(di.udi_devnames[i], dev) == 0) {\r
-        cp =  calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);\r
-        strcpy(cp, di.udi_vendor);\r
-        strcat(cp, " ");\r
-        strcat(cp, di.udi_product);\r
-        strncpy(out, cp, outlen - 1);\r
-        out[outlen - 1] = 0;\r
-        free( cp );\r
-        return out;\r
-      }\r
-  }\r
-  return NULL;\r
-}\r
-\r
-static int fghJoystickFindUSBdev(char *name, char *out, int outlen)\r
-{\r
-  int i, f;\r
-  char buf[50];\r
-  char *cp;\r
-  static int protection_warned = 0;\r
-\r
-  for (i = 0; i < 16; i++) {\r
-    snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);\r
-    f = open(buf, O_RDONLY);\r
-    if (f >= 0) {\r
-      cp = fghJoystickWalkUSBdev(f, name, out, outlen);\r
-      close(f);\r
-      if (cp)\r
-        return 1;\r
-    }\r
-#ifdef HAVE_ERRNO_H\r
-    else if (errno == EACCES) {\r
-      if (!protection_warned) {\r
-        fgWarning ( "Can't open %s for read!", buf );\r
-        protection_warned = 1;\r
-      }\r
-    }\r
-#endif\r
-  }\r
-  return 0;\r
-}\r
-\r
-static int fghJoystickInitializeHID(struct os_specific_s *os,\r
-       int *num_axes, int *num_buttons)\r
-{\r
-    int size, is_joystick;\r
-#   ifdef HAVE_USBHID_H\r
-        int report_id = 0;\r
-#   endif\r
-    struct hid_data *d;\r
-    struct hid_item h;\r
-    report_desc_t rd;\r
-\r
-    if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )\r
-    {\r
-#ifdef HAVE_ERRNO_H\r
-        fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );\r
-#else\r
-        fgWarning ( "error: %s", os->fname );\r
-#endif\r
-        return FALSE;\r
-    }\r
-\r
-    os->hids = NULL;\r
-\r
-#   ifdef HAVE_USBHID_H\r
-        if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)\r
-        {\r
-            /*** XXX {report_id} may not be the right variable? ***/\r
-#ifdef HAVE_ERRNO_H\r
-            fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );\r
-#else\r
-            fgWarning ( "error: %s%d", UHIDDEV, report_id );\r
-#endif\r
-            return FALSE;\r
-        }\r
-\r
-        size = hid_report_size( rd, hid_input, report_id );\r
-#   else\r
-        size = hid_report_size( rd, 0, hid_input );\r
-#   endif\r
-    os->hid_data_buf = calloc( 1, size );\r
-    os->hid_dlen = size;\r
-\r
-    is_joystick = 0;\r
-#   ifdef HAVE_USBHID_H\r
-        d = hid_start_parse( rd, 1 << hid_input, report_id );\r
-#   else\r
-        d = hid_start_parse( rd, 1 << hid_input );\r
-#   endif\r
-        while( hid_get_item( d, &h ) )\r
-        {\r
-            int usage, page, interesting_hid;\r
-\r
-            page = HID_PAGE( h.usage );\r
-            usage = HID_USAGE( h.usage );\r
-\r
-            /* This test is somewhat too simplistic, but this is how MicroSoft\r
-             * does, so I guess it works for all joysticks/game pads. */\r
-            is_joystick = is_joystick ||\r
-                ( h.kind == hid_collection &&\r
-                  page == HUP_GENERIC_DESKTOP &&\r
-                  ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );\r
-\r
-            if( h.kind != hid_input )\r
-                continue;\r
-\r
-            if( !is_joystick )\r
-                continue;\r
-\r
-            interesting_hid = TRUE;\r
-            if( page == HUP_GENERIC_DESKTOP )\r
-            {\r
-                switch( usage )\r
-                {\r
-                case HUG_X:\r
-                case HUG_RX:\r
-                case HUG_Y:\r
-                case HUG_RY:\r
-                case HUG_Z:\r
-                case HUG_RZ:\r
-                case HUG_SLIDER:\r
-                    if( *num_axes < _JS_MAX_AXES )\r
-                    {\r
-                        os->axes_usage[ *num_axes ] = usage;\r
-                        ( *num_axes )++;\r
-                    }\r
-                    break;\r
-                case HUG_HAT_SWITCH:\r
-                    /* Allocate two axes for a hat */\r
-                    if( *num_axes + 1 < _JS_MAX_AXES )\r
-                    {\r
-                        os->axes_usage[ *num_axes ] = usage;\r
-                        (*num_axes)++;\r
-                        os->axes_usage[ *num_axes ] = usage;\r
-                        (*num_axes)++;\r
-                    }\r
-                    break;\r
-                default:\r
-                    interesting_hid = FALSE;\r
-                    break;\r
-                }\r
-            }\r
-            else if( page == HUP_BUTTON )\r
-            {\r
-                interesting_hid = ( usage > 0 ) &&\r
-                    ( usage <= _JS_MAX_BUTTONS );\r
-\r
-                if( interesting_hid && usage - 1 > *num_buttons )\r
-                    *num_buttons = usage - 1;\r
-            }\r
-\r
-            if( interesting_hid )\r
-            {\r
-                h.next = os->hids;\r
-                os->hids = calloc( 1, sizeof ( struct hid_item ) );\r
-                *os->hids = h;\r
-            }\r
-        }\r
-        hid_end_parse( d );\r
-\r
-        return os->hids != NULL;\r
-}\r
-#    endif\r
-#endif\r
-\r
-/*\r
- * Functions associated with the "jsJoystick" class in PLIB\r
- */\r
-#if TARGET_HOST_MAC_OSX\r
-#define K_NUM_DEVICES   32\r
-int numDevices;\r
-io_object_t ioDevices[K_NUM_DEVICES];\r
-\r
-static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );\r
-static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );\r
-\r
-static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );\r
-/* callback for CFArrayApply */\r
-static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );\r
-\r
-static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );\r
-static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );\r
-static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );\r
-#endif\r
-\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
- * The static joystick structure pointer\r
- */\r
-#define MAX_NUM_JOYSTICKS  2\r
-SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];\r
-\r
-/*\r
- * Read the raw joystick data\r
- */\r
-static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
-{\r
-    int i;\r
-\r
-    /* Defaults */\r
-    if( buttons )\r
-        *buttons = 0;\r
-\r
-    if( axes )\r
-        for( i = 0; i < joy->num_axes; i++ )\r
-            axes[ i ] = 1500.0f;\r
-\r
-    if( joy->error )\r
-        return;\r
-\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
-        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
-\r
-        /* keep only joystick devices */\r
-        if ( ( page == kHIDPage_GenericDesktop ) && (\r
-                            (usage == kHIDUsage_GD_Joystick)\r
-                         || (usage == kHIDUsage_GD_GamePad)\r
-                         || (usage == kHIDUsage_GD_MultiAxisController)\r
-                         || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */\r
-            /* add it to the array */\r
-            ioDevices[numDevices++] = ioDev;\r
-    }\r
-\r
-    IOObjectRelease(hidIterator);\r
-}\r
-\r
-static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )\r
-{\r
-    IOReturn rv;\r
-    CFMutableDictionaryRef cfProperties;\r
-\r
-#if 0\r
-    /* comment copied from darwin/SDL_sysjoystick.c */\r
-    /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also\r
-     * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties\r
-     */\r
-\r
-    io_registry_entry_t parent1, parent2;\r
-\r
-    rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);\r
-    if (rv != kIOReturnSuccess) {\r
-        fgWarning ( "error getting device entry parent");\r
-        return NULL;\r
-    }\r
-\r
-    rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);\r
-    if (rv != kIOReturnSuccess) {\r
-        fgWarning ( "error getting device entry parent 2");\r
-        return NULL;\r
-    }\r
-#endif\r
-\r
-    rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,\r
-        &cfProperties, kCFAllocatorDefault, kNilOptions);\r
-    if (rv != kIOReturnSuccess || !cfProperties) {\r
-        fgWarning ( "error getting device properties");\r
-        return NULL;\r
-    }\r
-\r
-    return cfProperties;\r
-}\r
-\r
-static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )\r
-{\r
-      if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {\r
-            fgError ( "%s", "element enumerator passed non-dictionary value");\r
-            return;\r
-    }\r
-\r
-      static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );\r
-}\r
-\r
-/** element enumerator function : pass NULL for top-level*/\r
-static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )\r
-{\r
-      FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),\r
-                                    "Joystick element type mismatch",\r
-                                    "fghJoystickEnumerateElements" );\r
-\r
-      CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};\r
-      CFArrayApplyFunction((CFArrayRef) element, range,\r
-            &fghJoystickElementEnumerator, joy );\r
-}\r
-\r
-static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )\r
-{\r
-    long cookie, lmin, lmax;\r
-    int index = joy->num_axes++;\r
-\r
-    CFNumberGetValue ((CFNumberRef)\r
-        CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),\r
-        kCFNumberLongType, &cookie);\r
-\r
-    joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;\r
-\r
-    CFNumberGetValue ((CFNumberRef)\r
-        CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),\r
-        kCFNumberLongType, &lmin);\r
-\r
-    CFNumberGetValue ((CFNumberRef)\r
-        CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),\r
-        kCFNumberLongType, &lmax);\r
-\r
-    joy->min[index] = lmin;\r
-    joy->max[index] = lmax;\r
-    joy->dead_band[index] = 0.0;\r
-    joy->saturate[index] = 1.0;\r
-    joy->center[index] = (lmax + lmin) * 0.5;\r
-}\r
-\r
-static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )\r
-{\r
-    long cookie;\r
-    CFNumberGetValue ((CFNumberRef)\r
-            CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),\r
-            kCFNumberLongType, &cookie);\r
-\r
-    joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;\r
-    /* anything else for buttons? */\r
-}\r
-\r
-static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )\r
-{\r
-    /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */\r
-    /* do we map hats to axes or buttons? */\r
-}\r
-#endif\r
-\r
-/*\r
- *  Platform-Specific Code\r
- */\r
-\r
-#if TARGET_HOST_MACINTOSH\r
-void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
-{\r
-    int i;\r
-\r
-    if ( buttons )\r
-    {\r
-        *buttons = 0;\r
-\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
-            *buttons |= state << i;\r
-        }\r
-    }\r
-\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
-            axes [i] = (float) state;\r
-        }\r
-    }\r
-}\r
-\r
-\r
-void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
-{\r
-       int i = 0;\r
-    OSStatus err;\r
-\r
-    /* XXX FIXME: get joystick name in Mac */\r
-\r
-    err = ISpStartup( );\r
-\r
-    if( err == noErr )\r
-    {\r
-#define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }\r
-\r
-        joy->error = GL_TRUE;\r
-\r
-        /* initialize the needs structure */\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
-          { "\pZ-Axis",    128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-          { "\pR-Axis",    128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-          { "\pAxis   4",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-          { "\pAxis   5",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-          { "\pAxis   6",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-          { "\pAxis   7",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-          { "\pAxis   8",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },\r
-\r
-          { "\pButton 0",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 1",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 2",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 3",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 4",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 5",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 6",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 7",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 8",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 9",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-          { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
-        };\r
-\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
-         * devices (gamepads, joysticks, etc)\r
-         */\r
-        /*\r
-          err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );\r
-          ISP_CHECK_ERR(err)\r
-\r
-\r
-          err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );\r
-          ISP_CHECK_ERR(err)\r
-        */\r
-\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( 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 = 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
-            joy->dead_band[ i ] = 0;\r
-            joy->saturate [ i ] = 1;\r
-            joy->center   [ i ] = kISpAxisMiddle;\r
-            joy->max      [ i ] = kISpAxisMaximum;\r
-            joy->min      [ i ] = kISpAxisMinimum;\r
-        }\r
-\r
-        joy->error = GL_FALSE;\r
-    }\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
-void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
-{\r
-    int i;\r
-\r
-    if ( buttons != NULL )\r
-    {\r
-        *buttons = 0;\r
-\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->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->pJoystick.hidDev == NULL )\r
-        return;\r
-\r
-    /* store the interface in this instance */\r
-    rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );\r
-    if( rv != kIOReturnSuccess )\r
-    {\r
-        fgWarning( "error opening device interface");\r
-        return;\r
-    }\r
-\r
-    props = getCFProperties( ioDevices[ joy->id ] );\r
-\r
-    /* recursively enumerate all the bits */\r
-    CFTypeRef topLevelElement =\r
-        CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );\r
-    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
-\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
- * This function replaces the constructor method in the JS library.\r
- */\r
-static void fghJoystickInit( int ident )\r
-{\r
-    if( ident >= MAX_NUM_JOYSTICKS )\r
-      fgError( "Too large a joystick number: %d", ident );\r
-\r
-    if( fgJoystick[ ident ] )\r
-        fgError( "illegal attempt to initialize joystick device again" );\r
-\r
-    fgJoystick[ ident ] =\r
-        ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );\r
-\r
-    /* Set defaults */\r
-    fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;\r
-    fgJoystick[ ident ]->error = GL_TRUE;\r
-\r
-       fgPlatformJoystickInit( fgJoystick, ident );\r
-\r
-    fghJoystickOpen( fgJoystick[ ident  ] );\r
-}\r
-\r
-/*\r
- * Try initializing all the joysticks (well, both of them)\r
- */\r
-void fgInitialiseJoysticks ( void )\r
-{\r
-    if( !fgState.JoysticksInitialised )\r
-    {\r
-        int ident ;\r
-        for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )\r
-            fghJoystickInit( ident );\r
-\r
-        fgState.JoysticksInitialised = GL_TRUE;\r
-    }\r
-}\r
-\r
-\r
-void fgJoystickClose( void )\r
-{\r
-    int ident ;\r
-    for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )\r
-    {\r
-        if( fgJoystick[ ident ] )\r
-        {\r
-                       fgPlatformJoystickClose ( ident );\r
-\r
-            free( fgJoystick[ ident ] );\r
-            fgJoystick[ ident ] = NULL;\r
-            /* show joystick has been deinitialized */\r
-        }\r
-    }\r
-}\r
-\r
-/*\r
- * Polls the joystick and executes the joystick callback hooked to the\r
- * window specified in the function's parameter:\r
- */\r
-void fgJoystickPollWindow( SFG_Window* window )\r
-{\r
-    float axes[ _JS_MAX_AXES ];\r
-    int buttons;\r
-    int ident;\r
-\r
-    freeglut_return_if_fail( window );\r
-    freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );\r
-\r
-    for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )\r
-    {\r
-        if( fgJoystick[ident] )\r
-        {\r
-            fghJoystickRead( fgJoystick[ident], &buttons, axes );\r
-\r
-            if( !fgJoystick[ident]->error )\r
-                INVOKE_WCB( *window, Joystick,\r
-                            ( buttons,\r
-                              (int) ( axes[ 0 ] * 1000.0f ),\r
-                              (int) ( axes[ 1 ] * 1000.0f ),\r
-                              (int) ( axes[ 2 ] * 1000.0f ) )\r
-                );\r
-        }\r
-    }\r
-}\r
-\r
-/*\r
- * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)\r
- */\r
-int fgJoystickDetect( void )\r
-{\r
-    int ident;\r
-\r
-    fgInitialiseJoysticks ();\r
-\r
-    if ( !fgState.JoysticksInitialised )\r
-        return 0;\r
-\r
-    for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )\r
-        if( fgJoystick[ident] && !fgJoystick[ident]->error )\r
-            return 1;\r
-\r
-    return 0;\r
-}\r
-\r
-/*\r
- * Joystick information functions\r
- */\r
-int  glutJoystickGetNumAxes( int ident )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );\r
-    return fgJoystick[ ident ]->num_axes;\r
-}\r
-int  glutJoystickGetNumButtons( int ident )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );\r
-    return fgJoystick[ ident ]->num_buttons;\r
-}\r
-int  glutJoystickNotWorking( int ident )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );\r
-    return fgJoystick[ ident ]->error;\r
-}\r
-\r
-float glutJoystickGetDeadBand( int ident, int axis )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );\r
-    return fgJoystick[ ident ]->dead_band [ axis ];\r
-}\r
-void  glutJoystickSetDeadBand( int ident, int axis, float db )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );\r
-    fgJoystick[ ident ]->dead_band[ axis ] = db;\r
-}\r
-\r
-float glutJoystickGetSaturation( int ident, int axis )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );\r
-    return fgJoystick[ ident ]->saturate[ axis ];\r
-}\r
-void  glutJoystickSetSaturation( int ident, int axis, float st )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );\r
-    fgJoystick[ ident ]->saturate [ axis ] = st;\r
-}\r
-\r
-void glutJoystickSetMinRange( int ident, float *axes )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );\r
-    memcpy( fgJoystick[ ident ]->min, axes,\r
-            fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickSetMaxRange( int ident, float *axes )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );\r
-    memcpy( fgJoystick[ ident ]->max, axes,\r
-            fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickSetCenter( int ident, float *axes )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );\r
-    memcpy( fgJoystick[ ident ]->center, axes,\r
-            fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-\r
-void glutJoystickGetMinRange( int ident, float *axes )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );\r
-    memcpy( axes, fgJoystick[ ident ]->min,\r
-            fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickGetMaxRange( int ident, float *axes )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );\r
-    memcpy( axes, fgJoystick[ ident ]->max,\r
-            fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickGetCenter( int ident, float *axes )\r
-{\r
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );\r
-    memcpy( axes, fgJoystick[ ident ]->center,\r
-            fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-\r
-/*** END OF FILE ***/\r
+/*
+ * freeglut_joystick.c
+ *
+ * Joystick handling code
+ *
+ * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
+ * Written by Steve Baker, <sjbaker1@airmail.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
+ *
+ * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
+ *  Many thanks for Steve Baker for permission to pull from that library.
+ */
+
+#include <GL/freeglut.h>
+#include "freeglut_internal.h"
+#ifdef HAVE_SYS_PARAM_H
+#    include <sys/param.h>
+#endif
+
+#define JS_TRUE  1
+#define JS_FALSE 0
+
+/* BSD defines from "jsBSD.cxx" around lines 42-270 */
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+#    ifdef HAVE_USB_JS
+#        if defined(__NetBSD__)
+/* XXX The below hack is done until freeglut's autoconf is updated. */
+#            define HAVE_USBHID_H 1
+#            ifdef HAVE_USBHID_H
+#                include <usbhid.h>
+#            else
+#                include <usb.h>
+#            endif
+#        elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#            ifdef HAVE_USBHID_H
+#                include <usbhid.h>
+#            else
+#                include <libusbhid.h>
+#            endif
+#        endif
+#        include <legacy/dev/usb/usb.h>
+#        include <dev/usb/usbhid.h>
+
+/* Compatibility with older usb.h revisions */
+#        if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
+#            define USB_MAX_DEVNAMES MAXDEVNAMES
+#        endif
+#    endif
+
+static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
+static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
+struct os_specific_s {
+  char             fname [128 ];
+  int              fd;
+  int              is_analog;
+  /* The following structure members are specific to analog joysticks */
+  struct joystick  ajs;
+#    ifdef HAVE_USB_JS
+  /* The following structure members are specific to USB joysticks */
+  struct hid_item *hids;
+  int              hid_dlen;
+  int              hid_offset;
+  char            *hid_data_buf;
+  int              axes_usage [ _JS_MAX_AXES ];
+#    endif
+  /* We keep button and axes state ourselves, as they might not be updated
+   * on every read of a USB device
+   */
+  int              cache_buttons;
+  float            cache_axes [ _JS_MAX_AXES ];
+};
+
+/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
+#    define USB_IDENT_OFFSET    2
+
+#    define USBDEV "/dev/usb"
+#    define UHIDDEV "/dev/uhid"
+#    define AJSDEV "/dev/joy"
+
+#    ifdef HAVE_USB_JS
+/*
+ * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
+ * the full name of a USB device. If /dev/usbN isn't readable, we punt and
+ * return the uhidN device name. We warn the user of this situation once.
+ */
+static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
+{
+  struct usb_device_info di;
+  int i, a;
+  char *cp;
+
+  for (a = 1; a < USB_MAX_DEVICES; a++) {
+    di.udi_addr = a;
+    if (ioctl(f, USB_DEVICEINFO, &di) != 0)
+      return NULL;
+    for (i = 0; i < USB_MAX_DEVNAMES; i++)
+      if (di.udi_devnames[i][0] &&
+          strcmp(di.udi_devnames[i], dev) == 0) {
+        cp =  calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
+        strcpy(cp, di.udi_vendor);
+        strcat(cp, " ");
+        strcat(cp, di.udi_product);
+        strncpy(out, cp, outlen - 1);
+        out[outlen - 1] = 0;
+        free( cp );
+        return out;
+      }
+  }
+  return NULL;
+}
+
+static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
+{
+  int i, f;
+  char buf[50];
+  char *cp;
+  static int protection_warned = 0;
+
+  for (i = 0; i < 16; i++) {
+    snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
+    f = open(buf, O_RDONLY);
+    if (f >= 0) {
+      cp = fghJoystickWalkUSBdev(f, name, out, outlen);
+      close(f);
+      if (cp)
+        return 1;
+    }
+#ifdef HAVE_ERRNO_H
+    else if (errno == EACCES) {
+      if (!protection_warned) {
+        fgWarning ( "Can't open %s for read!", buf );
+        protection_warned = 1;
+      }
+    }
+#endif
+  }
+  return 0;
+}
+
+static int fghJoystickInitializeHID(struct os_specific_s *os,
+       int *num_axes, int *num_buttons)
+{
+    int size, is_joystick;
+#   ifdef HAVE_USBHID_H
+        int report_id = 0;
+#   endif
+    struct hid_data *d;
+    struct hid_item h;
+    report_desc_t rd;
+
+    if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
+    {
+#ifdef HAVE_ERRNO_H
+        fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
+#else
+        fgWarning ( "error: %s", os->fname );
+#endif
+        return FALSE;
+    }
+
+    os->hids = NULL;
+
+#   ifdef HAVE_USBHID_H
+        if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
+        {
+            /*** XXX {report_id} may not be the right variable? ***/
+#ifdef HAVE_ERRNO_H
+            fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
+#else
+            fgWarning ( "error: %s%d", UHIDDEV, report_id );
+#endif
+            return FALSE;
+        }
+
+        size = hid_report_size( rd, hid_input, report_id );
+#   else
+        size = hid_report_size( rd, 0, hid_input );
+#   endif
+    os->hid_data_buf = calloc( 1, size );
+    os->hid_dlen = size;
+
+    is_joystick = 0;
+#   ifdef HAVE_USBHID_H
+        d = hid_start_parse( rd, 1 << hid_input, report_id );
+#   else
+        d = hid_start_parse( rd, 1 << hid_input );
+#   endif
+        while( hid_get_item( d, &h ) )
+        {
+            int usage, page, interesting_hid;
+
+            page = HID_PAGE( h.usage );
+            usage = HID_USAGE( h.usage );
+
+            /* This test is somewhat too simplistic, but this is how MicroSoft
+             * does, so I guess it works for all joysticks/game pads. */
+            is_joystick = is_joystick ||
+                ( h.kind == hid_collection &&
+                  page == HUP_GENERIC_DESKTOP &&
+                  ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
+
+            if( h.kind != hid_input )
+                continue;
+
+            if( !is_joystick )
+                continue;
+
+            interesting_hid = TRUE;
+            if( page == HUP_GENERIC_DESKTOP )
+            {
+                switch( usage )
+                {
+                case HUG_X:
+                case HUG_RX:
+                case HUG_Y:
+                case HUG_RY:
+                case HUG_Z:
+                case HUG_RZ:
+                case HUG_SLIDER:
+                    if( *num_axes < _JS_MAX_AXES )
+                    {
+                        os->axes_usage[ *num_axes ] = usage;
+                        ( *num_axes )++;
+                    }
+                    break;
+                case HUG_HAT_SWITCH:
+                    /* Allocate two axes for a hat */
+                    if( *num_axes + 1 < _JS_MAX_AXES )
+                    {
+                        os->axes_usage[ *num_axes ] = usage;
+                        (*num_axes)++;
+                        os->axes_usage[ *num_axes ] = usage;
+                        (*num_axes)++;
+                    }
+                    break;
+                default:
+                    interesting_hid = FALSE;
+                    break;
+                }
+            }
+            else if( page == HUP_BUTTON )
+            {
+                interesting_hid = ( usage > 0 ) &&
+                    ( usage <= _JS_MAX_BUTTONS );
+
+                if( interesting_hid && usage - 1 > *num_buttons )
+                    *num_buttons = usage - 1;
+            }
+
+            if( interesting_hid )
+            {
+                h.next = os->hids;
+                os->hids = calloc( 1, sizeof ( struct hid_item ) );
+                *os->hids = h;
+            }
+        }
+        hid_end_parse( d );
+
+        return os->hids != NULL;
+}
+#    endif
+#endif
+
+/*
+ * Functions associated with the "jsJoystick" class in PLIB
+ */
+#if TARGET_HOST_MAC_OSX
+#define K_NUM_DEVICES   32
+int numDevices;
+io_object_t ioDevices[K_NUM_DEVICES];
+
+static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
+static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
+
+static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
+/* callback for CFArrayApply */
+static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
+
+static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
+static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
+static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
+#endif
+
+
+/* External function declarations (mostly platform-specific) */
+extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
+extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
+extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
+extern void fgPlatformJoystickClose ( int ident );
+
+/*
+ * The static joystick structure pointer
+ */
+#define MAX_NUM_JOYSTICKS  2
+SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
+
+/*
+ * Read the raw joystick data
+ */
+static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+    int i;
+
+    /* Defaults */
+    if( buttons )
+        *buttons = 0;
+
+    if( axes )
+        for( i = 0; i < joy->num_axes; i++ )
+            axes[ i ] = 1500.0f;
+
+    if( joy->error )
+        return;
+
+       fgPlatformJoystickRawRead ( joy, buttons, axes );
+}
+
+/*
+ * Correct the joystick axis data
+ */
+static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
+{
+    if( value < joy->center[ axis ] )
+    {
+        float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
+                                                       joy->min[ axis ] );
+
+        if( xx < -joy->saturate[ axis ] )
+            return -1.0f;
+
+        if( xx > -joy->dead_band [ axis ] )
+            return 0.0f;
+
+        xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
+                                                 joy->dead_band[ axis ] );
+
+        return ( xx < -1.0f ) ? -1.0f : xx;
+    }
+    else
+    {
+        float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
+                                                        joy->center[ axis ] );
+
+        if( xx > joy->saturate[ axis ] )
+            return 1.0f;
+
+        if( xx < joy->dead_band[ axis ] )
+            return 0.0f;
+
+        xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
+                                                 joy->dead_band[ axis ] );
+
+        return ( xx > 1.0f ) ? 1.0f : xx;
+    }
+}
+
+/*
+ * Read the corrected joystick data
+ */
+static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+    float raw_axes[ _JS_MAX_AXES ];
+    int  i;
+
+    if( joy->error )
+    {
+        if( buttons )
+            *buttons = 0;
+
+        if( axes )
+            for ( i=0; i<joy->num_axes; i++ )
+                axes[ i ] = 0.0f;
+    }
+
+    fghJoystickRawRead( joy, buttons, raw_axes );
+
+    if( axes )
+        for( i=0; i<joy->num_axes; i++ )
+            axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
+}
+
+/*
+ * Happy happy happy joy joy joy (happy new year toudi :D)
+ */
+
+
+#if TARGET_HOST_MAC_OSX
+/** open the IOKit connection, enumerate all the HID devices, add their
+interface references to the static array. We then use the array index
+as the device number when we come to open() the joystick. */
+static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
+{
+    CFMutableDictionaryRef hidMatch = NULL;
+    IOReturn rv = kIOReturnSuccess;
+
+    io_iterator_t hidIterator;
+    io_object_t ioDev;
+
+    /* build a dictionary matching HID devices */
+    hidMatch = IOServiceMatching(kIOHIDDeviceKey);
+
+    rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
+    if (rv != kIOReturnSuccess || !hidIterator) {
+      fgWarning( "no joystick (HID) devices found" );
+      return;
+    }
+
+    /* iterate */
+    while ((ioDev = IOIteratorNext(hidIterator))) {
+        /* filter out keyboard and mouse devices */
+        CFDictionaryRef properties = getCFProperties(ioDev);
+        long usage, page;
+
+        CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
+        CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
+        CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
+        CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
+
+        /* keep only joystick devices */
+        if ( ( page == kHIDPage_GenericDesktop ) && (
+                            (usage == kHIDUsage_GD_Joystick)
+                         || (usage == kHIDUsage_GD_GamePad)
+                         || (usage == kHIDUsage_GD_MultiAxisController)
+                         || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
+            /* add it to the array */
+            ioDevices[numDevices++] = ioDev;
+    }
+
+    IOObjectRelease(hidIterator);
+}
+
+static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
+{
+    IOReturn rv;
+    CFMutableDictionaryRef cfProperties;
+
+#if 0
+    /* comment copied from darwin/SDL_sysjoystick.c */
+    /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
+     * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
+     */
+
+    io_registry_entry_t parent1, parent2;
+
+    rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
+    if (rv != kIOReturnSuccess) {
+        fgWarning ( "error getting device entry parent");
+        return NULL;
+    }
+
+    rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
+    if (rv != kIOReturnSuccess) {
+        fgWarning ( "error getting device entry parent 2");
+        return NULL;
+    }
+#endif
+
+    rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
+        &cfProperties, kCFAllocatorDefault, kNilOptions);
+    if (rv != kIOReturnSuccess || !cfProperties) {
+        fgWarning ( "error getting device properties");
+        return NULL;
+    }
+
+    return cfProperties;
+}
+
+static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
+{
+      if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
+            fgError ( "%s", "element enumerator passed non-dictionary value");
+            return;
+    }
+
+      static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
+}
+
+/** element enumerator function : pass NULL for top-level*/
+static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
+{
+      FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
+                                    "Joystick element type mismatch",
+                                    "fghJoystickEnumerateElements" );
+
+      CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
+      CFArrayApplyFunction((CFArrayRef) element, range,
+            &fghJoystickElementEnumerator, joy );
+}
+
+static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
+{
+    long cookie, lmin, lmax;
+    int index = joy->num_axes++;
+
+    CFNumberGetValue ((CFNumberRef)
+        CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
+        kCFNumberLongType, &cookie);
+
+    joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;
+
+    CFNumberGetValue ((CFNumberRef)
+        CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
+        kCFNumberLongType, &lmin);
+
+    CFNumberGetValue ((CFNumberRef)
+        CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
+        kCFNumberLongType, &lmax);
+
+    joy->min[index] = lmin;
+    joy->max[index] = lmax;
+    joy->dead_band[index] = 0.0;
+    joy->saturate[index] = 1.0;
+    joy->center[index] = (lmax + lmin) * 0.5;
+}
+
+static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
+{
+    long cookie;
+    CFNumberGetValue ((CFNumberRef)
+            CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
+            kCFNumberLongType, &cookie);
+
+    joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
+    /* anything else for buttons? */
+}
+
+static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
+{
+    /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
+    /* do we map hats to axes or buttons? */
+}
+#endif
+
+/*
+ *  Platform-Specific Code
+ */
+
+#if TARGET_HOST_MACINTOSH
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+    int i;
+
+    if ( buttons )
+    {
+        *buttons = 0;
+
+        for ( i = 0; i < joy->num_buttons; i++ )
+        {
+            UInt32 state;
+            int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);
+            ISP_CHECK_ERR(err)
+
+            *buttons |= state << i;
+        }
+    }
+
+    if ( axes )
+    {
+        for ( i = 0; i < joy->num_axes; i++ )
+        {
+            UInt32 state;
+            int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );
+            ISP_CHECK_ERR(err)
+
+            axes [i] = (float) state;
+        }
+    }
+}
+
+
+void fgPlatformJoystickOpen( SFG_Joystick* joy )
+{
+       int i = 0;
+    OSStatus err;
+
+    /* XXX FIXME: get joystick name in Mac */
+
+    err = ISpStartup( );
+
+    if( err == noErr )
+    {
+#define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
+
+        joy->error = GL_TRUE;
+
+        /* initialize the needs structure */
+        ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =
+        {
+          { "\pX-Axis",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pY-Axis",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pZ-Axis",    128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pR-Axis",    128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pAxis   4",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pAxis   5",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pAxis   6",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pAxis   7",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+          { "\pAxis   8",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
+
+          { "\pButton 0",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 1",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 2",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 3",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 4",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 5",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 6",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 7",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 8",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 9",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+          { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+        };
+
+        memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
+
+
+        /* next two calls allow keyboard and mouse to emulate other input
+         * devices (gamepads, joysticks, etc)
+         */
+        /*
+          err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
+          ISP_CHECK_ERR(err)
+
+
+          err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
+          ISP_CHECK_ERR(err)
+        */
+
+        err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,
+                                              joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
+                                              0 );
+        ISP_CHECK_ERR( err )
+
+        err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
+                       'freeglut', nil, 0, 128, 0 );
+        ISP_CHECK_ERR( err )
+
+        joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;
+        joy->num_axes    = ISP_NUM_AXIS;
+
+        for( i = 0; i < joy->num_axes; i++ )
+        {
+            joy->dead_band[ i ] = 0;
+            joy->saturate [ i ] = 1;
+            joy->center   [ i ] = kISpAxisMiddle;
+            joy->max      [ i ] = kISpAxisMaximum;
+            joy->min      [ i ] = kISpAxisMinimum;
+        }
+
+        joy->error = GL_FALSE;
+    }
+    else
+        joy->num_buttons = joy->num_axes = 0;
+}
+
+
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
+{
+    fgJoystick[ ident ]->id = ident;
+    snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */
+    fgJoystick[ ident ]->error = GL_FALSE;
+}
+
+
+void fgPlatformJoystickClose ( int ident )
+{
+    ISpSuspend( );
+    ISpStop( );
+    ISpShutdown( );
+}
+#endif
+
+#if TARGET_HOST_MAC_OSX
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+    int i;
+
+    if ( buttons != NULL )
+    {
+        *buttons = 0;
+
+        for ( i = 0; i < joy->num_buttons; i++ )
+        {
+            IOHIDEventStruct hidEvent;
+            (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );
+            if ( hidEvent.value )
+                *buttons |= 1 << i;
+        }
+    }
+
+    if ( axes != NULL )
+    {
+        for ( i = 0; i < joy->num_axes; i++ )
+        {
+            IOHIDEventStruct hidEvent;
+            (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );
+            axes[i] = hidEvent.value;
+        }
+    }
+}
+
+
+void fgPlatformJoystickOpen( SFG_Joystick* joy )
+{
+    IOReturn rv;
+    SInt32 score;
+    IOCFPlugInInterface **plugin;
+
+    HRESULT pluginResult;
+
+    CFDictionaryRef props;
+    CFTypeRef topLevelElement;
+
+    if( joy->id >= numDevices )
+    {
+        fgWarning( "device index out of range in fgJoystickOpen()" );
+        return;
+    }
+
+    /* create device interface */
+    rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
+                                            kIOHIDDeviceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID,
+                                            &plugin, &score );
+
+    if( rv != kIOReturnSuccess )
+    {
+        fgWarning( "error creating plugin for io device" );
+        return;
+    }
+
+    pluginResult = ( *plugin )->QueryInterface(
+        plugin,
+        CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
+        &( LPVOID )joy->pJoystick.hidDev
+    );
+
+    if( pluginResult != S_OK )
+        fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
+
+    ( *plugin )->Release( plugin ); /* don't leak a ref */
+    if( joy->pJoystick.hidDev == NULL )
+        return;
+
+    /* store the interface in this instance */
+    rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );
+    if( rv != kIOReturnSuccess )
+    {
+        fgWarning( "error opening device interface");
+        return;
+    }
+
+    props = getCFProperties( ioDevices[ joy->id ] );
+
+    /* recursively enumerate all the bits */
+    CFTypeRef topLevelElement =
+        CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
+    enumerateElements( topLevelElement );
+
+    CFRelease( props );
+}
+
+
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
+{
+    fgJoystick[ ident ]->id = ident;
+    fgJoystick[ ident ]->error = GL_FALSE;
+    fgJoystick[ ident ]->num_axes = 0;
+    fgJoystick[ ident ]->num_buttons = 0;
+
+    if( numDevices < 0 )
+    {
+        /* do first-time init (since we can't over-ride jsInit, hmm */
+        numDevices = 0;
+
+        mach_port_t masterPort;
+        IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
+        if( rv != kIOReturnSuccess )
+        {
+            fgWarning( "error getting master Mach port" );
+            return;
+        }
+        fghJoystickFindDevices( masterPort );
+    }
+
+    if ( ident >= numDevices )
+    {
+        fgJoystick[ ident ]->error = GL_TRUE;
+        return;
+    }
+
+    /* get the name now too */
+    CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
+    CFTypeRef ref = CFDictionaryGetValue( properties,
+                                          CFSTR( kIOHIDProductKey ) );
+    if (!ref)
+        ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
+
+    if( !ref ||
+        !CFStringGetCString( ( CFStringRef )ref, name, 128,
+                             CFStringGetSystemEncoding( ) ) )
+    {
+        fgWarning( "error getting device name" );
+        name[ 0 ] = '\0';
+    }
+}
+
+
+void fgPlatformJoystickClose ( int ident )
+{
+    ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->
+        close( fgJoystick[ ident ]->pJoystick.hidDev );
+}
+#endif
+
+
+
+
+static void fghJoystickOpen( SFG_Joystick* joy )
+{
+    /*
+     * Default values (for no joystick -- each conditional will reset the
+     * error flag)
+     */
+    joy->error = TRUE;
+    joy->num_axes = joy->num_buttons = 0;
+    joy->name[ 0 ] = '\0';
+
+       fgPlatformJoystickOpen ( joy );
+
+}
+
+/*
+ * This function replaces the constructor method in the JS library.
+ */
+static void fghJoystickInit( int ident )
+{
+    if( ident >= MAX_NUM_JOYSTICKS )
+      fgError( "Too large a joystick number: %d", ident );
+
+    if( fgJoystick[ ident ] )
+        fgError( "illegal attempt to initialize joystick device again" );
+
+    fgJoystick[ ident ] =
+        ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
+
+    /* Set defaults */
+    fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
+    fgJoystick[ ident ]->error = GL_TRUE;
+
+       fgPlatformJoystickInit( fgJoystick, ident );
+
+    fghJoystickOpen( fgJoystick[ ident  ] );
+}
+
+/*
+ * Try initializing all the joysticks (well, both of them)
+ */
+void fgInitialiseJoysticks ( void )
+{
+    if( !fgState.JoysticksInitialised )
+    {
+        int ident ;
+        for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+            fghJoystickInit( ident );
+
+        fgState.JoysticksInitialised = GL_TRUE;
+    }
+}
+
+
+void fgJoystickClose( void )
+{
+    int ident ;
+    for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+    {
+        if( fgJoystick[ ident ] )
+        {
+                       fgPlatformJoystickClose ( ident );
+
+            free( fgJoystick[ ident ] );
+            fgJoystick[ ident ] = NULL;
+            /* show joystick has been deinitialized */
+        }
+    }
+}
+
+/*
+ * Polls the joystick and executes the joystick callback hooked to the
+ * window specified in the function's parameter:
+ */
+void fgJoystickPollWindow( SFG_Window* window )
+{
+    float axes[ _JS_MAX_AXES ];
+    int buttons;
+    int ident;
+
+    freeglut_return_if_fail( window );
+    freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
+
+    for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+    {
+        if( fgJoystick[ident] )
+        {
+            fghJoystickRead( fgJoystick[ident], &buttons, axes );
+
+            if( !fgJoystick[ident]->error )
+                INVOKE_WCB( *window, Joystick,
+                            ( buttons,
+                              (int) ( axes[ 0 ] * 1000.0f ),
+                              (int) ( axes[ 1 ] * 1000.0f ),
+                              (int) ( axes[ 2 ] * 1000.0f ) )
+                );
+        }
+    }
+}
+
+/*
+ * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
+ */
+int fgJoystickDetect( void )
+{
+    int ident;
+
+    fgInitialiseJoysticks ();
+
+    if ( !fgState.JoysticksInitialised )
+        return 0;
+
+    for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
+        if( fgJoystick[ident] && !fgJoystick[ident]->error )
+            return 1;
+
+    return 0;
+}
+
+/*
+ * Joystick information functions
+ */
+int  glutJoystickGetNumAxes( int ident )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
+    return fgJoystick[ ident ]->num_axes;
+}
+int  glutJoystickGetNumButtons( int ident )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
+    return fgJoystick[ ident ]->num_buttons;
+}
+int  glutJoystickNotWorking( int ident )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
+    return fgJoystick[ ident ]->error;
+}
+
+float glutJoystickGetDeadBand( int ident, int axis )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
+    return fgJoystick[ ident ]->dead_band [ axis ];
+}
+void  glutJoystickSetDeadBand( int ident, int axis, float db )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
+    fgJoystick[ ident ]->dead_band[ axis ] = db;
+}
+
+float glutJoystickGetSaturation( int ident, int axis )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
+    return fgJoystick[ ident ]->saturate[ axis ];
+}
+void  glutJoystickSetSaturation( int ident, int axis, float st )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
+    fgJoystick[ ident ]->saturate [ axis ] = st;
+}
+
+void glutJoystickSetMinRange( int ident, float *axes )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
+    memcpy( fgJoystick[ ident ]->min, axes,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickSetMaxRange( int ident, float *axes )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
+    memcpy( fgJoystick[ ident ]->max, axes,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickSetCenter( int ident, float *axes )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
+    memcpy( fgJoystick[ ident ]->center, axes,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+
+void glutJoystickGetMinRange( int ident, float *axes )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
+    memcpy( axes, fgJoystick[ ident ]->min,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickGetMaxRange( int ident, float *axes )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
+    memcpy( axes, fgJoystick[ ident ]->max,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickGetCenter( int ident, float *axes )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
+    memcpy( axes, fgJoystick[ ident ]->center,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+
+/*** END OF FILE ***/