freeglut_joystick.c
上传用户:gb3593
上传日期:2022-01-07
资源大小:3028k
文件大小:54k
- /*
- * freeglut_joystick.c
- *
- * Joystick handling code
- *
- * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
- * Written by Steve Baker, <sjbaker1@airmail.net>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- /*
- * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
- *
- * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
- * Many thanks for Steve Baker for permission to pull from that library.
- */
- #include <GL/freeglut.h>
- #include "freeglut_internal.h"
- #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
- */
- /* 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
- # 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_MS_WINDOWS && !defined(_WIN32_WCE)
- # define _JS_MAX_AXES 8
- # include <windows.h>
- # include <mmsystem.h>
- # include <regstr.h>
- #endif
- #if TARGET_HOST_POSIX_X11
- # define _JS_MAX_AXES 16
- # if HAVE_SYS_IOCTL_H
- # include <sys/ioctl.h>
- # endif
- # if HAVE_FCNTL_H
- # include <fcntl.h>
- # endif
- # if HAVE_ERRNO
- # include <errno.h>
- # endif
- # if defined(__FreeBSD__) || defined(__NetBSD__)
- /* XXX The below hack is done until freeglut's autoconf is updated. */
- # define HAVE_USB_JS 1
- # if defined(__FreeBSD__)
- # 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
- # if defined(__linux__)
- # 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.
- */
- static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
- {
- struct usb_device_info di;
- int i, a;
- char *cp;
- for (a = 1; a < USB_MAX_DEVICES; a++) {
- di.udi_addr = a;
- if (ioctl(f, USB_DEVICEINFO, &di) != 0)
- return NULL;
- for (i = 0; i < USB_MAX_DEVNAMES; i++)
- if (di.udi_devnames[i][0] &&
- strcmp(di.udi_devnames[i], dev) == 0) {
- cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
- strcpy(cp, di.udi_vendor);
- strcat(cp, " ");
- strcat(cp, di.udi_product);
- strncpy(out, cp, outlen - 1);
- out[outlen - 1] = 0;
- free( cp );
- return out;
- }
- }
- return NULL;
- }
- static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
- {
- int i, f;
- char buf[50];
- char *cp;
- static int protection_warned = 0;
- for (i = 0; i < 16; i++) {
- snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
- f = open(buf, O_RDONLY);
- if (f >= 0) {
- cp = fghJoystickWalkUSBdev(f, name, out, outlen);
- close(f);
- if (cp)
- return 1;
- }
- #if HAVE_ERRNO
- else if (errno == EACCES) {
- if (!protection_warned) {
- fgWarning ( "Can't open %s for read!", buf );
- protection_warned = 1;
- }
- }
- #endif
- }
- return 0;
- }
- static int fghJoystickInitializeHID(struct os_specific_s *os,
- int *num_axes, int *num_buttons)
- {
- int size, is_joystick;
- # ifdef HAVE_USBHID_H
- int report_id = 0;
- # endif
- struct hid_data *d;
- struct hid_item h;
- report_desc_t rd;
- if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
- {
- #if HAVE_ERRNO
- fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
- #else
- fgWarning ( "error: %s", os->fname );
- #endif
- return FALSE;
- }
- os->hids = NULL;
- # ifdef HAVE_USBHID_H
- if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
- {
- /*** XXX {report_id} may not be the right variable? ***/
- #if HAVE_ERRNO
- fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
- #else
- fgWarning ( "error: %s%d", UHIDDEV, report_id );
- #endif
- return FALSE;
- }
- size = hid_report_size( rd, hid_input, report_id );
- # else
- size = hid_report_size( rd, 0, hid_input );
- # endif
- os->hid_data_buf = calloc( 1, size );
- os->hid_dlen = size;
- is_joystick = 0;
- # ifdef HAVE_USBHID_H
- d = hid_start_parse( rd, 1 << hid_input, report_id );
- # else
- d = hid_start_parse( rd, 1 << hid_input );
- # endif
- while( hid_get_item( d, &h ) )
- {
- int usage, page, interesting_hid;
- page = HID_PAGE( h.usage );
- usage = HID_USAGE( h.usage );
- /* This test is somewhat too simplistic, but this is how MicroSoft
- * does, so I guess it works for all joysticks/game pads. */
- is_joystick = is_joystick ||
- ( h.kind == hid_collection &&
- page == HUP_GENERIC_DESKTOP &&
- ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
- if( h.kind != hid_input )
- continue;
- if( !is_joystick )
- continue;
- interesting_hid = TRUE;
- if( page == HUP_GENERIC_DESKTOP )
- {
- switch( usage )
- {
- case HUG_X:
- case HUG_RX:
- case HUG_Y:
- case HUG_RY:
- case HUG_Z:
- case HUG_RZ:
- case HUG_SLIDER:
- if( *num_axes < _JS_MAX_AXES )
- {
- os->axes_usage[ *num_axes ] = usage;
- ( *num_axes )++;
- }
- break;
- case HUG_HAT_SWITCH:
- /* Allocate two axes for a hat */
- if( *num_axes + 1 < _JS_MAX_AXES )
- {
- os->axes_usage[ *num_axes ] = usage;
- (*num_axes)++;
- os->axes_usage[ *num_axes ] = usage;
- (*num_axes)++;
- }
- break;
- default:
- interesting_hid = FALSE;
- break;
- }
- }
- else if( page == HUP_BUTTON )
- {
- interesting_hid = ( usage > 0 ) &&
- ( usage <= _JS_MAX_BUTTONS );
- if( interesting_hid && usage - 1 > *num_buttons )
- *num_buttons = usage - 1;
- }
- if( interesting_hid )
- {
- h.next = os->hids;
- os->hids = calloc( 1, sizeof ( struct hid_item ) );
- *os->hids = h;
- }
- }
- hid_end_parse( d );
- return os->hids != NULL;
- }
- # endif
- #endif
- /*
- * 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
- {
- #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
- #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
- JOYCAPS jsCaps;
- JOYINFOEX js;
- UINT js_id;
- #endif
- #if TARGET_HOST_POSIX_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 ];
- # else
- struct JS_DATA_TYPE js;
- # endif
- char fname [ 128 ];
- int fd;
- #endif
- int id;
- GLboolean error;
- char name [ 128 ];
- int num_axes;
- int num_buttons;
- float dead_band[ _JS_MAX_AXES ];
- float saturate [ _JS_MAX_AXES ];
- float center [ _JS_MAX_AXES ];
- float max [ _JS_MAX_AXES ];
- float min [ _JS_MAX_AXES ];
- };
- /*
- * Functions associated with the "jsJoystick" class in PLIB
- */
- #if TARGET_HOST_MAC_OSX
- #define K_NUM_DEVICES 32
- int numDevices;
- io_object_t ioDevices[K_NUM_DEVICES];
- static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
- static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
- static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
- /* callback for CFArrayApply */
- static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
- static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
- static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
- static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
- #endif
- /*
- * The static joystick structure pointer
- */
- #define MAX_NUM_JOYSTICKS 2
- static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
- /*
- * Read the raw joystick data
- */
- static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
- {
- #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
- 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 )
- {
- *buttons = 0;
- 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)
- *buttons |= state << i;
- }
- }
- 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_MS_WINDOWS && !defined(_WIN32_WCE)
- status = joyGetPosEx( joy->js_id, &joy->js );
- if ( status != JOYERR_NOERROR )
- {
- joy->error = GL_TRUE;
- return;
- }
- if ( buttons )
- *buttons = joy->js.dwButtons;
- if ( axes )
- {
- /*
- * WARNING - Fall through case clauses!!
- */
- 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;
- case 3: axes[2] = (float) joy->js.dwZpos;
- case 2: axes[1] = (float) joy->js.dwYpos;
- case 1: axes[0] = (float) joy->js.dwXpos;
- }
- }
- #endif
- #if TARGET_HOST_POSIX_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;
- }
- return;
- }
- # ifdef HAVE_USB_JS
- while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
- {
- struct hid_item *h;
- for ( h = joy->os->hids; h; h = h->next )
- {
- 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)
- {
- 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 HAVE_ERRNO
- if ( len < 0 && errno != EAGAIN )
- #else
- if ( len < 0 )
- #endif
- {
- 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 HAVE_ERRNO
- if ( errno == EAGAIN )
- {
- /* Use the old values */
- if ( buttons )
- *buttons = joy->tmp_buttons;
- if ( axes )
- memcpy( axes, joy->tmp_axes,
- sizeof( float ) * joy->num_axes );
- return;
- }
- #endif
- fgWarning ( "%s", joy->fname );
- joy->error = GL_TRUE;
- return;
- }
- switch ( joy->js.type & ~JS_EVENT_INIT )
- {
- case JS_EVENT_BUTTON:
- if( joy->js.value == 0 ) /* clear the flag */
- joy->tmp_buttons &= ~( 1 << joy->js.number );
- else
- joy->tmp_buttons |= ( 1 << joy->js.number );
- break;
- case JS_EVENT_AXIS:
- 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 ( "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
- status = read( joy->fd, &joy->js, 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 ); /* XXX Should not be here -- BSD is handled earlier */
- # else
- *buttons = joy->js.buttons;
- # endif
- if ( axes )
- {
- axes[ 0 ] = (float) joy->js.x;
- axes[ 1 ] = (float) joy->js.y;
- }
- # endif
- #endif
- }
- /*
- * Correct the joystick axis data
- */
- static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
- {
- if( value < joy->center[ axis ] )
- {
- float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
- joy->min[ axis ] );
- if( xx < -joy->saturate[ axis ] )
- return -1.0f;
- if( xx > -joy->dead_band [ axis ] )
- return 0.0f;
- xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
- joy->dead_band[ axis ] );
- return ( xx < -1.0f ) ? -1.0f : xx;
- }
- else
- {
- float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
- joy->center[ axis ] );
- if( xx > joy->saturate[ axis ] )
- return 1.0f;
- if( xx < joy->dead_band[ axis ] )
- return 0.0f;
- xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
- joy->dead_band[ axis ] );
- return ( xx > 1.0f ) ? 1.0f : xx;
- }
- }
- /*
- * Read the corrected joystick data
- */
- static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
- {
- float raw_axes[ _JS_MAX_AXES ];
- int i;
- if( joy->error )
- {
- if( buttons )
- *buttons = 0;
- if( axes )
- for ( i=0; i<joy->num_axes; i++ )
- axes[ i ] = 0.0f;
- }
- fghJoystickRawRead( joy, buttons, raw_axes );
- if( axes )
- for( i=0; i<joy->num_axes; i++ )
- axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
- }
- /*
- * Happy happy happy joy joy joy (happy new year toudi :D)
- */
- #if TARGET_HOST_MAC_OSX
- /** open the IOKit connection, enumerate all the HID devices, add their
- interface references to the static array. We then use the array index
- as the device number when we come to open() the joystick. */
- static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
- {
- CFMutableDictionaryRef hidMatch = NULL;
- IOReturn rv = kIOReturnSuccess;
- io_iterator_t hidIterator;
- io_object_t ioDev;
- /* build a dictionary matching HID devices */
- hidMatch = IOServiceMatching(kIOHIDDeviceKey);
- rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
- if (rv != kIOReturnSuccess || !hidIterator) {
- fgWarning( "no joystick (HID) devices found" );
- return;
- }
- /* iterate */
- while ((ioDev = IOIteratorNext(hidIterator))) {
- /* filter out keyboard and mouse devices */
- CFDictionaryRef properties = getCFProperties(ioDev);
- long usage, page;
- CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
- CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
- CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
- CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
- /* keep only joystick devices */
- if ( ( page == kHIDPage_GenericDesktop ) && (
- (usage == kHIDUsage_GD_Joystick)
- || (usage == kHIDUsage_GD_GamePad)
- || (usage == kHIDUsage_GD_MultiAxisController)
- || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
- /* add it to the array */
- ioDevices[numDevices++] = ioDev;
- }
- IOObjectRelease(hidIterator);
- }
- static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
- {
- IOReturn rv;
- CFMutableDictionaryRef cfProperties;
- #if 0
- /* comment copied from darwin/SDL_sysjoystick.c */
- /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
- * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
- */
- io_registry_entry_t parent1, parent2;
- rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
- if (rv != kIOReturnSuccess) {
- fgWarning ( "error getting device entry parent");
- return NULL;
- }
- rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
- if (rv != kIOReturnSuccess) {
- fgWarning ( "error getting device entry parent 2");
- return NULL;
- }
- #endif
- rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
- &cfProperties, kCFAllocatorDefault, kNilOptions);
- if (rv != kIOReturnSuccess || !cfProperties) {
- fgWarning ( "error getting device properties");
- return NULL;
- }
- return cfProperties;
- }
- static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
- {
- if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
- fgError ( "%s", "element enumerator passed non-dictionary value");
- return;
- }
- static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
- }
- /** element enumerator function : pass NULL for top-level*/
- static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
- {
- FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
- "Joystick element type mismatch",
- "fghJoystickEnumerateElements" );
- CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
- CFArrayApplyFunction((CFArrayRef) element, range,
- &fghJoystickElementEnumerator, joy );
- }
- static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
- {
- long cookie, lmin, lmax;
- int index = joy->num_axes++;
- CFNumberGetValue ((CFNumberRef)
- CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
- kCFNumberLongType, &cookie);
- 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_MS_WINDOWS && !defined(_WIN32_WCE)
- /* Inspired by
- http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
- */
- # if FREEGLUT_LIB_PRAGMAS
- # 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 .. MediaResourcesCurrentJoystickSettings */
- _snprintf ( buffer, sizeof(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. */
- _snprintf ( buffer, sizeof(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 */
- _snprintf ( buffer, sizeof(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 )
- {
- int i = 0;
- #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_POSIX_X11
- # if defined( __FreeBSD__ ) || defined( __NetBSD__ )
- char *cp;
- # endif
- # ifdef JS_NEW
- unsigned char u;
- # else
- # if defined( __linux__ ) || TARGET_HOST_SOLARIS
- int counter = 0;
- # endif
- # endif
- #endif
- /* Silence gcc, the correct #ifdefs would be too fragile... */
- (void)i;
- /*
- * 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 ] = ' ';
- #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( "device index out of range in fgJoystickOpen()" );
- return;
- }
- /* create device interface */
- rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
- kIOHIDDeviceUserClientTypeID,
- kIOCFPlugInInterfaceID,
- &plugin, &score );
- if( rv != kIOReturnSuccess )
- {
- fgWarning( "error creating plugin for io device" );
- return;
- }
- pluginResult = ( *plugin )->QueryInterface(
- plugin,
- CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
- &( LPVOID )joy->hidDev
- );
- if( pluginResult != S_OK )
- fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
- ( *plugin )->Release( plugin ); /* don't leak a ref */
- if( joy->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_MS_WINDOWS && !defined(_WIN32_WCE)
- joy->js.dwFlags = JOY_RETURNALL;
- joy->js.dwSize = sizeof( joy->js );
- memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
- joy->error =
- ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
- JOYERR_NOERROR );
- if( joy->jsCaps.wNumAxes == 0 )
- {
- joy->num_axes = 0;
- joy->error = GL_TRUE;
- }
- 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++ )
- {
- joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
- joy->dead_band[ i ] = 0.0f;
- joy->saturate [ i ] = 1.0f;
- }
- #endif
- #if TARGET_HOST_POSIX_X11
- #if defined( __FreeBSD__ ) || defined( __NetBSD__ )
- for( i = 0; i < _JS_MAX_AXES; i++ )
- joy->os->cache_axes[ i ] = 0.0f;
- joy->os->cache_buttons = 0;
- joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
- #if HAVE_ERRNO
- if( joy->os->fd < 0 && errno == EACCES )
- fgWarning ( "%s exists but is not readable by you", joy->os->fname );
- #endif
- joy->error =( joy->os->fd < 0 );
- if( joy->error )
- return;
- 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;
- snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
- joyfile = fopen( joyfname, "r" );
- joy->error =( joyfile == NULL );
- if( joy->error )
- return;
- 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;
- }
- # endif
- #endif
- #if defined( __linux__ ) || TARGET_HOST_SOLARIS
- /* Default for older Linux systems. */
- joy->num_axes = 2;
- joy->num_buttons = 32;
- # ifdef JS_NEW
- for( i = 0; i < _JS_MAX_AXES; i++ )
- joy->tmp_axes[ i ] = 0.0f;
- 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
- * when no stick is present - but there is a chance
- * that could happen by accident - so it's gotta happen
- * on both axes for at least 100 attempts.
- *
- * PWO: shouldn't be that done somehow wiser on the kernel level?
- */
- # 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 )
- joy->error = GL_TRUE;
- # endif
- for( i = 0; i < _JS_MAX_AXES; i++ )
- {
- # ifdef JS_NEW
- joy->max [ i ] = 32767.0f;
- joy->center[ i ] = 0.0f;
- joy->min [ i ] = -32767.0f;
- # 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
- #endif
- }
- /*
- * This function replaces the constructor method in the JS library.
- */
- static void fghJoystickInit( int ident )
- {
- if( ident >= MAX_NUM_JOYSTICKS )
- fgError( "Too large a joystick number: %d", ident );
- if( fgJoystick[ ident ] )
- fgError( "illegal attempt to initialize joystick device again" );
- fgJoystick[ ident ] =
- ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
- /* Set defaults */
- fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
- fgJoystick[ ident ]->error = GL_TRUE;
- #if TARGET_HOST_MACINTOSH
- fgJoystick[ ident ]->id = ident;
- snprintf( fgJoystick[ ident ]->fname, sizeof(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( "error getting master Mach port" );
- return;
- }
- fghJoystickFindDevices( masterPort );
- }
- if ( ident >= numDevices )
- {
- fgJoystick[ ident ]->error = GL_TRUE;
- return;
- }
- /* get the name now too */
- CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
- CFTypeRef ref = CFDictionaryGetValue( properties,
- CFSTR( kIOHIDProductKey ) );
- if (!ref)
- ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
- if( !ref ||
- !CFStringGetCString( ( CFStringRef )ref, name, 128,
- CFStringGetSystemEncoding( ) ) )
- {
- fgWarning( "error getting device name" );
- name[ 0 ] = ' ';
- }
- #endif
- #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
- switch( ident )
- {
- case 0:
- fgJoystick[ ident ]->js_id = JOYSTICKID1;
- fgJoystick[ ident ]->error = GL_FALSE;
- break;
- case 1:
- fgJoystick[ ident ]->js_id = JOYSTICKID2;
- fgJoystick[ ident ]->error = GL_FALSE;
- break;
- default:
- fgJoystick[ ident ]->num_axes = 0;
- fgJoystick[ ident ]->error = GL_TRUE;
- return;
- }
- #endif
- #if TARGET_HOST_POSIX_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 )
- snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
- else
- snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
- ident - USB_IDENT_OFFSET );
- # elif defined( __linux__ )
- fgJoystick[ ident ]->id = ident;
- fgJoystick[ ident ]->error = GL_FALSE;
- snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
- if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
- snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
- # endif
- #endif
- fghJoystickOpen( fgJoystick[ ident ] );
- }
- /*
- * Try initializing all the joysticks (well, both of them)
- */
- void fgInitialiseJoysticks ( void )
- {
- if( !fgState.JoysticksInitialised )
- {
- int ident ;
- for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
- fghJoystickInit( ident );
- fgState.JoysticksInitialised = GL_TRUE;
- }
- }
- /*
- *
- */
- void fgJoystickClose( void )
- {
- int ident ;
- for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
- {
- if( fgJoystick[ ident ] )
- {
- #if TARGET_HOST_MACINTOSH
- ISpSuspend( );
- ISpStop( );
- ISpShutdown( );
- #endif
- #if TARGET_HOST_MAC_OSX
- ( *( fgJoystick[ ident ]->hidDev ) )->
- close( fgJoystick[ ident ]->hidDev );
- #endif
- #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
- /* Do nothing special */
- #endif
- #if TARGET_HOST_POSIX_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 */
- }
- }
- }
- /*
- * Polls the joystick and executes the joystick callback hooked to the
- * window specified in the function's parameter:
- */
- void fgJoystickPollWindow( SFG_Window* window )
- {
- float axes[ _JS_MAX_AXES ];
- int buttons;
- int ident;
- freeglut_return_if_fail( window );
- freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
- for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
- {
- if( fgJoystick[ident] )
- {
- fghJoystickRead( fgJoystick[ident], &buttons, axes );
- if( !fgJoystick[ident]->error )
- INVOKE_WCB( *window, Joystick,
- ( buttons,
- (int) ( axes[ 0 ] * 1000.0f ),
- (int) ( axes[ 1 ] * 1000.0f ),
- (int) ( axes[ 2 ] * 1000.0f ) )
- );
- }
- }
- }
- /*
- * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
- */
- int fgJoystickDetect( void )
- {
- int ident;
- fgInitialiseJoysticks ();
- if ( !fgState.JoysticksInitialised )
- return 0;
- for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
- if( fgJoystick[ident] && !fgJoystick[ident]->error )
- return 1;
- return 0;
- }
- /*
- * Joystick information functions
- */
- int glutJoystickGetNumAxes( int ident )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
- return fgJoystick[ ident ]->num_axes;
- }
- int glutJoystickGetNumButtons( int ident )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
- return fgJoystick[ ident ]->num_buttons;
- }
- int glutJoystickNotWorking( int ident )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
- return fgJoystick[ ident ]->error;
- }
- float glutJoystickGetDeadBand( int ident, int axis )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
- return fgJoystick[ ident ]->dead_band [ axis ];
- }
- void glutJoystickSetDeadBand( int ident, int axis, float db )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
- fgJoystick[ ident ]->dead_band[ axis ] = db;
- }
- float glutJoystickGetSaturation( int ident, int axis )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
- return fgJoystick[ ident ]->saturate[ axis ];
- }
- void glutJoystickSetSaturation( int ident, int axis, float st )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
- fgJoystick[ ident ]->saturate [ axis ] = st;
- }
- void glutJoystickSetMinRange( int ident, float *axes )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
- memcpy( fgJoystick[ ident ]->min, axes,
- fgJoystick[ ident ]->num_axes * sizeof( float ) );
- }
- void glutJoystickSetMaxRange( int ident, float *axes )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
- memcpy( fgJoystick[ ident ]->max, axes,
- fgJoystick[ ident ]->num_axes * sizeof( float ) );
- }
- void glutJoystickSetCenter( int ident, float *axes )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
- memcpy( fgJoystick[ ident ]->center, axes,
- fgJoystick[ ident ]->num_axes * sizeof( float ) );
- }
- void glutJoystickGetMinRange( int ident, float *axes )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
- memcpy( axes, fgJoystick[ ident ]->min,
- fgJoystick[ ident ]->num_axes * sizeof( float ) );
- }
- void glutJoystickGetMaxRange( int ident, float *axes )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
- memcpy( axes, fgJoystick[ ident ]->max,
- fgJoystick[ ident ]->num_axes * sizeof( float ) );
- }
- void glutJoystickGetCenter( int ident, float *axes )
- {
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
- memcpy( axes, fgJoystick[ ident ]->center,
- fgJoystick[ ident ]->num_axes * sizeof( float ) );
- }
- /*** END OF FILE ***/