[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#248201: Reassign to freeglut3



reassign 248201 freeglut3
tags 248201 + patch
thanks

Hi,

this bug is caused by freeglut3-2.2.0 not correctly handling
glutIgnoreKeyRepeat() calls. This has been fixed in upstream CVS on Sun, 14
Mar 2004.

The attached files are taken from upstream CVS and are diff'ed against the
2.2.0 release tag. The corresponding revisions are listed in the diffs.

I have successfully tested the freeglut3 package with these patches applied
and since then can't reproduce this bug in billard-gl. I therefore recommend
incorporating the attached patches into the next release of the freeglut3
package.

Thierry
===================================================================
RCS file: /cvsroot/freeglut/freeglut/freeglut/src/freeglut_init.c,v
retrieving revision 1.26
retrieving revision 1.33
diff -u -r1.26 -r1.33
--- freeglut/freeglut/freeglut/src/freeglut_init.c	2003/11/28 19:19:54	1.26
+++ freeglut/freeglut/freeglut/src/freeglut_init.c	2004/03/14 04:36:02	1.33
@@ -29,7 +29,7 @@
 #include "config.h"
 #endif
 
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
@@ -65,7 +65,7 @@
                       GL_FALSE,              /* UseCurrentContext */
                       GL_FALSE,              /* GLDebugSwitch */
                       GL_FALSE,              /* XSyncSwitch */
-                      GL_TRUE,               /* IgnoreKeyRepeat */
+                      GL_TRUE,               /* KeyRepeat */
                       0xffffffff,            /* Modifiers */
                       0,                     /* FPSInterval */
                       0,                     /* SwapCount */
@@ -205,6 +205,7 @@
 #endif
 
     fgJoystickInit( 0 );
+    fgJoystickInit( 1 );
 
     fgState.Initialised = GL_TRUE;
 }
@@ -271,7 +272,7 @@
     fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
     fgState.ExecState           = GLUT_EXEC_STATE_INIT;
 
-    fgState.IgnoreKeyRepeat = GL_TRUE;
+    fgState.KeyRepeat       = GL_FALSE;
     fgState.Modifiers       = 0xffffffff;
 
     fgState.GameModeSize.X  = 640;
@@ -297,7 +298,7 @@
         free( fgState.ProgramName );
         fgState.ProgramName = NULL;
     }
-    
+
 
 #if TARGET_HOST_UNIX_X11
 
@@ -368,7 +369,7 @@
  *   It returns a bitmask that indicates which of the four values
  *   were actually found in the string.  For each value found,
  *   the corresponding argument is updated;  for each value
- *   not found, the corresponding argument is left unchanged. 
+ *   not found, the corresponding argument is left unchanged.
  */
 
 static int
@@ -376,7 +377,7 @@
 {
     register int Result = 0;
     int Sign = 1;
-    
+
     if (*string == '+')
         string++;
     else if (*string == '-')
@@ -416,7 +417,7 @@
     strind = (char *)string;
     if (*strind != '+' && *strind != '-' && *strind != 'x') {
         tempWidth = ReadInteger(strind, &nextCharacter);
-        if (strind == nextCharacter) 
+        if (strind == nextCharacter)
             return 0;
         strind = nextCharacter;
         mask |= WidthValue;
@@ -519,9 +520,13 @@
         const char *fps = getenv( "GLUT_FPS" );
         if( fps )
         {
-            sscanf( fps, "%d", &fgState.FPSInterval );
-            if( fgState.FPSInterval <= 0 )
-                fgState.FPSInterval = 5000;  /* 5000 milliseconds */
+            int interval;
+            sscanf( fps, "%d", &interval );
+
+            if( interval <= 0 )
+                fgState.FPSInterval = 5000;  /* 5000 millisecond default */
+            else
+                fgState.FPSInterval = interval;
         }
     }
 
@@ -608,15 +613,9 @@
     }
 
     /*
-     * Have the display created now. As I am too lazy to implement
-     * the program arguments parsing, we will have the DISPLAY
-     * environment variable used for opening the X display:
-     *
-     * XXX The above comment is rather unclear.  We have just
-     * XXX completed parsing of the program arguments for GLUT
-     * XXX parameters.  We obviously canNOT parse the application-
-     * XXX specific parameters.  Can someone re-write the above
-     * XXX more clearly?
+     * Have the display created now. If there wasn't a "-display"
+     * in the program arguments, we will use the DISPLAY environment
+     * variable for opening the X display (see code above):
      */
     fgInitialize( displayName );
 
===================================================================
RCS file: /cvsroot/freeglut/freeglut/freeglut/src/freeglut_internal.h,v
retrieving revision 1.34
retrieving revision 1.42
diff -u -r1.34 -r1.42
--- freeglut/freeglut/freeglut/src/freeglut_internal.h	2003/12/11 21:29:43	1.34
+++ freeglut/freeglut/freeglut/src/freeglut_internal.h	2004/03/14 04:36:02	1.42
@@ -31,17 +31,17 @@
 /* XXX Update these for each release! */
 #define  VERSION_MAJOR 2
 #define  VERSION_MINOR 2
-#define  VERSION_PATCH 0 
+#define  VERSION_PATCH 0
 
 /*
  * Freeglut is meant to be available under all Unix/X11 and Win32 platforms.
  */
-#if !defined(_WIN32)
-#   define  TARGET_HOST_UNIX_X11    1
-#   define  TARGET_HOST_WIN32       0
-#else
+#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)
 #   define  TARGET_HOST_UNIX_X11    0
 #   define  TARGET_HOST_WIN32       1
+#else
+#   define  TARGET_HOST_UNIX_X11    1
+#   define  TARGET_HOST_WIN32       0
 #endif
 
 #define  FREEGLUT_MAX_MENUS         3
@@ -61,7 +61,10 @@
 #if TARGET_HOST_WIN32
 #include <windows.h>
 #include <windowsx.h>
+#include <mmsystem.h>
+#endif
 
+#if defined(_MSC_VER)
 #define strdup   _strdup
 #endif
 
@@ -230,7 +233,7 @@
     GLboolean        GLDebugSwitch;        /* OpenGL state debugging switch  */
     GLboolean        XSyncSwitch;          /* X11 sync protocol switch       */
 
-    GLboolean        IgnoreKeyRepeat;      /* Whether to ignore key repeat.  */
+    int              KeyRepeat;            /* Global key repeat mode.        */
     int              Modifiers;            /* Current ALT/SHIFT/CTRL state   */
 
     GLuint           FPSInterval;          /* Interval between FPS printfs   */
@@ -338,6 +341,8 @@
 
 #if TARGET_HOST_UNIX_X11
     XVisualInfo*    VisualInfo;      /* The window's visual information     */
+    Pixmap          Pixmap;          /* Used for offscreen rendering        */
+    /* GLXPixmap      GLXPixMap; */  /* Used for offscreen rendering        */
 #elif TARGET_HOST_WIN32
     HDC             Device;          /* The window's device context         */
 #endif
@@ -362,17 +367,44 @@
     int             Cursor;             /* The currently selected cursor     */
 
     long            JoystickPollRate;   /* The joystick polling rate         */
-    long            JoystickLastPoll;   /* When the last poll has happened   */
+    long            JoystickLastPoll;   /* When the last poll happened       */
 
     int             MouseX, MouseY;     /* The most recent mouse position    */
 
-    GLboolean       IsGameMode;         /* Is this the game mode window?     */
+    GLboolean       IgnoreKeyRepeat;    /* Whether to ignore key repeat.     */
+    GLboolean       KeyRepeating;       /* Currently in repeat mode          */
 
+    GLboolean       IsGameMode;         /* Is this the game mode window?     */
     GLboolean       NeedToResize;       /* Do we need to resize the window?  */
