Joe Krahn\'s input (dials) device implementation.
[freeglut] / src / freeglut_joystick.c
index 1115076..b6fcdbc 100644 (file)
  *  Many thanks for Steve Baker for permission to pull from that library.
  */
 
-#if defined( __FreeBSD__ ) || defined( __NetBSD__ )
-#    include <sys/param.h>
-#endif
-
-#ifdef HAVE_CONFIG_H
-#    include "config.h"
-#endif
-
 #include <GL/freeglut.h>
 #include "freeglut_internal.h"
+#if HAVE_SYS_PARAM_H
+#    include <sys/param.h>
+#endif
 
 /*
  * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
  * interspersed
  */
-#define _JS_MAX_BUTTONS 32
 
+/* XXX It might be better to poll the operating system for the numbers of buttons and
+ * XXX axes and then dynamically allocate the arrays.
+ */
+#define _JS_MAX_BUTTONS 32
 
 #if TARGET_HOST_MACINTOSH
 #    define _JS_MAX_AXES  9
 #    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 HAVE_SYS_IOCTL_H
+#        include <sys/ioctl.h>
+#    endif
+#    if HAVE_FCNTL_H
+#        include <fcntl.h>
+#    endif
+#    include <errno.h>
 #    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
 #        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 */
@@ -241,8 +239,7 @@ static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
         return 1;
     } else if (errno == EACCES) {
       if (!protection_warned) {
-        fprintf(stderr, "Can't open %s for read!\n",
-          buf);
+        fgWarning ( "Can't open %s for read!", buf );
         protection_warned = 1;
       }
     }
@@ -263,7 +260,7 @@ static int fghJoystickInitializeHID(struct os_specific_s *os,
 
     if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
     {
-        fprintf( stderr, "error: %s: %s", os->fname, strerror( errno ) );
+        fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
         return FALSE;
     }
 
@@ -273,8 +270,7 @@ static int fghJoystickInitializeHID(struct os_specific_s *os,
         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 ) );
+            fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
             return FALSE;
         }
 
@@ -440,7 +436,6 @@ static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object
 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
 /* callback for CFArrayApply */
 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
-static void fghJoystickParseElement ( SFG_Joystick* joy, CFDictionaryRef element );
 
 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
@@ -452,7 +447,6 @@ static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
  * The static joystick structure pointer
  */
 #define MAX_NUM_JOYSTICKS  2
-static int fgNumberOfJoysticks = 0;
 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
 
 
@@ -724,7 +718,7 @@ static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
             break;
 
         default:
-            fgWarning ( "%s", "PLIB_JS: Unrecognised /dev/js return!?!" );
+            fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
 
             /* use the old values */
 
@@ -851,7 +845,7 @@ static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
 
     rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
     if (rv != kIOReturnSuccess || !hidIterator) {
-      fgWarning( "%s", "no joystick (HID) devices found" );
+      fgWarning( "no joystick (HID) devices found" );
       return;
     }
 
@@ -894,13 +888,13 @@ static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object
 
     rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
     if (rv != kIOReturnSuccess) {
-        fgWarning ( "%s", "error getting device entry parent");
+        fgWarning ( "error getting device entry parent");
         return NULL;
     }
 
     rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
     if (rv != kIOReturnSuccess) {
-        fgWarning ( "%s", "error getting device entry parent 2");
+        fgWarning ( "error getting device entry parent 2");
         return NULL;
     }
 #endif
@@ -908,7 +902,7 @@ static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object
     rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
         &cfProperties, kCFAllocatorDefault, kNilOptions);
     if (rv != kIOReturnSuccess || !cfProperties) {
-        fgWarning ( "%s", "error getting device properties");
+        fgWarning ( "error getting device properties");
         return NULL;
     }
 
@@ -928,73 +922,15 @@ static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, voi
 /** element enumerator function : pass NULL for top-level*/
 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
 {
-      assert(CFGetTypeID(element) == CFArrayGetTypeID());
+      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 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;
@@ -1239,7 +1175,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
 #if TARGET_HOST_MAC_OSX
     if( joy->id >= numDevices )
     {
-        fgWarning( "%s", "device index out of range in fgJoystickOpen()" );
+        fgWarning( "device index out of range in fgJoystickOpen()" );
         return;
     }
 
@@ -1251,7 +1187,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
 
     if( rv != kIOReturnSuccess )
     {
-        fgWarning( "%s", "error creating plugin for io device" );
+        fgWarning( "error creating plugin for io device" );
         return;
     }
 
@@ -1262,7 +1198,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
     );
 
     if( pluginResult != S_OK )
-        fgWarning ( "%s", "QI-ing IO plugin to HID Device interface failed" );
+        fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
 
     ( *plugin )->Release( plugin ); /* don't leak a ref */
     if( joy->hidDev == NULL )
@@ -1358,7 +1294,7 @@ static void fghJoystickOpen( SFG_Joystick* joy )
     joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
 
     if( joy->os->fd < 0 && errno == EACCES )
-        fgWarning ( "%s exists but is not readable by you\n", joy->os->fname );
+        fgWarning ( "%s exists but is not readable by you", joy->os->fname );
 
     joy->error =( joy->os->fd < 0 );
 
@@ -1530,13 +1466,13 @@ static void fghJoystickOpen( SFG_Joystick* joy )
 /*
  * This function replaces the constructor method in the JS library.
  */
-void fgJoystickInit( int ident )
+static void fghJoystickInit( int ident )
 {
     if( ident >= MAX_NUM_JOYSTICKS )
-      fgError( "Too large a joystick number" );
+      fgError( "Too large a joystick number: %d", ident );
 
     if( fgJoystick[ ident ] )
-        fgError( "illegal attempt to initialize joystick device" );
+        fgError( "illegal attempt to initialize joystick device again" );
 
     fgJoystick[ ident ] =
         ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
@@ -1566,7 +1502,7 @@ void fgJoystickInit( int ident )
         IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
         if( rv != kIOReturnSuccess )
         {
-            fgWarning( "%s", "error getting master Mach port" );
+            fgWarning( "error getting master Mach port" );
             return;
         }
         fghJoystickFindDevices( masterPort );
@@ -1589,7 +1525,7 @@ void fgJoystickInit( int ident )
         !CFStringGetCString( ( CFStringRef )ref, name, 128,
                              CFStringGetSystemEncoding( ) ) )
     {
-        fgWarning( "%s", "error getting device name" );
+        fgWarning( "error getting device name" );
         name[ 0 ] = '\0';
     }
 #endif
@@ -1641,6 +1577,21 @@ void fgJoystickInit( int 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 )
@@ -1724,63 +1675,102 @@ void fgJoystickPollWindow( SFG_Window* window )
 }
 
 /*
- * PWO: These jsJoystick class methods have not been implemented.
+ * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
+ */
+int fgJoystickDetect( void )
+{
+    int ident;
+
+    fgInitialiseJoysticks ();
+
+    if ( !fgJoystick )
+        return 0;
+
+    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 ) );
 }