+    GLboolean       IsOffscreen;        /* Tags a `window' as on/offscreen.  */
 };
 
 
 /*
+ * SET_WCB() is used as:
+ *
+ *     SET_WCB( window, Visibility, func );
+ *
+ * ...where {window} is the freeglut window to set the callback,
+ *          {Visibility} is the window-specific callback to set,
+ *          {func} is a function-pointer.
+ *
+ * Originally, {FETCH_WCB( ... ) = func} was rather sloppily used,
+ * but this can cause warnings because the FETCH_WCB() macro type-
+ * casts its result, and a type-cast value shouldn't be an lvalue.
+ *
+ * The {if( FETCH_WCB( ... ) != func )} test is to do type-checking
+ * and for no other reason.  Since it's hidden in the macro, the
+ * ugliness is felt to be rather benign.
+ */
+#define SET_WCB(window,cbname,func)                            \
+do                                                             \
+{                                                              \
+    if( FETCH_WCB( window, cbname ) != func )                  \
+        (((window).CallBacks[CB_ ## cbname]) = (void *) func); \
+} while( 0 )                                                   \
+
+/*
  * FETCH_WCB() is used as:
  *
  *     FETCH_WCB( window, Visibility );
@@ -459,7 +491,7 @@
     CB_ButtonBox,
     CB_TabletMotion,
     CB_TabletButton,
-    
+
     /* Always make this the LAST one */
     TOTAL_CALLBACKS
 };
===================================================================
RCS file: /cvsroot/freeglut/freeglut/freeglut/src/freeglut_joystick.c,v
retrieving revision 1.15
retrieving revision 1.26
diff -u -r1.15 -r1.26
--- freeglut/freeglut/freeglut/src/freeglut_joystick.c	2003/11/15 19:06:27	1.15
+++ freeglut/freeglut/freeglut/src/freeglut_joystick.c	2004/03/14 03:47:46	1.26
@@ -25,123 +25,407 @@
  */
 
 /*
- * PWO: This is not exactly what Steve Baker has done for PLIB, as I had to
- *      convert it from C++ to C. And I've also reformatted it a bit (that's
- *      my little personal deviation :]) I don't really know if it is still
- *      portable...
- *      Steve: could you please add some comments to the code? :)
- *
  * 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.
  */
 
 #if defined( __FreeBSD__ ) || defined( __NetBSD__ )
-#include <sys/param.h>
+#    include <sys/param.h>
 #endif
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#    include "config.h"
 #endif
 
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
- * PWO: I don't like it at all. It's a mess. Could it be cleared?
+ * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
+ * interspersed
+ */
+#define _JS_MAX_BUTTONS 32
+
+
+#if TARGET_HOST_MACINTOSH
+#    define _JS_MAX_AXES  9
+#    include <InputSprocket.h>
+#endif
+
+#if TARGET_HOST_MAC_OSX
+#    define _JS_MAX_AXES 16
+#    include <mach/mach.h>
+#    include <IOKit/IOkitLib.h>
+#    include <IOKit/hid/IOHIDLib.h>
+#endif
+
+#if TARGET_HOST_WIN32
+#    define _JS_MAX_AXES  8
+#    include <windows.h>
+#    include <mmsystem.h>
+#    include <string.h>
+#    include <regstr.h>
+
+#endif
+
+#if TARGET_HOST_UNIX_X11
+#    define _JS_MAX_AXES 16
+#    if defined(__FreeBSD__) || defined(__NetBSD__)
+/*
+ * XXX The below hack is done until freeglut's autoconf is updated.
+ */
+#        define HAVE_USB_JS    1
+
+#        include <sys/ioctl.h>
+#        if defined(__FreeBSD__) && __FreeBSD_version >= 500000
+#            include <sys/joystick.h>
+#        else
+/*
+ * XXX NetBSD/amd64 systems may find that they have to steal the
+ * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
+ * XXX I cannot comment whether that works for the interface, but
+ * XXX it lets you compile...(^&  I do not think that we can do away
+ * XXX with this header.
+ */
+#            include <machine/joystick.h>         /* For analog joysticks */
+#        endif
+#        define JS_DATA_TYPE joystick
+#        define JS_RETURN (sizeof(struct JS_DATA_TYPE))
+#    endif
+
+#    include <unistd.h>
+#    include <fcntl.h>
+#    include <errno.h>
+
+#    if defined(__linux__)
+#        include <sys/ioctl.h>
+#        include <linux/joystick.h>
+
+/* check the joystick driver version */
+#        if defined(JS_VERSION) && JS_VERSION >= 0x010000
+#            define JS_NEW
+#        endif
+#    else  /* Not BSD or Linux */
+#        ifndef JS_RETURN
+
+  /*
+   * We'll put these values in and that should
+   * allow the code to at least compile when there is
+   * no support. The JS open routine should error out
+   * and shut off all the code downstream anyway and if
+   * the application doesn't use a joystick we'll be fine.
+   */
+
+  struct JS_DATA_TYPE
+  {
+    int buttons;
+    int x;
+    int y;
+  };
+
+#            define JS_RETURN (sizeof(struct JS_DATA_TYPE))
+#        endif
+#    endif
+#endif
+
+#define JS_TRUE  1
+#define JS_FALSE 0
+
+/*
+ * BSD defines from "jsBSD.cxx" around lines 42-270
+ */
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+
+#    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__)
+#            if __FreeBSD_version < 500000
+#                include <libusbhid.h>
+#            else
+/*
+ * XXX The below hack is done until freeglut's autoconf is updated.
+ */
+#                define HAVE_USBHID_H 1
+#                include <usbhid.h>
+#            endif
+#        endif
+#        include <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.
  */
-#ifdef WIN32
-#   include <windows.h>
-#   if defined( __CYGWIN32__ ) || defined( __CYGWIN__ )
-#       define NEAR /* */
-#       define FAR  /* */
+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++) {
+    sprintf(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;
+    } else if (errno == EACCES) {
+      if (!protection_warned) {
+        fprintf(stderr, "Can't open %s for read!\n",
+          buf);
+        protection_warned = 1;
+      }
+    }
+  }
+  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
-#   include <mmsystem.h>
-#   include <string.h>
-#else
-#   include <unistd.h>
-#   include <fcntl.h>
-#   if defined(__FreeBSD__) || defined(__NetBSD__)
-#   if __FreeBSD_version >= 500000
-#       include <sys/joystick.h>
+    struct hid_data *d;
+    struct hid_item h;
+    report_desc_t rd;
+
+    if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
+    {
+        fprintf( stderr, "error: %s: %s", os->fname, strerror( errno ) );
+        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? ***/
+            fprintf( stderr, "error: %s%d: %s",
+                     UHIDDEV, report_id, strerror( errno ) );
+            return FALSE;
+        }
+
+        size = hid_report_size( rd, hid_input, report_id );
 #   else
-#       include <machine/joystick.h>
+        size = hid_report_size( rd, 0, hid_input );
 #   endif
-#       define JS_DATA_TYPE joystick
-#       define JS_RETURN (sizeof(struct JS_DATA_TYPE))
-#   elif defined(__linux__)
-#       include <sys/ioctl.h>
-#       include <linux/joystick.h>
-#       include <errno.h>
+    os->hid_data_buf = calloc( 1, size );
+    os->hid_dlen = size;
 
-        /*
-         * Check the joystick driver version
-         */
-#       ifdef JS_VERSION
-#           if JS_VERSION >= 0x010000
-#               define JS_NEW
-#           endif
-#       endif
+    is_joystick = 0;
+#   ifdef HAVE_USBHID_H
+        d = hid_start_parse( rd, 1 << hid_input, report_id );
 #   else
-#       ifndef JS_DATA_TYPE
+        d = hid_start_parse( rd, 1 << hid_input );
+#   endif
+        while( hid_get_item( d, &h ) )
+        {
+            int usage, page, interesting_hid;
 
-            /*
-             * Not Windoze and no (known) joystick driver...
-             *
-             * Well - we'll put these values in and that should
-             * allow the code to at least compile. The JS open
-             * routine should error out and shut off all the code
-             * downstream anyway
-             */
-            struct JS_DATA_TYPE
+            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 )
             {
-                int buttons;
-                int x;
-                int y;
-            };
+                interesting_hid = ( usage > 0 ) &&
+                    ( usage <= _JS_MAX_BUTTONS );
 
-#           define JS_RETURN (sizeof(struct JS_DATA_TYPE))
-#       endif
-#   endif
-#endif
+                if( interesting_hid && usage - 1 > *num_buttons )
+                    *num_buttons = usage - 1;
+            }
 
-#ifdef WIN32
-#   define _JS_MAX_AXES 6
-#else
-#   ifdef __FreeBSD__
-#       define _JS_MAX_AXES 2
-#   else
-#       define _JS_MAX_AXES 6
-#   endif
+            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
 
+/*
+ * Definition of "SFG_Joystick" structure -- based on JS's "jsJoystick" object class.
+ * See "js.h" lines 80-178.
+ */
 typedef struct tagSFG_Joystick SFG_Joystick;
 struct tagSFG_Joystick
 {
-/*
- * XXX All BSDs might share this?
- */
-#ifdef __FreeBSD__
-    int         id;
+#if TARGET_HOST_MACINTOSH
+#define  ISP_NUM_AXIS    9
+#define  ISP_NUM_NEEDS  41
+    ISpElementReference isp_elem  [ ISP_NUM_NEEDS ];
+    ISpNeed             isp_needs [ ISP_NUM_NEEDS ];
+#endif
+
+#if TARGET_HOST_MAC_OSX
+    IOHIDDeviceInterface ** hidDev;
+    IOHIDElementCookie buttonCookies[41];
+    IOHIDElementCookie axisCookies[_JS_MAX_AXES];
+    long minReport[_JS_MAX_AXES],
+         maxReport[_JS_MAX_AXES];
 #endif
 
-#ifdef WIN32
+#if TARGET_HOST_WIN32
+    JOYCAPS     jsCaps;
     JOYINFOEX   js;
     UINT        js_id;
-#else
+#endif
+
+
+#if TARGET_HOST_UNIX_X11
+#   if defined(__FreeBSD__) || defined(__NetBSD__)
+       struct os_specific_s *os;
+#   endif
+
 #   ifdef JS_NEW
-        struct js_event js;
-        int         tmp_buttons;
-        float       tmp_axes[ _JS_MAX_AXES ];
+       struct js_event     js;
+       int          tmp_buttons;
+       float        tmp_axes [ _JS_MAX_AXES ];
 #   else
-        struct JS_DATA_TYPE js;
+       struct JS_DATA_TYPE js;
 #   endif
 
-    char fname[ 128 ];
-    int  fd;
+    char         fname [ 128 ];
+    int          fd;
 #endif
 
-    GLboolean error;
-    int       num_axes;
-    int       num_buttons;
+    int          id;
+    GLboolean    error;
+    char         name [ 128 ];
+    int          num_axes;
+    int          num_buttons;
 
     float dead_band[ _JS_MAX_AXES ];
     float saturate [ _JS_MAX_AXES ];
@@ -151,54 +435,172 @@
 };
 
 /*
+ * 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 );
+
+void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
+/* callback for CFArrayApply */
+static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
+void fghJoystickParseElement ( SFG_Joystick* joy, CFDictionaryRef element );
+
+void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
+void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
+void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
+#endif
+
+
+/*
  * The static joystick structure pointer
  */
-static SFG_Joystick* fgJoystick = NULL;
+#define MAX_NUM_JOYSTICKS  2
+static int fgNumberOfJoysticks = 0;
+static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
+
 
 /*
  * Read the raw joystick data
  */
 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
 {
-#ifdef WIN32
+#if TARGET_HOST_WIN32
     MMRESULT status;
 #else
     int status;
 #endif
 
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+    int len;
+#endif
+
     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;
+
+#if TARGET_HOST_MACINTOSH
+    if ( buttons )
     {
-        if( buttons )
-            *buttons = 0;
+        *buttons = 0;
 
-        if( axes )
-            for( i=0; i<joy->num_axes; i++ )
-                axes[ i ] = 1500.0f;
+        for ( i = 0; i < joy->num_buttons; i++ )
+        {
+            UInt32 state;
+            int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
+            ISP_CHECK_ERR(err)
 
-        return;
+            *buttons |= state << i;
+        }
     }
 
-#ifdef WIN32
+    if ( axes )
+    {
+        for ( i = 0; i < joy->num_axes; i++ )
+        {
+            UInt32 state;
+            int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
+            ISP_CHECK_ERR(err)
+
+            axes [i] = (float) state;
+        }
+    }
+#endif
+
+#if TARGET_HOST_MAC_OSX
+    if ( buttons != NULL )
+    {
+        *buttons = 0;
+
+        for ( i = 0; i < joy->num_buttons; i++ )
+        {
+            IOHIDEventStruct hidEvent;
+            (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
+            if ( hidEvent.value )
+                *buttons |= 1 << i;
+        }
+    }
+
+    if ( axes != NULL )
+    {
+        for ( i = 0; i < joy->num_axes; i++ )
+        {
+            IOHIDEventStruct hidEvent;
+            (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
+            axes[i] = hidEvent.value;
+        }
+    }
+#endif
+
+#if TARGET_HOST_WIN32
     status = joyGetPosEx( joy->js_id, &joy->js );
 
-    if( status != JOYERR_NOERROR )
+    if ( status != JOYERR_NOERROR )
     {
         joy->error = GL_TRUE;
         return;
     }
 
-    if( buttons )
+    if ( buttons )
         *buttons = joy->js.dwButtons;
 
-    if( axes )
+    if ( axes )
     {
         /*
          * WARNING - Fall through case clauses!!
          */
-        switch( joy->num_axes )
+        switch ( joy->num_axes )
         {
+        case 8:
+            /* Generate two POV axes from the POV hat angle.
+             * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
+             *   hundredths of a degree, or 0xFFFF when idle.
+             */
+            if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
+            {
+              axes [ 6 ] = 0.0;
+              axes [ 7 ] = 0.0;
+            }
+            else
+            {
+              /* This is the contentious bit: how to convert angle to X/Y.
+               *    wk: I know of no define for PI that we could use here:
+               *    SG_PI would pull in sg, M_PI is undefined for MSVC
+               * But the accuracy of the value of PI is very unimportant at
+               * this point.
+               */
+              float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
+              float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
+
+              /* Convert to coordinates on a square so that North-East
+               * is (1,1) not (.7,.7), etc.
+               * s and c cannot both be zero so we won't divide by zero.
+               */
+              if ( fabs ( s ) < fabs ( c ) )
+              {
+                axes [ 6 ] = ( c < 0.0 ) ? -s/c  : s/c ;
+                axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
+              }
+              else
+              {
+                axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
+                axes [ 7 ] = ( s < 0.0 ) ? -c/s  : c/s ;
+              }
+            }
+
         case 6: axes[5] = (float) joy->js.dwVpos;
         case 5: axes[4] = (float) joy->js.dwUpos;
         case 4: axes[3] = (float) joy->js.dwRpos;
@@ -207,34 +609,110 @@
         case 1: axes[0] = (float) joy->js.dwXpos;
         }
     }
-#else
-#   ifdef JS_NEW
+#endif
+
+#if TARGET_HOST_UNIX_X11
+#    if defined(__FreeBSD__) || defined(__NetBSD__)
+    if ( joy->os->is_analog )
+    {
+        int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
+        if ( status != sizeof(joy->os->ajs) ) {
+            perror ( joy->os->fname );
+            joy->error = GL_TRUE;
+            return;
+        }
+        if ( buttons != NULL )
+            *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
+
+        if ( axes != NULL )
+        {
+            axes[0] = (float) joy->os->ajs.x;
+            axes[1] = (float) joy->os->ajs.y;
+        }
 
-    while( 1 )
+        return;
+    }
+
+#        ifdef HAVE_USB_JS
+    while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
     {
-        status = read( joy->fd, &joy->js, sizeof(struct js_event) );
+        struct hid_item *h;
 
-        if( status != sizeof( struct js_event ) )
+        for  ( h = joy->os->hids; h; h = h->next )
         {
-            if( errno == EAGAIN )
+            int d = hid_get_data ( joy->os->hid_data_buf, h );
+
+            int page = HID_PAGE ( h->usage );
+            int usage = HID_USAGE ( h->usage );
+
+            if ( page == HUP_GENERIC_DESKTOP )
+            {
+                int i;
+                for ( i = 0; i < joy->num_axes; i++ )
+                    if (joy->os->axes_usage[i] == usage)
+                    {
+                        if (usage == HUG_HAT_SWITCH)
+                        {
+                            if (d < 0 || d > 8)
+                                d = 0;  /* safety */
+                            joy->os->cache_axes[i] = (float)hatmap_x[d];
+                            joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
+                        }
+                        else
+                        {
+                            joy->os->cache_axes[i] = (float)d;
+                        }
+                        break;
+                    }
+            }
+            else if (page == HUP_BUTTON)
             {
-                /*
-                 * Use the old values
-                 */
-                if( buttons )
+               if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
+               {
+                   if (d)
+                       joy->os->cache_buttons |= (1 << usage - 1);
+                   else
+                       joy->os->cache_buttons &= ~(1 << usage - 1);
+               }
+            }
+        }
+    }
+    if ( len < 0 && errno != EAGAIN )
+    {
+        perror( joy->os->fname );
+        joy->error = 1;
+    }
+    if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
+    if ( axes    != NULL )
+        memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
+#        endif
+#    endif
+
+#    ifdef JS_NEW
+
+    while ( 1 )
+    {
+        status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
+
+        if ( status != sizeof( struct js_event ) )
+        {
+            if ( errno == EAGAIN )
+            {
+                /* Use the old values */
+                if ( buttons )
                     *buttons = joy->tmp_buttons;
-                if( axes )
+                if ( axes )
                     memcpy( axes, joy->tmp_axes,
                             sizeof( float ) * joy->num_axes );
                 return;
             }
 
-            fgWarning( "%s", joy->fname );
+            fgWarning ( "%s", joy->fname );
             joy->error = GL_TRUE;
             return;
         }
 
-        switch( joy->js.type & ~JS_EVENT_INIT )
+        switch ( joy->js.type & ~JS_EVENT_INIT )
         {
         case JS_EVENT_BUTTON:
             if( joy->js.value == 0 ) /* clear the flag */
@@ -244,40 +722,54 @@
             break;
 
         case JS_EVENT_AXIS:
-            joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
-            
-            if( axes )
-                memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
+            if ( joy->js.number < joy->num_axes )
+            {
+                joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
+
+                if( axes )
+                    memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
+            }
             break;
+
+        default:
+            fgWarning ( "%s", "PLIB_JS: Unrecognised /dev/js return!?!" );
+
+            /* use the old values */
+
+            if ( buttons != NULL ) *buttons = joy->tmp_buttons;
+            if ( axes    != NULL )
+                memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
+
+            return;
         }
 
         if( buttons )
             *buttons = joy->tmp_buttons;
     }
-#   else
+#    else
 
     status = read( joy->fd, &joy->js, JS_RETURN );
 
-    if( status != JS_RETURN )
+    if ( status != JS_RETURN )
     {
         fgWarning( "%s", joy->fname );
         joy->error = GL_TRUE;
         return;
     }
 
-    if( buttons )
-#       if defined( __FreeBSD__ ) || defined( __NetBSD__ )
-        *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 );
-#       else
+    if ( buttons )
+#        if defined( __FreeBSD__ ) || defined( __NetBSD__ )
+        *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 );  /* XXX Should not be here -- BSD is handled earlier */
+#        else
         *buttons = joy->js.buttons;
-#       endif
+#        endif
 
-    if( axes )
+    if ( axes )
     {
         axes[ 0 ] = (float) joy->js.x;
         axes[ 1 ] = (float) joy->js.y;
     }
-#   endif
+#    endif
 #endif
 }
 
@@ -334,158 +826,681 @@
             *buttons = 0;
 
         if( axes )
-            for ( i=0; i<joy->num_axes ; i++ )
-                axes[ i ] = 0.0f ;
+            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++ )
+        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( "%s", "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 ( "%s", "error getting device entry parent");
+        return NULL;
+    }
+
+    rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
+    if (rv != kIOReturnSuccess) {
+        fgWarning ( "%s", "error getting device entry parent 2");
+        return NULL;
+    }
+#endif
+
+    rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
+        &cfProperties, kCFAllocatorDefault, kNilOptions);
+    if (rv != kIOReturnSuccess || !cfProperties) {
+        fgWarning ( "%s", "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 )
+{
+      assert(CFGetTypeID(element) == CFArrayGetTypeID());
+
+      CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
+      CFArrayApplyFunction((CFArrayRef) element, range,
+            &fghJoystickElementEnumerator, joy );
+}
+
+static void fghJoystickParseElement ( SFG_Joystick *joy, CFDictionaryRef element )
+{
+    CFTypeRef refPage = CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementUsagePageKey));
+    CFTypeRef refUsage = CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementUsageKey));
+
+    long type, page, usage;
+
+    CFNumberGetValue((CFNumberRef)
+        CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementTypeKey)),
+        kCFNumberLongType, &type);
+
+    switch ( typ e) {
+    case kIOHIDElementTypeInput_Misc:
+    case kIOHIDElementTypeInput_Axis:
+    case kIOHIDElementTypeInput_Button:
+        printf("got input element...");
+        CFNumberGetValue( (CFNumberRef) refUsage, kCFNumberLongType, &usage );
+        CFNumberGetValue( (CFNumberRef) refPage, kCFNumberLongType, &page );
+
+        if (page == kHIDPage_GenericDesktop) {
+            switch ( usage ) /* look at usage to determine function */
+            {
+            case kHIDUsage_GD_X:
+            case kHIDUsage_GD_Y:
+            case kHIDUsage_GD_Z:
+            case kHIDUsage_GD_Rx:
+            case kHIDUsage_GD_Ry:
+            case kHIDUsage_GD_Rz:
+            case kHIDUsage_GD_Slider: /* for throttle / trim controls */
+                printf(" axis\n");
+                fghJoystickAddAxisElement((CFDictionaryRef) element);
+                break;
+
+            case kHIDUsage_GD_Hatswitch:
+                printf(" hat\n");
+                fghJoystickAddHatElement((CFDictionaryRef) element);
+                break;
+
+            default:
+                printf("input type element has weird usage (%x)\n", usage);
+                break;
+            }
+        } else if (page == kHIDPage_Button) {
+            printf(" button\n");
+            fghJoystickAddButtonElement((CFDictionaryRef) element);
+        } else
+            printf("input type element has weird page (%x)\n", page);
+        break;
+
+    case kIOHIDElementTypeCollection:
+        fghJoystickEnumerateElements (
+            CFDictionaryGetValue ( element, CFSTR(kIOHIDElementKey) )
+        );
+        break;
+
+    default:
+        break;
+    }
+}
+
+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);
+
+    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->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
+
+#if TARGET_HOST_WIN32
+/* Inspired by
+   http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
+ */
+#    if defined(_MSC_VER)
+#        pragma comment (lib, "advapi32.lib")
+#    endif
+
+static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )
+{
+    char buffer [ 256 ];
+
+    char OEMKey [ 256 ];
+
+    HKEY  hKey;
+    DWORD dwcb;
+    LONG  lr;
+
+    if ( joy->error )
+        return 0;
+
+    /* Open .. MediaResources\CurrentJoystickSettings */
+    sprintf ( buffer, "%s\\%s\\%s",
+              REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,
+              REGSTR_KEY_JOYCURR );
+
+    lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
+
+    if ( lr != ERROR_SUCCESS ) return 0;
+
+    /* Get OEM Key name */
+    dwcb = sizeof(OEMKey);
+
+    /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */
+    sprintf ( buffer, "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );
+
+    lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);
+    RegCloseKey ( hKey );
+
+    if ( lr != ERROR_SUCCESS ) return 0;
+
+    /* Open OEM Key from ...MediaProperties */
+    sprintf ( buffer, "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );
+
+    lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );
+
+    if ( lr != ERROR_SUCCESS ) return 0;
+
+    /* Get OEM Name */
+    dwcb = buf_sz;
+
+    lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,
+                             &dwcb );
+    RegCloseKey ( hKey );
+
+    if ( lr != ERROR_SUCCESS ) return 0;
+
+    return 1;
+}
+#endif
+
+
 static void fghJoystickOpen( SFG_Joystick* joy )
 {
-#ifdef WIN32
-    JOYCAPS jsCaps;
-    int     i;
+    int i;
+#if TARGET_HOST_MACINTOSH
+    OSStatus err;
+#endif
+#if TARGET_HOST_MAC_OSX
+        IOReturn rv;
+        SInt32 score;
+        IOCFPlugInInterface **plugin;
+
+        HRESULT pluginResult;
+
+        CFDictionaryRef props;
+    CFTypeRef topLevelElement;
+#endif
+#if TARGET_HOST_UNIX_X11
+#    if defined( __FreeBSD__ ) || defined( __NetBSD__ )
+       char *cp;
+#    endif
+#    ifdef JS_NEW
+       unsigned char u;
+#    else
+       int counter;
+#    endif
+#endif
+
+    /*
+     * 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';
+
+#if TARGET_HOST_MACINTOSH
+    /*
+     * 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->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( joy->isp_num_needs,
+                                              joy->isp_needs, joy->isp_elem,
+                                              0 );
+        ISP_CHECK_ERR( err )
+
+        err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
+                       'freeglut', nil, 0, 128, 0 );
+        ISP_CHECK_ERR( err )
+
+        joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
+        joy->num_axes    = joy->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;
+#endif
+
+#if TARGET_HOST_MAC_OSX
+    if( joy->id >= numDevices )
+    {
+        fgWarning( "%s", "device index out of range in fgJoystickOpen()" );
+        return;
+    }
+
+    /* create device interface */
+    rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
+                                            kIOHIDDeviceUserClientTypeID,
+                                            kIOCFPlugInInterfaceID,
+                                            &plugin, &score );
+
+    if( rv != kIOReturnSuccess )
+    {
+        fgWarning( "%s", "error creating plugin for io device" );
+        return;
+    }
+
+    pluginResult = ( *plugin )->QueryInterface(
+        plugin,
+        CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
+        &( LPVOID )joy->hidDev
+    );
+
+    if( pluginResult != S_OK )
+        fgWarning ( "%s", "QI-ing IO plugin to HID Device interface failed" );
 
+    ( *plugin )->Release( plugin ); /* don't leak a ref */
+    if( joy->hidDev == NULL )
+        return;
+
+    /* store the interface in this instance */
+    rv = ( *( joy->hidDev ) )->open( joy->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 );
+#endif
+
+#if TARGET_HOST_WIN32
     joy->js.dwFlags = JOY_RETURNALL;
     joy->js.dwSize  = sizeof( joy->js );
 
-    memset( &jsCaps, 0, sizeof( jsCaps ) );
+    memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
 
     joy->error =
-        ( joyGetDevCaps( joy->js_id, &jsCaps, sizeof( jsCaps ) ) !=
+        ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
           JOYERR_NOERROR );
-    joy->num_axes =
-        ( jsCaps.wNumAxes < _JS_MAX_AXES ) ? jsCaps.wNumAxes : _JS_MAX_AXES;
 
-    /*
-     * WARNING - Fall through case clauses!!
-     */
-    switch( joy->num_axes )
+    if( joy->jsCaps.wNumAxes == 0 )
     {
-    case 6:
-        joy->min[ 5 ] = (float) jsCaps.wVmin;
-        joy->max[ 5 ] = (float) jsCaps.wVmax;
-    case 5:
-        joy->min[ 4 ] = (float) jsCaps.wUmin;
-        joy->max[ 4 ] = (float) jsCaps.wUmax;
-    case 4:
-        joy->min[ 3 ] = (float) jsCaps.wRmin;
-        joy->max[ 3 ] = (float) jsCaps.wRmax;
-    case 3:
-        joy->min[ 2 ] = (float) jsCaps.wZmin;
-        joy->max[ 2 ] = (float) jsCaps.wZmax;
-    case 2:
-        joy->min[ 1 ] = (float) jsCaps.wYmin;
-        joy->max[ 1 ] = (float) jsCaps.wYmax;
-    case 1:
-        joy->min[ 0 ] = (float) jsCaps.wXmin;
-        joy->max[ 0 ] = (float) jsCaps.wXmax;
-        break;
-
-    /*
-     * I guess we have no axes at all
-     */
-    default:
+        joy->num_axes = 0;
         joy->error = GL_TRUE;
-        break;
+    }
+    else
+    {
+        /* Device name from jsCaps is often "Microsoft PC-joystick driver",
+         * at least for USB.  Try to get the real name from the registry.
+         */
+        if ( ! fghJoystickGetOEMProductName( joy, joy->name,
+                                             sizeof( joy->name ) ) )
+        {
+            fgWarning( "JS: Failed to read joystick name from registry" );
+            strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );
+        }
+
+        /* Windows joystick drivers may provide any combination of
+         * X,Y,Z,R,U,V,POV - not necessarily the first n of these.
+         */
+        if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )
+        {
+            joy->num_axes = _JS_MAX_AXES;
+            joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0;  /* POV Y */
+            joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0;  /* POV X */
+        }
+        else
+            joy->num_axes = 6;
+
+        joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;
+        joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;
+        joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;
+        joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;
+        joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;
+        joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;
+        joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;
+        joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;
+        joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;
+        joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;
+        joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;
+        joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;
     }
 
     /*
      * Guess all the rest judging on the axes extremals
      */
-    for( i=0 ; i<joy->num_axes ; i++ )
+    for( i = 0; i < joy->num_axes; i++ )
     {
-        joy->center   [ i ] = (joy->max[i] + joy->min[i]) * 0.5f;
+        joy->center   [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
         joy->dead_band[ i ] = 0.0f;
         joy->saturate [ i ] = 1.0f;
     }
+#endif
 
-#else
-#   ifdef __FreeBSD__
-    int   buttons[ _JS_MAX_AXES ];
-    float axes[ _JS_MAX_AXES ];
-    int   noargs, in_no_axes;
-    char  joyfname[ 1024 ];
-    FILE* joyfile;
-#   else
-#       ifndef JS_NEW
-    int counter;
-#       endif
-#   endif
-    int i;
-
-    /*
-     * Default for older Linux systems.
-     */
-    joy->num_axes    =  2;
-    joy->num_buttons = 32;
+#if TARGET_HOST_UNIX_X11
+#if defined( __FreeBSD__ ) || defined( __NetBSD__ )
+    for( i = 0; i < _JS_MAX_AXES; i++ )
+        joy->os->cache_axes[ i ] = 0.0f;
 
-#   ifdef JS_NEW
-    for( i=0 ; i<_JS_MAX_AXES ; i++ )
-        joy->tmp_axes[ i ] = 0.0f ;
+    joy->os->cache_buttons = 0;
 
-    joy->tmp_buttons = 0 ;
-#   endif
+    joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
 
-    joy->fd = open( joy->fname, O_RDONLY );
+    if( joy->os->fd < 0 && errno == EACCES )
+        fgWarning ( "%s exists but is not readable by you\n", joy->os->fname );
 
-    joy->error = (joy->fd < 0);
+    joy->error =( joy->os->fd < 0 );
 
     if( joy->error )
         return;
-/*
- * XXX All BSDs should share this?
- */
-#   ifdef __FreeBSD__
-    fghJoystickRawRead(joy, buttons, axes );
-    joy->error = axes[ 0 ] < -1000000000.0f;
-    if( joy->error )
-        return;
 
-    sprintf( joyfname, "%s/.joy%drc", getenv( "HOME" ), joy->id );
+    joy->num_axes = 0;
+    joy->num_buttons = 0;
+    if( joy->os->is_analog )
+    {
+        FILE *joyfile;
+        char joyfname[ 1024 ];
+        int noargs, in_no_axes;
+
+        float axes [ _JS_MAX_AXES ];
+        int buttons[ _JS_MAX_AXES ];
+
+        joy->num_axes    =  2;
+        joy->num_buttons = 32;
+
+        fghJoystickRawRead( joy, buttons, axes );
+        joy->error = axes[ 0 ] < -1000000000.0f;
+        if( joy->error )
+            return;
 
-    joyfile = fopen( joyfname, "r" );
-    joy->error =( joyfile == NULL );
-    if( joy->error )
-      return;
+        sprintf( joyfname, "%s/.joy%drc", getenv( "HOME" ), joy->id );
 
-    noargs = fscanf(
-        joyfile, "%d%f%f%f%f%f%f",
-        &in_no_axes,
-        &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
-        &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ]
-    );
+        joyfile = fopen( joyfname, "r" );
+        joy->error =( joyfile == NULL );
+        if( joy->error )
+            return;
 
-    joy->error =( noargs != 7 ) || ( in_no_axes != _JS_MAX_AXES );
-    fclose( joyfile );
-    if( joy->error )
+        noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
+                         &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
+                         &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
+        joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
+        fclose( joyfile );
+        if( joy->error )
+            return;
+
+        for( i = 0; i < _JS_MAX_AXES; i++ )
+        {
+            joy->dead_band[ i ] = 0.0f;
+            joy->saturate [ i ] = 1.0f;
+        }
+
+        return;    /* End of analog code */
+    }
+
+#    ifdef HAVE_USB_JS
+    if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
+                                    &joy->num_buttons ) )
+    {
+        close( joy->os->fd );
+        joy->error = GL_TRUE;
         return;
+    }
+
+    cp = strrchr( joy->os->fname, '/' );
+    if( cp )
+    {
+        if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
+            0 )
+            strcpy( joy->name, &cp[1] );
+    }
+
+    if( joy->num_axes > _JS_MAX_AXES )
+        joy->num_axes = _JS_MAX_AXES;
 
     for( i = 0; i < _JS_MAX_AXES; i++ )
     {
+        /* We really should get this from the HID, but that data seems
+         * to be quite unreliable for analog-to-USB converters. Punt for
+         * now.
+         */
+        if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
+        {
+            joy->max   [ i ] = 1.0f;
+            joy->center[ i ] = 0.0f;
+            joy->min   [ i ] = -1.0f;
+        }
+        else
+        {
+            joy->max   [ i ] = 255.0f;
+            joy->center[ i ] = 127.0f;
+            joy->min   [ i ] = 0.0f;
+        }
+
         joy->dead_band[ i ] = 0.0f;
-        joy->saturate [ i ] = 1.0f;
+        joy->saturate[ i ] = 1.0f;
     }
-#   else
+#    endif
+#endif
 
+#if defined( __linux__ )
     /*
-     * Set the correct number of axes for the linux driver
+     * Default for older Linux systems.
      */
-#       ifdef JS_NEW
+    joy->num_axes    =  2;
+    joy->num_buttons = 32;
 
-    ioctl( joy->fd, JSIOCGAXES   , &joy->num_axes    );
-    ioctl( joy->fd, JSIOCGBUTTONS, &joy->num_buttons );
-    fcntl( joy->fd, F_SETFL, O_NONBLOCK );
+#    ifdef JS_NEW
+    for( i = 0; i < _JS_MAX_AXES; i++ )
+        joy->tmp_axes[ i ] = 0.0f;
 
-#       endif
+    joy->tmp_buttons = 0;
+#    endif
+
+    joy->fd = open( joy->fname, O_RDONLY );
+
+    joy->error =( joy->fd < 0 );
+
+    if( joy->error )
+        return;
+
+    /*
+     * Set the correct number of axes for the linux driver
+     */
+#    ifdef JS_NEW
+    /* Melchior Franz's fixes for big-endian Linuxes since writing
+     *  to the upper byte of an uninitialized word doesn't work.
+     *  9 April 2003
+     */
+    ioctl( joy->fd, JSIOCGAXES, &u );
+    joy->num_axes = u;
+    ioctl( joy->fd, JSIOCGBUTTONS, &u );
+    joy->num_buttons = u;
+    ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
+    fcntl( joy->fd, F_SETFL, O_NONBLOCK );
+#    endif
 
     /*
      * The Linux driver seems to return 512 for all axes
@@ -495,79 +1510,150 @@
      *
      * PWO: shouldn't be that done somehow wiser on the kernel level?
      */
-#       ifndef JS_NEW
+#    ifndef JS_NEW
     counter = 0;
 
     do
-    { 
+    {
         fghJoystickRawRead( joy, NULL, joy->center );
         counter++;
     } while( !joy->error &&
              counter < 100 &&
              joy->center[ 0 ] == 512.0f &&
              joy->center[ 1 ] == 512.0f );
-   
-    if( counter >= 100 )
+
+    if ( counter >= 100 )
         joy->error = GL_TRUE;
-#       endif
+#    endif
 
     for( i = 0; i < _JS_MAX_AXES; i++ )
     {
-#       ifdef JS_NEW
+#    ifdef JS_NEW
         joy->max   [ i ] =  32767.0f;
         joy->center[ i ] =      0.0f;
         joy->min   [ i ] = -32767.0f;
-#       else
+#    else
         joy->max[ i ] = joy->center[ i ] * 2.0f;
         joy->min[ i ] = 0.0f;
-#       endif
-        joy->dead_band[ i ] = 0.0f ;
-        joy->saturate [ i ] = 1.0f ;
+#    endif
+        joy->dead_band[ i ] = 0.0f;
+        joy->saturate [ i ] = 1.0f;
     }
-#   endif
+#endif
 #endif
 }
 
 /*
- *
+ * This function replaces the constructor method in the JS library.
  */
 void fgJoystickInit( int ident )
 {
-    if( fgJoystick )
-        fgError( "illegal attemp to initialize joystick device" );
+    if( ident >= MAX_NUM_JOYSTICKS )
+      fgError( "Too large a joystick number" );
+
+    if( fgJoystick[ ident ] )
+        fgError( "illegal attempt to initialize joystick device" );
 
-    fgJoystick = ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
+    fgJoystick[ ident ] =
+        ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
 
-#ifdef WIN32
+    /* Set defaults */
+    fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
+    fgJoystick[ ident ]->error = GL_TRUE;
+
+#if TARGET_HOST_MACINTOSH
+    fgJoystick[ ident ]->id = ident;
+    sprintf( fgJoystick[ ident ]->fname, "/dev/js%d", ident ); /* FIXME */
+    fgJoystick[ ident ]->error = GL_FALSE;
+#endif
+
+#if TARGET_HOST_MAC_OSX
+    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( "%s", "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( "%s", "error getting device name" );
+        name[ 0 ] = '\0';
+    }
+#endif
+
+#if TARGET_HOST_WIN32
     switch( ident )
     {
     case 0:
-        fgJoystick->js_id = JOYSTICKID1;
-        fghJoystickOpen( fgJoystick );
+        fgJoystick[ ident ]->js_id = JOYSTICKID1;
+        fgJoystick[ ident ]->error = GL_FALSE;
         break;
     case 1:
-        fgJoystick->js_id = JOYSTICKID2;
-        fghJoystickOpen( fgJoystick );
+        fgJoystick[ ident ]->js_id = JOYSTICKID2;
+        fgJoystick[ ident ]->error = GL_FALSE;
         break;
     default:
-        fgJoystick->num_axes = 0;
-        fgJoystick->error = GL_TRUE;
-        break;
+        fgJoystick[ ident ]->num_axes = 0;
+        fgJoystick[ ident ]->error = GL_TRUE;
+        return;
     }
-#else
-
-/*
- * XXX All BSDs should share this code?
- */
-#   ifdef __FreeBSD__
-    fgJoystick->id = ident;
-    sprintf( fgJoystick->fname, "/dev/joy%d", ident );
-#   else
-    sprintf( fgJoystick->fname, "/dev/js%d", ident );
-#   endif
+#endif
 
-    fghJoystickOpen( fgJoystick );
+#if TARGET_HOST_UNIX_X11
+#    if defined( __FreeBSD__ ) || defined( __NetBSD__ )
+    fgJoystick[ ident ]->id = ident;
+    fgJoystick[ ident ]->error = GL_FALSE;
+
+    fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
+    memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
+    if( ident < USB_IDENT_OFFSET )
+        fgJoystick[ ident ]->os->is_analog = 1;
+    if( fgJoystick[ ident ]->os->is_analog )
+        sprintf( fgJoystick[ ident ]->os->fname, "%s%d", AJSDEV, ident );
+    else
+        sprintf( fgJoystick[ ident ]->os->fname, "%s%d", UHIDDEV,
+                 ident - USB_IDENT_OFFSET );
+#    elif defined( __linux__ )
+    fgJoystick[ ident ]->id = ident;
+    fgJoystick[ ident ]->error = GL_FALSE;
+
+    sprintf( fgJoystick[ident]->fname, "/dev/input/js%d", ident );
+
+    if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
+        sprintf( fgJoystick[ ident ]->fname, "/dev/js%d", ident );
+#    endif
 #endif
+
+    fghJoystickOpen( fgJoystick[ ident  ] );
 }
 
 /*
@@ -575,16 +1661,52 @@
  */
 void fgJoystickClose( void )
 {
-    if( !fgJoystick )
-        fgError( "illegal attempt to deinitialize joystick device" );
+    int ident ;
+    for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+    {
+        if( fgJoystick[ ident ] )
+        {
+
+#if TARGET_HOST_MACINTOSH
+            ISpSuspend( );
+            ISpStop( );
+            ISpShutdown( );
+#endif
+
+#if TARGET_HOST_MAC_OSX
+            ( *( fgJoystick[ ident ]->hidDev ) )->
+                close( fgJoystick[ ident ]->hidDev );
+#endif
 
-#ifndef WIN32
-    if( ! fgJoystick->error )
-        close( fgJoystick->fd );
+#if TARGET_HOST_WIN32
+            /* Do nothing special */
 #endif
 
-    free( fgJoystick );
-    fgJoystick = NULL;  /* show joystick has been deinitialized */
+#if TARGET_HOST_UNIX_X11
+#if defined( __FreeBSD__ ) || defined( __NetBSD__ )
+            if( fgJoystick[ident]->os )
+            {
+                if( ! fgJoystick[ ident ]->error )
+                    close( fgJoystick[ ident ]->os->fd );
+#ifdef HAVE_USB_JS
+                if( fgJoystick[ ident ]->os->hids )
+                    free (fgJoystick[ ident ]->os->hids);
+                if( fgJoystick[ ident ]->os->hid_data_buf )
+                    free( fgJoystick[ ident ]->os->hid_data_buf );
+#endif
+                free( fgJoystick[ident]->os );
+            }
+#endif
+
+            if( ! fgJoystick[ident]->error )
+                close( fgJoystick[ ident ]->fd );
+#endif
+
+            free( fgJoystick[ ident ] );
+            fgJoystick[ ident ] = NULL;
+            /* show joystick has been deinitialized */
+        }
+    }
 }
 
 /*
@@ -595,64 +1717,89 @@
 {
     float axes[ _JS_MAX_AXES ];
     int buttons;
+    int ident;
 
-    freeglut_return_if_fail( fgJoystick );
     freeglut_return_if_fail( window );
     freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
 
-    fghJoystickRead( fgJoystick, &buttons, axes );
+    for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+    {
+        if( fgJoystick[ident] )
+        {
+            fghJoystickRead( fgJoystick[ident], &buttons, axes );
 
-    INVOKE_WCB( *window, Joystick,
-                ( buttons,
-                  (int) (axes[ 0 ] * 1000.0f ),
-                  (int) (axes[ 1 ] * 1000.0f ),
-                  (int) (axes[ 2 ] * 1000.0f ) )
-    );
-    
-    /*
-     * fgSetWindow (window);
-     * window->Callbacks.Joystick(
-     *   buttons,
-     *   (int) (axes[ 0 ] * 1000.0f),
-     *   (int) (axes[ 1 ] * 1000.0f),
-     *   (int) (axes[ 2 ] * 1000.0f)
-     * );
-     */
+            if( !fgJoystick[ident]->error )
+                INVOKE_WCB( *window, Joystick,
+                            ( buttons,
+                              (int) ( axes[ 0 ] * 1000.0f ),
+                              (int) ( axes[ 1 ] * 1000.0f ),
+                              (int) ( axes[ 2 ] * 1000.0f ) )
+                );
+        }
+    }
 }
 
 /*
  * PWO: These jsJoystick class methods have not been implemented.
  *      We might consider adding such functions to freeglut-2.0.
  */
-#if 0
-int  getNumAxes ()
-    { return num_axes; }
-int  notWorking ()
-    { return error; }
-
-float getDeadBand ( int axis )
-    { return dead_band [ axis ]; }
-void  setDeadBand ( int axis, float db )
-    { dead_band [ axis ] = db; }
-
-float getSaturation ( int axis )
-    { return saturate [ axis ]; }
-void  setSaturation ( int axis, float st )
-    { saturate [ axis ] = st; }
-
-void setMinRange ( float *axes )
-    { memcpy ( min   , axes, num_axes * sizeof(float) ); }
-void setMaxRange ( float *axes )
-    { memcpy ( max   , axes, num_axes * sizeof(float) ); }
-void setCenter   ( float *axes )
-    { memcpy ( center, axes, num_axes * sizeof(float) ); }
-
-void getMinRange ( float *axes )
-    { memcpy ( axes, min   , num_axes * sizeof(float) ); }
-void getMaxRange ( float *axes )
-    { memcpy ( axes, max   , num_axes * sizeof(float) ); }
-void getCenter   ( float *axes )
-    { memcpy ( axes, center, num_axes * sizeof(float) ); }
-#endif
+int  glutJoystickGetNumAxes( int ident )
+{
+    return fgJoystick[ ident ]->num_axes;
+}
+int  glutJoystickNotWorking( int ident )
+{
+    return fgJoystick[ ident ]->error;
+}
+
+float glutJoystickGetDeadBand( int ident, int axis )
+{
+    return fgJoystick[ ident ]->dead_band [ axis ];
+}
+void  glutJoystickSetDeadBand( int ident, int axis, float db )
+{
+    fgJoystick[ ident ]->dead_band[ axis ] = db;
+}
+
+float glutJoystickGetSaturation( int ident, int axis )
+{
+    return fgJoystick[ ident ]->saturate[ axis ];
+}
+void  glutJoystickSetSaturation( int ident, int axis, float st )
+{
+    fgJoystick[ ident ]->saturate [ axis ] = st;
+}
+
+void glutJoystickSetMinRange( int ident, float *axes )
+{
+    memcpy( fgJoystick[ ident ]->min, axes,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickSetMaxRange( int ident, float *axes )
+{
+    memcpy( fgJoystick[ ident ]->max, axes,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickSetCenter( int ident, float *axes )
+{
+    memcpy( fgJoystick[ ident ]->center, axes,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+
+void glutJoystickGetMinRange( int ident, float *axes )
+{
+    memcpy( axes, fgJoystick[ ident ]->min,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickGetMaxRange( int ident, float *axes )
+{
+    memcpy( axes, fgJoystick[ ident ]->max,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
+void glutJoystickGetCenter( int ident, float *axes )
+{
+    memcpy( axes, fgJoystick[ ident ]->center,
+            fgJoystick[ ident ]->num_axes * sizeof( float ) );
+}
 
 /*** END OF FILE ***/
===================================================================
RCS file: /cvsroot/freeglut/freeglut/freeglut/src/freeglut_main.c,v
retrieving revision 1.78
retrieving revision 1.93
diff -u -r1.78 -r1.93
--- freeglut/freeglut/freeglut/src/freeglut_main.c	2003/12/11 22:13:02	1.78
+++ freeglut/freeglut/freeglut/src/freeglut_main.c	2004/03/14 04:36:02	1.93
@@ -29,7 +29,7 @@
 #include "config.h"
 #endif
 
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 #include <limits.h>
@@ -180,14 +180,14 @@
 
         fgSetWindow( window );
 
-        fghReshapeWindowByHandle( 
+        fghReshapeWindowByHandle(
             window->Window.Handle,
             window->State.Width,
             window->State.Height
         );
 
         window->State.NeedToResize = GL_FALSE;
-        fgSetWindow ( current_window );
+        fgSetWindow( current_window );
     }
 
     INVOKE_WCB( *window, Display, ( ) );
@@ -199,40 +199,25 @@
 static void fghcbDisplayWindow( SFG_Window *window,
                                 SFG_Enumerator *enumerator )
 {
-    if( window->State.Redisplay &&
-        window->State.Visible )
+    if( window->State.NeedToResize )
     {
-        /*
-         * XXX Resizing should *not* depend upon whether there
-         * XXX is a pending redisplay flag, as far as I can tell.
-         * XXX
-         * XXX Note, too, that the {NeedToResize} flag is a little
-         * XXX fuzzy in its meaning, since for WIN32, this also
-         * XXX means "we need to tell the application that the window has
-         * XXX changed size", while in X11, it only means "we need
-         * XXX to ask the window system to resize the window.
-         * XXX Splitting the flag's meaning might be desirable, but
-         * XXX that could complicate the code more.  (On X11, the
-         * XXX user callback is called as soon as the event is
-         * XXX discovered, but resizing the window is postponed
-         * XXX until after other events.)
-         */
-        if( window->State.NeedToResize )
-        {
-            SFG_Window *current_window = fgStructure.Window;
+        SFG_Window *current_window = fgStructure.Window;
 
-            fgSetWindow( window );
+        fgSetWindow( window );
 
-            fghReshapeWindowByHandle( 
-                window->Window.Handle,
-                window->State.Width,
-                window->State.Height
-            );
+        fghReshapeWindowByHandle(
+            window->Window.Handle,
+            window->State.Width,
+            window->State.Height
+        );
 
-            window->State.NeedToResize = GL_FALSE;
-            fgSetWindow ( current_window );
-        }
+        window->State.NeedToResize = GL_FALSE;
+        fgSetWindow ( current_window );
+    }
 
+    if( window->State.Redisplay &&
+        window->State.Visible )
+    {
         window->State.Redisplay = GL_FALSE;
 
 #if TARGET_HOST_UNIX_X11
@@ -244,7 +229,7 @@
         }
 #elif TARGET_HOST_WIN32
         RedrawWindow(
-            window->Window.Handle, NULL, NULL, 
+            window->Window.Handle, NULL, NULL,
             RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW
         );
 #endif
@@ -303,10 +288,11 @@
 static void fghCheckTimers( void )
 {
     long checkTime = fgElapsedTime( );
-    SFG_Timer *timer;
 
-    while( timer = fgState.Timers.First )
+    while( fgState.Timers.First )
     {
+        SFG_Timer *timer = fgState.Timers.First;
+
         if( timer->TriggerTime > checkTime )
             break;
 
@@ -393,20 +379,12 @@
  * Indicates whether Joystick events are being used by ANY window.
  *
  * The current mechanism is to walk all of the windows and ask if
- * there is a joystick callback.  Certainly in some cases, maybe
- * in all cases, the joystick is attached to the system and accessed
- * from ONE point by GLUT/freeglut, so this is not the right way,
- * in general, to do this.  However, the Joystick code is segregated
- * in its own little world, so we can't access the information that
- * we need in order to do that nicely.
- *
- * Some alternatives:
- *  * Store Joystick data into freeglut global state.
- *  * Provide NON-static functions or data from Joystick *.c file.
+ * there is a joystick callback.  We have a short-circuit early
+ * return if we find any joystick handler registered.
  *
- * Basically, the RIGHT way to do this requires knowing something
- * about the Joystick.  Right now, the Joystick code is behind
- * an opaque wall.
+ * The real way to do this is to make use of the glutTimer() API
+ * to more cleanly re-implement the joystick API.  Then, this code
+ * and all other "joystick timer" code can be yanked.
  *
  */
 static void fgCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e)
@@ -434,7 +412,7 @@
         e->data = w;
     }
     fgEnumSubWindows( w, fgHavePendingRedisplaysCallback, e );
-}        
+}
 static int fgHavePendingRedisplays (void)
 {
     SFG_Enumerator enumerator;
@@ -464,31 +442,44 @@
  */
 static void fgSleepForEvents( void )
 {
-#if TARGET_HOST_UNIX_X11
-    fd_set fdset;
-    int err;
-    int socket;
-    struct timeval wait;
-    long msec;    
-    
+    long msec;
+
     if( fgState.IdleCallback || fgHavePendingRedisplays( ) )
         return;
-    socket = ConnectionNumber( fgDisplay.Display );
-    FD_ZERO( &fdset );
-    FD_SET( socket, &fdset );
-    
+
     msec = fgNextTimer( );
-    if( fgHaveJoystick( ) )
-        msec = MIN( msec, 10 );
+    if( fgHaveJoystick( ) )     /* XXX Use GLUT timers for joysticks... */
+        msec = MIN( msec, 10 ); /* XXX Dumb; forces granularity to .01sec */
 
-    wait.tv_sec = msec / 1000;
-    wait.tv_usec = (msec % 1000) * 1000;
-    err = select( socket+1, &fdset, NULL, NULL, &wait );
-
-    if( -1 == err )
-        fgWarning ( "freeglut select() error: %d\n", errno );
-    
+#if TARGET_HOST_UNIX_X11
+    /*
+     * Possibly due to aggressive use of XFlush() and friends,
+     * it is possible to have our socket drained but still have
+     * unprocessed events.  (Or, this may just be normal with
+     * X, anyway?)  We do non-trivial processing of X events
+     * after tham in event-reading loop, in any case, so we
+     * need to allow that we may have an empty socket but non-
+     * empty event queue.
+     */
+    if( ! XPending( fgDisplay.Display ) )
+    {
+        fd_set fdset;
+        int err;
+        int socket;
+        struct timeval wait;
+
+        socket = ConnectionNumber( fgDisplay.Display );
+        FD_ZERO( &fdset );
+        FD_SET( socket, &fdset );
+        wait.tv_sec = msec / 1000;
+        wait.tv_usec = (msec % 1000) * 1000;
+        err = select( socket+1, &fdset, NULL, NULL, &wait );
+
+        if( -1 == err )
+            fgWarning ( "freeglut select() error: %d\n", errno );
+    }
 #elif TARGET_HOST_WIN32
+    MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLEVENTS );
 #endif
 }
 
@@ -506,7 +497,7 @@
         ret |= GLUT_ACTIVE_CTRL;
     if( event->xkey.state & Mod1Mask )
         ret |= GLUT_ACTIVE_ALT;
-    
+
     return ret;
 }
 #endif
@@ -549,7 +540,7 @@
              */
             if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow )
             {
-                GETWINDOW( xclient ); 
+                GETWINDOW( xclient );
 
                 fgDestroyWindow ( window );
 
@@ -607,6 +598,7 @@
         case DestroyNotify:
             /*
              * This is sent to confirm the XDestroyWindow call.
+             *
              * XXX WHY is this commented out?  Should we re-enable it?
              */
             /* fgAddToWindowDestroyList ( window ); */
@@ -621,12 +613,13 @@
              * XXX double-buffered does not respect viewport when we
              * XXX do a buffer-swap).
              *
-             * XXX GETWINDOW( xexpose );
-             * XXX fgSetWindow( window );
-             * XXX glutPostRedisplay( );
              */
             if( event.xexpose.count == 0 )
-                fghRedrawWindowByHandle( event.xexpose.window );
+            {
+                GETWINDOW( xexpose );
+                fgSetWindow( window );
+                glutPostRedisplay( );
+            }
             break;
 
         case MapNotify:
@@ -647,7 +640,7 @@
 
         case VisibilityNotify:
         {
-            GETWINDOW( xvisibility ); 
+            GETWINDOW( xvisibility );
             /*
              * XXX INVOKE_WCB() does this check for us.
              */
@@ -667,13 +660,13 @@
                 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
                 window->State.Visible = GL_TRUE;
                 break;
-                
+
             case VisibilityPartiallyObscured:
                 INVOKE_WCB( *window, WindowStatus,
                             ( GLUT_PARTIALLY_RETAINED ) );
                 window->State.Visible = GL_TRUE;
                 break;
-                
+
             case VisibilityFullyObscured:
                 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) );
                 window->State.Visible = GL_FALSE;
@@ -748,7 +741,7 @@
              */
             GETWINDOW( xbutton );
             GETMOUSE( xbutton );
-          
+
             /*
              * An X button (at least in XFree86) is numbered from 1.
              * A GLUT button is numbered from 0.
@@ -790,7 +783,7 @@
                     window->ActiveMenu->Window->State.MouseY =
                         event.xbutton.y_root - window->ActiveMenu->Y;
                 }
-                
+
                 /* In the menu, invoke the callback and deactivate the menu*/
                 if( fgCheckActiveMenu( window->ActiveMenu->Window,
                                        window->ActiveMenu ) )
@@ -890,7 +883,7 @@
                 int direction = -1;
                 if( button % 2 )
                     direction = 1;
-                
+
                 if( pressed )
                     INVOKE_WCB( *window, MouseWheel, ( wheel_number,
                                                        direction,
@@ -915,6 +908,34 @@
             GETWINDOW( xkey );
             GETMOUSE( xkey );
 
+            /* Detect auto repeated keys, if configured globally or per-window */
+
+            if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE )
+            {
+                if (event.type==KeyRelease)
+                {
+                    /*
+                     * Look at X11 keystate to detect repeat mode.
+                     * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs.
+                     */
+
+                    char keys[32];
+                    XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */
+
+                    if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) )
+                        window->State.KeyRepeating = GL_TRUE;
+                    else
+                        window->State.KeyRepeating = GL_FALSE;
+                }
+            }
+            else
+                window->State.KeyRepeating = GL_FALSE;
+
+            /* Cease processing this event if it is auto repeated */
+
+            if (window->State.KeyRepeating)
+                break;
+
             if( event.type == KeyPress )
             {
                 keyboard_cb = FETCH_WCB( *window, Keyboard );
@@ -1062,6 +1083,8 @@
  */
 void FGAPIENTRY glutMainLoop( void )
 {
+    int action;
+
 #if TARGET_HOST_WIN32
     SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ;
 #endif
@@ -1087,7 +1110,7 @@
             INVOKE_WCB( *window, Visibility, ( window->State.Visible ) );
             fgSetWindow( current_window );
         }
-        
+
         window = (SFG_Window *)window->Node.Next ;
     }
 #endif
@@ -1101,13 +1124,13 @@
         /*
          * Step through the list of windows, seeing if there are any
          * that are not menus
-         */ 
+         */
         for( window = ( SFG_Window * )fgStructure.Windows.First;
              window;
              window = ( SFG_Window * )window->Node.Next )
             if ( ! ( window->IsMenu ) )
                 break;
-        
+
         if( ! window )
             fgState.ExecState = GLUT_EXEC_STATE_STOP;
         else
@@ -1122,9 +1145,12 @@
     /*
      * When this loop terminates, destroy the display, state and structure
      * of a freeglut session, so that another glutInit() call can happen
+     *
+     * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it.
      */
+    action = fgState.ActionOnWindowClose;
     fgDeinitialize( );
-    if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
+    if( action == GLUT_ACTION_EXIT )
         exit( 0 );
 }
 
@@ -1225,19 +1251,25 @@
 
     case WM_SIZE:
         /*
-         * We got resized... But check if the window has been already added...
+         * If the window is visible, then it is the user manually resizing it.
+         * If it is not, then it is the system sending us a dummy resize with
+         * zero dimensions on a "glutIconifyWindow" call.
          */
-        window->State.NeedToResize = GL_TRUE;
-        window->State.Width  = LOWORD(lParam);
-        window->State.Height = HIWORD(lParam);
+        if( window->State.Visible )
+        {
+            window->State.NeedToResize = GL_TRUE;
+            window->State.Width  = LOWORD(lParam);
+            window->State.Height = HIWORD(lParam);
+        }
+
         break;
 #if 0
-    case WM_SETFOCUS: 
+    case WM_SETFOCUS:
         printf("WM_SETFOCUS: %p\n", window );
         lRet = DefWindowProc( hWnd, uMsg, wParam, lParam );
         break;
 
-    case WM_ACTIVATE: 
+    case WM_ACTIVATE:
         if (LOWORD(wParam) != WA_INACTIVE)
         {
             /* glutSetCursor( fgStructure.Window->State.Cursor ); */
@@ -1258,7 +1290,7 @@
          * XXX call glutSetCurdsor() instead of defining two macros
          * XXX and implementing a nested case in-line.
          */
-    case WM_SETCURSOR: 
+    case WM_SETCURSOR:
         /* Set the cursor AND change it for this window class. */
 #define MAP_CURSOR(a,b)                 \
     case a:                             \
@@ -1323,7 +1355,7 @@
     {
         window->State.MouseX = LOWORD( lParam );
         window->State.MouseY = HIWORD( lParam );
-        
+
         if ( window->ActiveMenu )
         {
             window->State.Redisplay = GL_TRUE;
@@ -1392,10 +1424,13 @@
         }
 
         if( GetSystemMetrics( SM_SWAPBUTTON ) )
+        {
             if( button == GLUT_LEFT_BUTTON )
                 button = GLUT_RIGHT_BUTTON;
-            else if( button == GLUT_RIGHT_BUTTON )
-                button = GLUT_LEFT_BUTTON;
+            else
+                if( button == GLUT_RIGHT_BUTTON )
+                    button = GLUT_LEFT_BUTTON;
+        }
 
         if( button == -1 )
             return DefWindowProc( hWnd, uMsg, lParam, wParam );
@@ -1558,11 +1593,11 @@
         int keypress = -1;
         POINT mouse_pos ;
 
-        if( fgState.IgnoreKeyRepeat && (lParam & KF_REPEAT) )
+        if( fgState.IgnoreKeyRepeat && (HIWORD(lParam) & KF_REPEAT) )
             break;
 
         /*
-         * Remember the current modifiers state. This is done here in order 
+         * Remember the current modifiers state. This is done here in order
          * to make sure the VK_DELETE keyboard callback is executed properly.
          */
         fgState.Modifiers = fgGetWin32Modifiers( );
@@ -1628,7 +1663,7 @@
         POINT mouse_pos;
 
         /*
-         * Remember the current modifiers state. This is done here in order 
+         * Remember the current modifiers state. This is done here in order
          * to make sure the VK_DELETE keyboard callback is executed properly.
          */
         fgState.Modifiers = fgGetWin32Modifiers( );
@@ -1681,9 +1716,9 @@
         {
             BYTE state[ 256 ];
             WORD code[ 2 ];
-            
+
             GetKeyboardState( state );
-            
+
             if( ToAscii( wParam, 0, state, code, 0 ) == 1 )
                 wParam=code[ 0 ];
 
@@ -1707,7 +1742,7 @@
     case WM_SYSCHAR:
     case WM_CHAR:
     {
-        if( fgState.IgnoreKeyRepeat && (lParam & KF_REPEAT) )
+        if( fgState.IgnoreKeyRepeat && (HIWORD(lParam) & KF_REPEAT) )
             break;
 
         fgState.Modifiers = fgGetWin32Modifiers( );
===================================================================
RCS file: /cvsroot/freeglut/freeglut/freeglut/src/freeglut_misc.c,v
retrieving revision 1.10
retrieving revision 1.12
diff -u -r1.10 -r1.12
--- freeglut/freeglut/freeglut/src/freeglut_misc.c	2003/11/21 21:15:58	1.10
+++ freeglut/freeglut/freeglut/src/freeglut_misc.c	2004/03/14 04:36:02	1.12
@@ -29,7 +29,7 @@
 #include "config.h"
 #endif
 
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
@@ -93,49 +93,43 @@
 }
 
 /*
- * Turns the ignore key auto repeat feature on and off
- *
- * DEPRECATED 11/4/02 - Do not use
+ * Control the auto-repeat of keystrokes to the current window
  */
 void FGAPIENTRY glutIgnoreKeyRepeat( int ignore )
 {
-    fgState.IgnoreKeyRepeat = ignore ? GL_TRUE : GL_FALSE;
+    freeglut_assert_ready;
+    freeglut_assert_window;
+
+    fgStructure.Window->State.IgnoreKeyRepeat = ignore ? GL_TRUE : GL_FALSE;
 }
 
 /*
- * Hints the window system whether to generate key auto repeat, or not.
- * This is evil.
+ * Set global auto-repeat of keystrokes
  *
- * XXX Is this also deprecated as of 20021104?
+ * RepeatMode should be either:
+ *    GLUT_KEY_REPEAT_OFF
+ *    GLUT_KEY_REPEAT_ON
+ *    GLUT_KEY_REPEAT_DEFAULT
  */
 void FGAPIENTRY glutSetKeyRepeat( int repeatMode )
 {
-#if TARGET_HOST_UNIX_X11
-
     freeglut_assert_ready;
 
     switch( repeatMode )
     {
-    case GLUT_KEY_REPEAT_OFF:   XAutoRepeatOff( fgDisplay.Display ); break;
-    case GLUT_KEY_REPEAT_ON:    XAutoRepeatOn( fgDisplay.Display );  break;
-    case GLUT_KEY_REPEAT_DEFAULT:
-        {
-            XKeyboardState keyboardState;
+    case GLUT_KEY_REPEAT_OFF:
+    case GLUT_KEY_REPEAT_ON:
+     fgState.KeyRepeat = repeatMode;
+     break;
 
-            XGetKeyboardControl( fgDisplay.Display, &keyboardState );
-            glutSetKeyRepeat(
-                keyboardState.global_auto_repeat == AutoRepeatModeOn ?
-                GLUT_KEY_REPEAT_ON : GLUT_KEY_REPEAT_OFF
-            );
-        }
-        break;
+    case GLUT_KEY_REPEAT_DEFAULT:
+     fgState.KeyRepeat = GLUT_KEY_REPEAT_ON;
+     break;
 
     default:
         fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode);
         break;
     }
-
-#endif
 }
 
 /*
===================================================================
RCS file: /cvsroot/freeglut/freeglut/freeglut/src/freeglut_state.c,v
retrieving revision 1.18
retrieving revision 1.22
diff -u -r1.18 -r1.22
--- freeglut/freeglut/freeglut/src/freeglut_state.c	2003/11/21 21:15:58	1.18
+++ freeglut/freeglut/freeglut/src/freeglut_state.c	2004/03/14 04:36:02	1.22
@@ -29,7 +29,7 @@
 #include "config.h"
 #endif
 
-#include "../include/GL/freeglut.h"
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
@@ -507,7 +507,7 @@
 
     case GLUT_HAS_MOUSE:
         /*
-         * The Windows can be booted without a mouse. 
+         * The Windows can be booted without a mouse.
          * It would be nice to have this reported.
          */
         return GetSystemMetrics( SM_MOUSEPRESENT );
@@ -522,6 +522,7 @@
 
     case GLUT_JOYSTICK_POLL_RATE:
     case GLUT_HAS_JOYSTICK:
+    case GLUT_OWNS_JOYSTICK:
     case GLUT_JOYSTICK_BUTTONS:
     case GLUT_JOYSTICK_AXES:
         /*
@@ -541,7 +542,7 @@
         return 0;
 
     case GLUT_DEVICE_IGNORE_KEY_REPEAT:
-        return fgState.IgnoreKeyRepeat;
+        return fgStructure.Window ? fgStructure.Window->State.IgnoreKeyRepeat : 0;
 
     case GLUT_DEVICE_KEY_REPEAT:
         /*

Attachment: signature.asc
Description: Digital signature


Reply to: