-/*\r
- * freeglut_joystick.c\r
- *\r
- * Joystick handling code\r
- *\r
- * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
- * Written by Steve Baker, <sjbaker1@airmail.net>\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a\r
- * copy of this software and associated documentation files (the "Software"),\r
- * to deal in the Software without restriction, including without limitation\r
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
- * and/or sell copies of the Software, and to permit persons to whom the\r
- * Software is furnished to do so, subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included\r
- * in all copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
- * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- */\r
-\r
-/*\r
- * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>\r
- *\r
- * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.\r
- * Many thanks for Steve Baker for permission to pull from that library.\r
- */\r
-\r
-#include <GL/freeglut.h>\r
-#include "freeglut_internal.h"\r
-#ifdef HAVE_SYS_PARAM_H\r
-# include <sys/param.h>\r
-#endif\r
-\r
-/*\r
- * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"\r
- * interspersed\r
- */\r
-\r
-#if TARGET_HOST_MACINTOSH\r
-# include <InputSprocket.h>\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-# include <mach/mach.h>\r
-# include <IOKit/IOkitLib.h>\r
-# include <IOKit/hid/IOHIDLib.h>\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-# include <windows.h>\r
-# include <mmsystem.h>\r
-# include <regstr.h>\r
-\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-# ifdef HAVE_SYS_IOCTL_H\r
-# include <sys/ioctl.h>\r
-# endif\r
-# ifdef HAVE_FCNTL_H\r
-# include <fcntl.h>\r
-# endif\r
-# ifdef HAVE_ERRNO_H\r
-# include <errno.h>\r
-# include <string.h>\r
-# endif\r
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
-/* XXX The below hack is done until freeglut's autoconf is updated. */\r
-# define HAVE_USB_JS 1\r
-\r
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\r
-# include <sys/joystick.h>\r
-# else\r
-/*\r
- * XXX NetBSD/amd64 systems may find that they have to steal the\r
- * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.\r
- * XXX I cannot comment whether that works for the interface, but\r
- * XXX it lets you compile...(^& I do not think that we can do away\r
- * XXX with this header.\r
- */\r
-# include <machine/joystick.h> /* For analog joysticks */\r
-# endif\r
-# define JS_DATA_TYPE joystick\r
-# define JS_RETURN (sizeof(struct JS_DATA_TYPE))\r
-# endif\r
-\r
-# if defined(__linux__)\r
-# include <linux/joystick.h>\r
-\r
-/* check the joystick driver version */\r
-# if defined(JS_VERSION) && JS_VERSION >= 0x010000\r
-# define JS_NEW\r
-# endif\r
-# else /* Not BSD or Linux */\r
-# ifndef JS_RETURN\r
-\r
- /*\r
- * We'll put these values in and that should\r
- * allow the code to at least compile when there is\r
- * no support. The JS open routine should error out\r
- * and shut off all the code downstream anyway and if\r
- * the application doesn't use a joystick we'll be fine.\r
- */\r
-\r
- struct JS_DATA_TYPE\r
- {\r
- int buttons;\r
- int x;\r
- int y;\r
- };\r
-\r
-# define JS_RETURN (sizeof(struct JS_DATA_TYPE))\r
-# endif\r
-# endif\r
-#endif\r
-\r
-#define JS_TRUE 1\r
-#define JS_FALSE 0\r
-\r
-/* BSD defines from "jsBSD.cxx" around lines 42-270 */\r
-\r
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\r
-\r
-# ifdef HAVE_USB_JS\r
-# if defined(__NetBSD__)\r
-/* XXX The below hack is done until freeglut's autoconf is updated. */\r
-# define HAVE_USBHID_H 1\r
-# ifdef HAVE_USBHID_H\r
-# include <usbhid.h>\r
-# else\r
-# include <usb.h>\r
-# endif\r
-# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\r
-# ifdef HAVE_USBHID_H\r
-# include <usbhid.h>\r
-# else\r
-# include <libusbhid.h>\r
-# endif\r
-# endif\r
-# include <legacy/dev/usb/usb.h>\r
-# include <dev/usb/usbhid.h>\r
-\r
-/* Compatibility with older usb.h revisions */\r
-# if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)\r
-# define USB_MAX_DEVNAMES MAXDEVNAMES\r
-# endif\r
-# endif\r
-\r
-static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };\r
-static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };\r
-struct os_specific_s {\r
- char fname [128 ];\r
- int fd;\r
- int is_analog;\r
- /* The following structure members are specific to analog joysticks */\r
- struct joystick ajs;\r
-# ifdef HAVE_USB_JS\r
- /* The following structure members are specific to USB joysticks */\r
- struct hid_item *hids;\r
- int hid_dlen;\r
- int hid_offset;\r
- char *hid_data_buf;\r
- int axes_usage [ _JS_MAX_AXES ];\r
-# endif\r
- /* We keep button and axes state ourselves, as they might not be updated\r
- * on every read of a USB device\r
- */\r
- int cache_buttons;\r
- float cache_axes [ _JS_MAX_AXES ];\r
-};\r
-\r
-/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */\r
-# define USB_IDENT_OFFSET 2\r
-\r
-# define USBDEV "/dev/usb"\r
-# define UHIDDEV "/dev/uhid"\r
-# define AJSDEV "/dev/joy"\r
-\r
-# ifdef HAVE_USB_JS\r
-/*\r
- * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate\r
- * the full name of a USB device. If /dev/usbN isn't readable, we punt and\r
- * return the uhidN device name. We warn the user of this situation once.\r
- */\r
-static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)\r
-{\r
- struct usb_device_info di;\r
- int i, a;\r
- char *cp;\r
-\r
- for (a = 1; a < USB_MAX_DEVICES; a++) {\r
- di.udi_addr = a;\r
- if (ioctl(f, USB_DEVICEINFO, &di) != 0)\r
- return NULL;\r
- for (i = 0; i < USB_MAX_DEVNAMES; i++)\r
- if (di.udi_devnames[i][0] &&\r
- strcmp(di.udi_devnames[i], dev) == 0) {\r
- cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);\r
- strcpy(cp, di.udi_vendor);\r
- strcat(cp, " ");\r
- strcat(cp, di.udi_product);\r
- strncpy(out, cp, outlen - 1);\r
- out[outlen - 1] = 0;\r
- free( cp );\r
- return out;\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-static int fghJoystickFindUSBdev(char *name, char *out, int outlen)\r
-{\r
- int i, f;\r
- char buf[50];\r
- char *cp;\r
- static int protection_warned = 0;\r
-\r
- for (i = 0; i < 16; i++) {\r
- snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);\r
- f = open(buf, O_RDONLY);\r
- if (f >= 0) {\r
- cp = fghJoystickWalkUSBdev(f, name, out, outlen);\r
- close(f);\r
- if (cp)\r
- return 1;\r
- }\r
-#ifdef HAVE_ERRNO_H\r
- else if (errno == EACCES) {\r
- if (!protection_warned) {\r
- fgWarning ( "Can't open %s for read!", buf );\r
- protection_warned = 1;\r
- }\r
- }\r
-#endif\r
- }\r
- return 0;\r
-}\r
-\r
-static int fghJoystickInitializeHID(struct os_specific_s *os,\r
- int *num_axes, int *num_buttons)\r
-{\r
- int size, is_joystick;\r
-# ifdef HAVE_USBHID_H\r
- int report_id = 0;\r
-# endif\r
- struct hid_data *d;\r
- struct hid_item h;\r
- report_desc_t rd;\r
-\r
- if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )\r
- {\r
-#ifdef HAVE_ERRNO_H\r
- fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );\r
-#else\r
- fgWarning ( "error: %s", os->fname );\r
-#endif\r
- return FALSE;\r
- }\r
-\r
- os->hids = NULL;\r
-\r
-# ifdef HAVE_USBHID_H\r
- if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)\r
- {\r
- /*** XXX {report_id} may not be the right variable? ***/\r
-#ifdef HAVE_ERRNO_H\r
- fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );\r
-#else\r
- fgWarning ( "error: %s%d", UHIDDEV, report_id );\r
-#endif\r
- return FALSE;\r
- }\r
-\r
- size = hid_report_size( rd, hid_input, report_id );\r
-# else\r
- size = hid_report_size( rd, 0, hid_input );\r
-# endif\r
- os->hid_data_buf = calloc( 1, size );\r
- os->hid_dlen = size;\r
-\r
- is_joystick = 0;\r
-# ifdef HAVE_USBHID_H\r
- d = hid_start_parse( rd, 1 << hid_input, report_id );\r
-# else\r
- d = hid_start_parse( rd, 1 << hid_input );\r
-# endif\r
- while( hid_get_item( d, &h ) )\r
- {\r
- int usage, page, interesting_hid;\r
-\r
- page = HID_PAGE( h.usage );\r
- usage = HID_USAGE( h.usage );\r
-\r
- /* This test is somewhat too simplistic, but this is how MicroSoft\r
- * does, so I guess it works for all joysticks/game pads. */\r
- is_joystick = is_joystick ||\r
- ( h.kind == hid_collection &&\r
- page == HUP_GENERIC_DESKTOP &&\r
- ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );\r
-\r
- if( h.kind != hid_input )\r
- continue;\r
-\r
- if( !is_joystick )\r
- continue;\r
-\r
- interesting_hid = TRUE;\r
- if( page == HUP_GENERIC_DESKTOP )\r
- {\r
- switch( usage )\r
- {\r
- case HUG_X:\r
- case HUG_RX:\r
- case HUG_Y:\r
- case HUG_RY:\r
- case HUG_Z:\r
- case HUG_RZ:\r
- case HUG_SLIDER:\r
- if( *num_axes < _JS_MAX_AXES )\r
- {\r
- os->axes_usage[ *num_axes ] = usage;\r
- ( *num_axes )++;\r
- }\r
- break;\r
- case HUG_HAT_SWITCH:\r
- /* Allocate two axes for a hat */\r
- if( *num_axes + 1 < _JS_MAX_AXES )\r
- {\r
- os->axes_usage[ *num_axes ] = usage;\r
- (*num_axes)++;\r
- os->axes_usage[ *num_axes ] = usage;\r
- (*num_axes)++;\r
- }\r
- break;\r
- default:\r
- interesting_hid = FALSE;\r
- break;\r
- }\r
- }\r
- else if( page == HUP_BUTTON )\r
- {\r
- interesting_hid = ( usage > 0 ) &&\r
- ( usage <= _JS_MAX_BUTTONS );\r
-\r
- if( interesting_hid && usage - 1 > *num_buttons )\r
- *num_buttons = usage - 1;\r
- }\r
-\r
- if( interesting_hid )\r
- {\r
- h.next = os->hids;\r
- os->hids = calloc( 1, sizeof ( struct hid_item ) );\r
- *os->hids = h;\r
- }\r
- }\r
- hid_end_parse( d );\r
-\r
- return os->hids != NULL;\r
-}\r
-# endif\r
-#endif\r
-\r
-/*\r
- * Functions associated with the "jsJoystick" class in PLIB\r
- */\r
-#if TARGET_HOST_MAC_OSX\r
-#define K_NUM_DEVICES 32\r
-int numDevices;\r
-io_object_t ioDevices[K_NUM_DEVICES];\r
-\r
-static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );\r
-static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );\r
-\r
-static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );\r
-/* callback for CFArrayApply */\r
-static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );\r
-\r
-static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );\r
-static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );\r
-static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );\r
-#endif\r
-\r
-\r
-/* External function declarations (mostly platform-specific) */\r
-extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );\r
-extern void fgPlatformJoystickClose ( int ident );\r
-\r
-/*\r
- * The static joystick structure pointer\r
- */\r
-#define MAX_NUM_JOYSTICKS 2\r
-static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];\r
-\r
-/*\r
- * Platform-Specific Code\r
- */\r
-\r
-#if TARGET_HOST_MACINTOSH\r
-void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
-{\r
- fgJoystick[ ident ]->id = ident;\r
- snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */\r
- fgJoystick[ ident ]->error = GL_FALSE;\r
-}\r
-\r
-\r
-void fgPlatformJoystickClose ( int ident )\r
-{\r
- ISpSuspend( );\r
- ISpStop( );\r
- ISpShutdown( );\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
-{\r
- fgJoystick[ ident ]->id = ident;\r
- fgJoystick[ ident ]->error = GL_FALSE;\r
- fgJoystick[ ident ]->num_axes = 0;\r
- fgJoystick[ ident ]->num_buttons = 0;\r
-\r
- if( numDevices < 0 )\r
- {\r
- /* do first-time init (since we can't over-ride jsInit, hmm */\r
- numDevices = 0;\r
-\r
- mach_port_t masterPort;\r
- IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );\r
- if( rv != kIOReturnSuccess )\r
- {\r
- fgWarning( "error getting master Mach port" );\r
- return;\r
- }\r
- fghJoystickFindDevices( masterPort );\r
- }\r
-\r
- if ( ident >= numDevices )\r
- {\r
- fgJoystick[ ident ]->error = GL_TRUE;\r
- return;\r
- }\r
-\r
- /* get the name now too */\r
- CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );\r
- CFTypeRef ref = CFDictionaryGetValue( properties,\r
- CFSTR( kIOHIDProductKey ) );\r
- if (!ref)\r
- ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );\r
-\r
- if( !ref ||\r
- !CFStringGetCString( ( CFStringRef )ref, name, 128,\r
- CFStringGetSystemEncoding( ) ) )\r
- {\r
- fgWarning( "error getting device name" );\r
- name[ 0 ] = '\0';\r
- }\r
-}\r
-\r
-\r
-void fgPlatformJoystickClose ( int ident )\r
-{\r
- ( *( fgJoystick[ ident ]->hidDev ) )->\r
- close( fgJoystick[ ident ]->hidDev );\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
-{\r
-#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
- fgJoystick[ ident ]->id = ident;\r
- fgJoystick[ ident ]->error = GL_FALSE;\r
-\r
- fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );\r
- memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );\r
- if( ident < USB_IDENT_OFFSET )\r
- fgJoystick[ ident ]->os->is_analog = 1;\r
- if( fgJoystick[ ident ]->os->is_analog )\r
- snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );\r
- else\r
- snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,\r
- ident - USB_IDENT_OFFSET );\r
-#elif defined( __linux__ )\r
- fgJoystick[ ident ]->id = ident;\r
- fgJoystick[ ident ]->error = GL_FALSE;\r
-\r
- snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );\r
-\r
- if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )\r
- snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );\r
-#endif\r
-}\r
-\r
-\r
-void fgPlatformJoystickClose ( int ident )\r
-{\r
-#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
- if( fgJoystick[ident]->os )\r
- {\r
- if( ! fgJoystick[ ident ]->error )\r
- close( fgJoystick[ ident ]->os->fd );\r
-#ifdef HAVE_USB_JS\r
- if( fgJoystick[ ident ]->os->hids )\r
- free (fgJoystick[ ident ]->os->hids);\r
- if( fgJoystick[ ident ]->os->hid_data_buf )\r
- free( fgJoystick[ ident ]->os->hid_data_buf );\r
-#endif\r
- free( fgJoystick[ident]->os );\r
- }\r
-#endif\r
-\r
- if( ! fgJoystick[ident]->error )\r
- close( fgJoystick[ ident ]->fd );\r
-}\r
-#endif\r
-\r
-\r
-\r
-/*\r
- * Read the raw joystick data\r
- */\r
-static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
-{\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
- MMRESULT status;\r
-#else\r
- int status;\r
-#endif\r
-\r
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
- int len;\r
-#endif\r
-\r
- int i;\r
-\r
- /* Defaults */\r
- if( buttons )\r
- *buttons = 0;\r
-\r
- if( axes )\r
- for( i = 0; i < joy->num_axes; i++ )\r
- axes[ i ] = 1500.0f;\r
-\r
- if( joy->error )\r
- return;\r
-\r
-#if TARGET_HOST_MACINTOSH\r
- if ( buttons )\r
- {\r
- *buttons = 0;\r
-\r
- for ( i = 0; i < joy->num_buttons; i++ )\r
- {\r
- UInt32 state;\r
- int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);\r
- ISP_CHECK_ERR(err)\r
-\r
- *buttons |= state << i;\r
- }\r
- }\r
-\r
- if ( axes )\r
- {\r
- for ( i = 0; i < joy->num_axes; i++ )\r
- {\r
- UInt32 state;\r
- int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );\r
- ISP_CHECK_ERR(err)\r
-\r
- axes [i] = (float) state;\r
- }\r
- }\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
- if ( buttons != NULL )\r
- {\r
- *buttons = 0;\r
-\r
- for ( i = 0; i < joy->num_buttons; i++ )\r
- {\r
- IOHIDEventStruct hidEvent;\r
- (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );\r
- if ( hidEvent.value )\r
- *buttons |= 1 << i;\r
- }\r
- }\r
-\r
- if ( axes != NULL )\r
- {\r
- for ( i = 0; i < joy->num_axes; i++ )\r
- {\r
- IOHIDEventStruct hidEvent;\r
- (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );\r
- axes[i] = hidEvent.value;\r
- }\r
- }\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
- status = joyGetPosEx( joy->js_id, &joy->js );\r
-\r
- if ( status != JOYERR_NOERROR )\r
- {\r
- joy->error = GL_TRUE;\r
- return;\r
- }\r
-\r
- if ( buttons )\r
- *buttons = joy->js.dwButtons;\r
-\r
- if ( axes )\r
- {\r
- /*\r
- * WARNING - Fall through case clauses!!\r
- */\r
- switch ( joy->num_axes )\r
- {\r
- case 8:\r
- /* Generate two POV axes from the POV hat angle.\r
- * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in\r
- * hundredths of a degree, or 0xFFFF when idle.\r
- */\r
- if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )\r
- {\r
- axes [ 6 ] = 0.0;\r
- axes [ 7 ] = 0.0;\r
- }\r
- else\r
- {\r
- /* This is the contentious bit: how to convert angle to X/Y.\r
- * wk: I know of no define for PI that we could use here:\r
- * SG_PI would pull in sg, M_PI is undefined for MSVC\r
- * But the accuracy of the value of PI is very unimportant at\r
- * this point.\r
- */\r
- float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );\r
- float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );\r
-\r
- /* Convert to coordinates on a square so that North-East\r
- * is (1,1) not (.7,.7), etc.\r
- * s and c cannot both be zero so we won't divide by zero.\r
- */\r
- if ( fabs ( s ) < fabs ( c ) )\r
- {\r
- axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;\r
- axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;\r
- }\r
- else\r
- {\r
- axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;\r
- axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;\r
- }\r
- }\r
-\r
- case 6: axes[5] = (float) joy->js.dwVpos;\r
- case 5: axes[4] = (float) joy->js.dwUpos;\r
- case 4: axes[3] = (float) joy->js.dwRpos;\r
- case 3: axes[2] = (float) joy->js.dwZpos;\r
- case 2: axes[1] = (float) joy->js.dwYpos;\r
- case 1: axes[0] = (float) joy->js.dwXpos;\r
- }\r
- }\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
- if ( joy->os->is_analog )\r
- {\r
- int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );\r
- if ( status != sizeof(joy->os->ajs) ) {\r
- perror ( joy->os->fname );\r
- joy->error = GL_TRUE;\r
- return;\r
- }\r
- if ( buttons != NULL )\r
- *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );\r
-\r
- if ( axes != NULL )\r
- {\r
- axes[0] = (float) joy->os->ajs.x;\r
- axes[1] = (float) joy->os->ajs.y;\r
- }\r
-\r
- return;\r
- }\r
-\r
-# ifdef HAVE_USB_JS\r
- while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )\r
- {\r
- struct hid_item *h;\r
-\r
- for ( h = joy->os->hids; h; h = h->next )\r
- {\r
- int d = hid_get_data ( joy->os->hid_data_buf, h );\r
-\r
- int page = HID_PAGE ( h->usage );\r
- int usage = HID_USAGE ( h->usage );\r
-\r
- if ( page == HUP_GENERIC_DESKTOP )\r
- {\r
- int i;\r
- for ( i = 0; i < joy->num_axes; i++ )\r
- if (joy->os->axes_usage[i] == usage)\r
- {\r
- if (usage == HUG_HAT_SWITCH)\r
- {\r
- if (d < 0 || d > 8)\r
- d = 0; /* safety */\r
- joy->os->cache_axes[i] = (float)hatmap_x[d];\r
- joy->os->cache_axes[i + 1] = (float)hatmap_y[d];\r
- }\r
- else\r
- {\r
- joy->os->cache_axes[i] = (float)d;\r
- }\r
- break;\r
- }\r
- }\r
- else if (page == HUP_BUTTON)\r
- {\r
- if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)\r
- {\r
- if (d)\r
- joy->os->cache_buttons |= (1 << ( usage - 1 ));\r
- else\r
- joy->os->cache_buttons &= ~(1 << ( usage - 1 ));\r
- }\r
- }\r
- }\r
- }\r
-#ifdef HAVE_ERRNO_H\r
- if ( len < 0 && errno != EAGAIN )\r
-#else\r
- if ( len < 0 )\r
-#endif\r
- {\r
- perror( joy->os->fname );\r
- joy->error = 1;\r
- }\r
- if ( buttons != NULL ) *buttons = joy->os->cache_buttons;\r
- if ( axes != NULL )\r
- memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );\r
-# endif\r
-# endif\r
-\r
-# ifdef JS_NEW\r
-\r
- while ( 1 )\r
- {\r
- status = read ( joy->fd, &joy->js, sizeof(struct js_event) );\r
-\r
- if ( status != sizeof( struct js_event ) )\r
- {\r
-#ifdef HAVE_ERRNO_H\r
- if ( errno == EAGAIN )\r
- {\r
- /* Use the old values */\r
- if ( buttons )\r
- *buttons = joy->tmp_buttons;\r
- if ( axes )\r
- memcpy( axes, joy->tmp_axes,\r
- sizeof( float ) * joy->num_axes );\r
- return;\r
- }\r
-#endif\r
-\r
- fgWarning ( "%s", joy->fname );\r
- joy->error = GL_TRUE;\r
- return;\r
- }\r
-\r
- switch ( joy->js.type & ~JS_EVENT_INIT )\r
- {\r
- case JS_EVENT_BUTTON:\r
- if( joy->js.value == 0 ) /* clear the flag */\r
- joy->tmp_buttons &= ~( 1 << joy->js.number );\r
- else\r
- joy->tmp_buttons |= ( 1 << joy->js.number );\r
- break;\r
-\r
- case JS_EVENT_AXIS:\r
- if ( joy->js.number < joy->num_axes )\r
- {\r
- joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;\r
-\r
- if( axes )\r
- memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );\r
- }\r
- break;\r
-\r
- default:\r
- fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );\r
-\r
- /* use the old values */\r
-\r
- if ( buttons != NULL ) *buttons = joy->tmp_buttons;\r
- if ( axes != NULL )\r
- memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );\r
-\r
- return;\r
- }\r
-\r
- if( buttons )\r
- *buttons = joy->tmp_buttons;\r
- }\r
-# else\r
-\r
- status = read( joy->fd, &joy->js, JS_RETURN );\r
-\r
- if ( status != JS_RETURN )\r
- {\r
- fgWarning( "%s", joy->fname );\r
- joy->error = GL_TRUE;\r
- return;\r
- }\r
-\r
- if ( buttons )\r
-# if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
- *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */\r
-# else\r
- *buttons = joy->js.buttons;\r
-# endif\r
-\r
- if ( axes )\r
- {\r
- axes[ 0 ] = (float) joy->js.x;\r
- axes[ 1 ] = (float) joy->js.y;\r
- }\r
-# endif\r
-#endif\r
-}\r
-\r
-/*\r
- * Correct the joystick axis data\r
- */\r
-static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )\r
-{\r
- if( value < joy->center[ axis ] )\r
- {\r
- float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -\r
- joy->min[ axis ] );\r
-\r
- if( xx < -joy->saturate[ axis ] )\r
- return -1.0f;\r
-\r
- if( xx > -joy->dead_band [ axis ] )\r
- return 0.0f;\r
-\r
- xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -\r
- joy->dead_band[ axis ] );\r
-\r
- return ( xx < -1.0f ) ? -1.0f : xx;\r
- }\r
- else\r
- {\r
- float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -\r
- joy->center[ axis ] );\r
-\r
- if( xx > joy->saturate[ axis ] )\r
- return 1.0f;\r
-\r
- if( xx < joy->dead_band[ axis ] )\r
- return 0.0f;\r
-\r
- xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -\r
- joy->dead_band[ axis ] );\r
-\r
- return ( xx > 1.0f ) ? 1.0f : xx;\r
- }\r
-}\r
-\r
-/*\r
- * Read the corrected joystick data\r
- */\r
-static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )\r
-{\r
- float raw_axes[ _JS_MAX_AXES ];\r
- int i;\r
-\r
- if( joy->error )\r
- {\r
- if( buttons )\r
- *buttons = 0;\r
-\r
- if( axes )\r
- for ( i=0; i<joy->num_axes; i++ )\r
- axes[ i ] = 0.0f;\r
- }\r
-\r
- fghJoystickRawRead( joy, buttons, raw_axes );\r
-\r
- if( axes )\r
- for( i=0; i<joy->num_axes; i++ )\r
- axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );\r
-}\r
-\r
-/*\r
- * Happy happy happy joy joy joy (happy new year toudi :D)\r
- */\r
-\r
-\r
-#if TARGET_HOST_MAC_OSX\r
-/** open the IOKit connection, enumerate all the HID devices, add their\r
-interface references to the static array. We then use the array index\r
-as the device number when we come to open() the joystick. */\r
-static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )\r
-{\r
- CFMutableDictionaryRef hidMatch = NULL;\r
- IOReturn rv = kIOReturnSuccess;\r
-\r
- io_iterator_t hidIterator;\r
- io_object_t ioDev;\r
-\r
- /* build a dictionary matching HID devices */\r
- hidMatch = IOServiceMatching(kIOHIDDeviceKey);\r
-\r
- rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);\r
- if (rv != kIOReturnSuccess || !hidIterator) {\r
- fgWarning( "no joystick (HID) devices found" );\r
- return;\r
- }\r
-\r
- /* iterate */\r
- while ((ioDev = IOIteratorNext(hidIterator))) {\r
- /* filter out keyboard and mouse devices */\r
- CFDictionaryRef properties = getCFProperties(ioDev);\r
- long usage, page;\r
-\r
- CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));\r
- CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));\r
- CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);\r
- CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);\r
-\r
- /* keep only joystick devices */\r
- if ( ( page == kHIDPage_GenericDesktop ) && (\r
- (usage == kHIDUsage_GD_Joystick)\r
- || (usage == kHIDUsage_GD_GamePad)\r
- || (usage == kHIDUsage_GD_MultiAxisController)\r
- || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */\r
- /* add it to the array */\r
- ioDevices[numDevices++] = ioDev;\r
- }\r
-\r
- IOObjectRelease(hidIterator);\r
-}\r
-\r
-static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )\r
-{\r
- IOReturn rv;\r
- CFMutableDictionaryRef cfProperties;\r
-\r
-#if 0\r
- /* comment copied from darwin/SDL_sysjoystick.c */\r
- /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also\r
- * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties\r
- */\r
-\r
- io_registry_entry_t parent1, parent2;\r
-\r
- rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);\r
- if (rv != kIOReturnSuccess) {\r
- fgWarning ( "error getting device entry parent");\r
- return NULL;\r
- }\r
-\r
- rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);\r
- if (rv != kIOReturnSuccess) {\r
- fgWarning ( "error getting device entry parent 2");\r
- return NULL;\r
- }\r
-#endif\r
-\r
- rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,\r
- &cfProperties, kCFAllocatorDefault, kNilOptions);\r
- if (rv != kIOReturnSuccess || !cfProperties) {\r
- fgWarning ( "error getting device properties");\r
- return NULL;\r
- }\r
-\r
- return cfProperties;\r
-}\r
-\r
-static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )\r
-{\r
- if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {\r
- fgError ( "%s", "element enumerator passed non-dictionary value");\r
- return;\r
- }\r
-\r
- static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );\r
-}\r
-\r
-/** element enumerator function : pass NULL for top-level*/\r
-static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )\r
-{\r
- FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),\r
- "Joystick element type mismatch",\r
- "fghJoystickEnumerateElements" );\r
-\r
- CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};\r
- CFArrayApplyFunction((CFArrayRef) element, range,\r
- &fghJoystickElementEnumerator, joy );\r
-}\r
-\r
-static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )\r
-{\r
- long cookie, lmin, lmax;\r
- int index = joy->num_axes++;\r
-\r
- CFNumberGetValue ((CFNumberRef)\r
- CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),\r
- kCFNumberLongType, &cookie);\r
-\r
- axisCookies[index] = (IOHIDElementCookie) cookie;\r
-\r
- CFNumberGetValue ((CFNumberRef)\r
- CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),\r
- kCFNumberLongType, &lmin);\r
-\r
- CFNumberGetValue ((CFNumberRef)\r
- CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),\r
- kCFNumberLongType, &lmax);\r
-\r
- joy->min[index] = lmin;\r
- joy->max[index] = lmax;\r
- joy->dead_band[index] = 0.0;\r
- joy->saturate[index] = 1.0;\r
- joy->center[index] = (lmax + lmin) * 0.5;\r
-}\r
-\r
-static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )\r
-{\r
- long cookie;\r
- CFNumberGetValue ((CFNumberRef)\r
- CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),\r
- kCFNumberLongType, &cookie);\r
-\r
- joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;\r
- /* anything else for buttons? */\r
-}\r
-\r
-static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )\r
-{\r
- /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */\r
- /* do we map hats to axes or buttons? */\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
-/* Inspired by\r
- http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp\r
- */\r
-# if FREEGLUT_LIB_PRAGMAS\r
-# pragma comment (lib, "advapi32.lib")\r
-# endif\r
-\r
-static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )\r
-{\r
- char buffer [ 256 ];\r
-\r
- char OEMKey [ 256 ];\r
-\r
- HKEY hKey;\r
- DWORD dwcb;\r
- LONG lr;\r
-\r
- if ( joy->error )\r
- return 0;\r
-\r
- /* Open .. MediaResources\CurrentJoystickSettings */\r
- _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",\r
- REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,\r
- REGSTR_KEY_JOYCURR );\r
-\r
- lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);\r
-\r
- if ( lr != ERROR_SUCCESS ) return 0;\r
-\r
- /* Get OEM Key name */\r
- dwcb = sizeof(OEMKey);\r
-\r
- /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */\r
- _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );\r
-\r
- lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);\r
- RegCloseKey ( hKey );\r
-\r
- if ( lr != ERROR_SUCCESS ) return 0;\r
-\r
- /* Open OEM Key from ...MediaProperties */\r
- _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );\r
-\r
- lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );\r
-\r
- if ( lr != ERROR_SUCCESS ) return 0;\r
-\r
- /* Get OEM Name */\r
- dwcb = buf_sz;\r
-\r
- lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,\r
- &dwcb );\r
- RegCloseKey ( hKey );\r
-\r
- if ( lr != ERROR_SUCCESS ) return 0;\r
-\r
- return 1;\r
-}\r
-#endif\r
-\r
-\r
-static void fghJoystickOpen( SFG_Joystick* joy )\r
-{\r
- int i = 0;\r
-#if TARGET_HOST_MACINTOSH\r
- OSStatus err;\r
-#endif\r
-#if TARGET_HOST_MAC_OSX\r
- IOReturn rv;\r
- SInt32 score;\r
- IOCFPlugInInterface **plugin;\r
-\r
- HRESULT pluginResult;\r
-\r
- CFDictionaryRef props;\r
- CFTypeRef topLevelElement;\r
-#endif\r
-#if TARGET_HOST_POSIX_X11\r
-# if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
- char *cp;\r
-# endif\r
-# ifdef JS_NEW\r
- unsigned char u;\r
-# else\r
-# if defined( __linux__ ) || TARGET_HOST_SOLARIS\r
- int counter = 0;\r
-# endif\r
-# endif\r
-#endif\r
-\r
- /* Silence gcc, the correct #ifdefs would be too fragile... */\r
- (void)i;\r
-\r
- /*\r
- * Default values (for no joystick -- each conditional will reset the\r
- * error flag)\r
- */\r
- joy->error = TRUE;\r
- joy->num_axes = joy->num_buttons = 0;\r
- joy->name[ 0 ] = '\0';\r
-\r
-#if TARGET_HOST_MACINTOSH\r
- /* XXX FIXME: get joystick name in Mac */\r
-\r
- err = ISpStartup( );\r
-\r
- if( err == noErr )\r
- {\r
-#define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }\r
-\r
- joy->error = GL_TRUE;\r
-\r
- /* initialize the needs structure */\r
- ISpNeed temp_isp_needs[ isp_num_needs ] =\r
- {\r
- { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
- { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },\r
-\r
- { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },\r
- };\r
-\r
- memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );\r
-\r
-\r
- /* next two calls allow keyboard and mouse to emulate other input\r
- * devices (gamepads, joysticks, etc)\r
- */\r
- /*\r
- err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );\r
- ISP_CHECK_ERR(err)\r
-\r
-\r
- err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );\r
- ISP_CHECK_ERR(err)\r
- */\r
-\r
- err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,\r
- joy->isp_needs, joy->isp_elem,\r
- 0 );\r
- ISP_CHECK_ERR( err )\r
-\r
- err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,\r
- 'freeglut', nil, 0, 128, 0 );\r
- ISP_CHECK_ERR( err )\r
-\r
- joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;\r
- joy->num_axes = joy->isp_num_axis;\r
-\r
- for( i = 0; i < joy->num_axes; i++ )\r
- {\r
- joy->dead_band[ i ] = 0;\r
- joy->saturate [ i ] = 1;\r
- joy->center [ i ] = kISpAxisMiddle;\r
- joy->max [ i ] = kISpAxisMaximum;\r
- joy->min [ i ] = kISpAxisMinimum;\r
- }\r
-\r
- joy->error = GL_FALSE;\r
- }\r
- else\r
- joy->num_buttons = joy->num_axes = 0;\r
-#endif\r
-\r
-#if TARGET_HOST_MAC_OSX\r
- if( joy->id >= numDevices )\r
- {\r
- fgWarning( "device index out of range in fgJoystickOpen()" );\r
- return;\r
- }\r
-\r
- /* create device interface */\r
- rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],\r
- kIOHIDDeviceUserClientTypeID,\r
- kIOCFPlugInInterfaceID,\r
- &plugin, &score );\r
-\r
- if( rv != kIOReturnSuccess )\r
- {\r
- fgWarning( "error creating plugin for io device" );\r
- return;\r
- }\r
-\r
- pluginResult = ( *plugin )->QueryInterface(\r
- plugin,\r
- CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),\r
- &( LPVOID )joy->hidDev\r
- );\r
-\r
- if( pluginResult != S_OK )\r
- fgWarning ( "QI-ing IO plugin to HID Device interface failed" );\r
-\r
- ( *plugin )->Release( plugin ); /* don't leak a ref */\r
- if( joy->hidDev == NULL )\r
- return;\r
-\r
- /* store the interface in this instance */\r
- rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );\r
- if( rv != kIOReturnSuccess )\r
- {\r
- fgWarning( "error opening device interface");\r
- return;\r
- }\r
-\r
- props = getCFProperties( ioDevices[ joy->id ] );\r
-\r
- /* recursively enumerate all the bits */\r
- CFTypeRef topLevelElement =\r
- CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );\r
- enumerateElements( topLevelElement );\r
-\r
- CFRelease( props );\r
-#endif\r
-\r
-#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)\r
- joy->js.dwFlags = JOY_RETURNALL;\r
- joy->js.dwSize = sizeof( joy->js );\r
-\r
- memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );\r
-\r
- joy->error =\r
- ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=\r
- JOYERR_NOERROR );\r
-\r
- if( joy->jsCaps.wNumAxes == 0 )\r
- {\r
- joy->num_axes = 0;\r
- joy->error = GL_TRUE;\r
- }\r
- else\r
- {\r
- /* Device name from jsCaps is often "Microsoft PC-joystick driver",\r
- * at least for USB. Try to get the real name from the registry.\r
- */\r
- if ( ! fghJoystickGetOEMProductName( joy, joy->name,\r
- sizeof( joy->name ) ) )\r
- {\r
- fgWarning( "JS: Failed to read joystick name from registry" );\r
- strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );\r
- }\r
-\r
- /* Windows joystick drivers may provide any combination of\r
- * X,Y,Z,R,U,V,POV - not necessarily the first n of these.\r
- */\r
- if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )\r
- {\r
- joy->num_axes = _JS_MAX_AXES;\r
- joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */\r
- joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */\r
- }\r
- else\r
- joy->num_axes = 6;\r
-\r
- joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;\r
- joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;\r
- joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;\r
- joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;\r
- joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;\r
- joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;\r
- joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;\r
- joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;\r
- joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;\r
- joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;\r
- joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;\r
- joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;\r
- }\r
-\r
- /* Guess all the rest judging on the axes extremals */\r
- for( i = 0; i < joy->num_axes; i++ )\r
- {\r
- joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;\r
- joy->dead_band[ i ] = 0.0f;\r
- joy->saturate [ i ] = 1.0f;\r
- }\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
- for( i = 0; i < _JS_MAX_AXES; i++ )\r
- joy->os->cache_axes[ i ] = 0.0f;\r
-\r
- joy->os->cache_buttons = 0;\r
-\r
- joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);\r
-\r
-#ifdef HAVE_ERRNO_H\r
- if( joy->os->fd < 0 && errno == EACCES )\r
- fgWarning ( "%s exists but is not readable by you", joy->os->fname );\r
-#endif\r
-\r
- joy->error =( joy->os->fd < 0 );\r
-\r
- if( joy->error )\r
- return;\r
-\r
- joy->num_axes = 0;\r
- joy->num_buttons = 0;\r
- if( joy->os->is_analog )\r
- {\r
- FILE *joyfile;\r
- char joyfname[ 1024 ];\r
- int noargs, in_no_axes;\r
-\r
- float axes [ _JS_MAX_AXES ];\r
- int buttons[ _JS_MAX_AXES ];\r
-\r
- joy->num_axes = 2;\r
- joy->num_buttons = 32;\r
-\r
- fghJoystickRawRead( joy, buttons, axes );\r
- joy->error = axes[ 0 ] < -1000000000.0f;\r
- if( joy->error )\r
- return;\r
-\r
- snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );\r
-\r
- joyfile = fopen( joyfname, "r" );\r
- joy->error =( joyfile == NULL );\r
- if( joy->error )\r
- return;\r
-\r
- noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,\r
- &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],\r
- &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );\r
- joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;\r
- fclose( joyfile );\r
- if( joy->error )\r
- return;\r
-\r
- for( i = 0; i < _JS_MAX_AXES; i++ )\r
- {\r
- joy->dead_band[ i ] = 0.0f;\r
- joy->saturate [ i ] = 1.0f;\r
- }\r
-\r
- return; /* End of analog code */\r
- }\r
-\r
-# ifdef HAVE_USB_JS\r
- if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,\r
- &joy->num_buttons ) )\r
- {\r
- close( joy->os->fd );\r
- joy->error = GL_TRUE;\r
- return;\r
- }\r
-\r
- cp = strrchr( joy->os->fname, '/' );\r
- if( cp )\r
- {\r
- if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==\r
- 0 )\r
- strcpy( joy->name, &cp[1] );\r
- }\r
-\r
- if( joy->num_axes > _JS_MAX_AXES )\r
- joy->num_axes = _JS_MAX_AXES;\r
-\r
- for( i = 0; i < _JS_MAX_AXES; i++ )\r
- {\r
- /* We really should get this from the HID, but that data seems\r
- * to be quite unreliable for analog-to-USB converters. Punt for\r
- * now.\r
- */\r
- if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )\r
- {\r
- joy->max [ i ] = 1.0f;\r
- joy->center[ i ] = 0.0f;\r
- joy->min [ i ] = -1.0f;\r
- }\r
- else\r
- {\r
- joy->max [ i ] = 255.0f;\r
- joy->center[ i ] = 127.0f;\r
- joy->min [ i ] = 0.0f;\r
- }\r
-\r
- joy->dead_band[ i ] = 0.0f;\r
- joy->saturate[ i ] = 1.0f;\r
- }\r
-# endif\r
-#endif\r
-\r
-#if defined( __linux__ ) || TARGET_HOST_SOLARIS\r
- /* Default for older Linux systems. */\r
- joy->num_axes = 2;\r
- joy->num_buttons = 32;\r
-\r
-# ifdef JS_NEW\r
- for( i = 0; i < _JS_MAX_AXES; i++ )\r
- joy->tmp_axes[ i ] = 0.0f;\r
-\r
- joy->tmp_buttons = 0;\r
-# endif\r
-\r
- joy->fd = open( joy->fname, O_RDONLY );\r
-\r
- joy->error =( joy->fd < 0 );\r
-\r
- if( joy->error )\r
- return;\r
-\r
- /* Set the correct number of axes for the linux driver */\r
-# ifdef JS_NEW\r
- /* Melchior Franz's fixes for big-endian Linuxes since writing\r
- * to the upper byte of an uninitialized word doesn't work.\r
- * 9 April 2003\r
- */\r
- ioctl( joy->fd, JSIOCGAXES, &u );\r
- joy->num_axes = u;\r
- ioctl( joy->fd, JSIOCGBUTTONS, &u );\r
- joy->num_buttons = u;\r
- ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );\r
- fcntl( joy->fd, F_SETFL, O_NONBLOCK );\r
-# endif\r
-\r
- /*\r
- * The Linux driver seems to return 512 for all axes\r
- * when no stick is present - but there is a chance\r
- * that could happen by accident - so it's gotta happen\r
- * on both axes for at least 100 attempts.\r
- *\r
- * PWO: shouldn't be that done somehow wiser on the kernel level?\r
- */\r
-# ifndef JS_NEW\r
- counter = 0;\r
-\r
- do\r
- {\r
- fghJoystickRawRead( joy, NULL, joy->center );\r
- counter++;\r
- } while( !joy->error &&\r
- counter < 100 &&\r
- joy->center[ 0 ] == 512.0f &&\r
- joy->center[ 1 ] == 512.0f );\r
-\r
- if ( counter >= 100 )\r
- joy->error = GL_TRUE;\r
-# endif\r
-\r
- for( i = 0; i < _JS_MAX_AXES; i++ )\r
- {\r
-# ifdef JS_NEW\r
- joy->max [ i ] = 32767.0f;\r
- joy->center[ i ] = 0.0f;\r
- joy->min [ i ] = -32767.0f;\r
-# else\r
- joy->max[ i ] = joy->center[ i ] * 2.0f;\r
- joy->min[ i ] = 0.0f;\r
-# endif\r
- joy->dead_band[ i ] = 0.0f;\r
- joy->saturate [ i ] = 1.0f;\r
- }\r
-#endif\r
-#endif\r
-}\r
-\r
-/*\r
- * This function replaces the constructor method in the JS library.\r
- */\r
-static void fghJoystickInit( int ident )\r
-{\r
- if( ident >= MAX_NUM_JOYSTICKS )\r
- fgError( "Too large a joystick number: %d", ident );\r
-\r
- if( fgJoystick[ ident ] )\r
- fgError( "illegal attempt to initialize joystick device again" );\r
-\r
- fgJoystick[ ident ] =\r
- ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );\r
-\r
- /* Set defaults */\r
- fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;\r
- fgJoystick[ ident ]->error = GL_TRUE;\r
-\r
- fgPlatformJoystickInit( fgJoystick, ident );\r
-\r
- fghJoystickOpen( fgJoystick[ ident ] );\r
-}\r
-\r
-/*\r
- * Try initializing all the joysticks (well, both of them)\r
- */\r
-void fgInitialiseJoysticks ( void )\r
-{\r
- if( !fgState.JoysticksInitialised )\r
- {\r
- int ident ;\r
- for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )\r
- fghJoystickInit( ident );\r
-\r
- fgState.JoysticksInitialised = GL_TRUE;\r
- }\r
-}\r
-\r
-\r
-void fgJoystickClose( void )\r
-{\r
- int ident ;\r
- for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )\r
- {\r
- if( fgJoystick[ ident ] )\r
- {\r
- fgPlatformJoystickClose ( ident );\r
-\r
- free( fgJoystick[ ident ] );\r
- fgJoystick[ ident ] = NULL;\r
- /* show joystick has been deinitialized */\r
- }\r
- }\r
-}\r
-\r
-/*\r
- * Polls the joystick and executes the joystick callback hooked to the\r
- * window specified in the function's parameter:\r
- */\r
-void fgJoystickPollWindow( SFG_Window* window )\r
-{\r
- float axes[ _JS_MAX_AXES ];\r
- int buttons;\r
- int ident;\r
-\r
- freeglut_return_if_fail( window );\r
- freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );\r
-\r
- for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )\r
- {\r
- if( fgJoystick[ident] )\r
- {\r
- fghJoystickRead( fgJoystick[ident], &buttons, axes );\r
-\r
- if( !fgJoystick[ident]->error )\r
- INVOKE_WCB( *window, Joystick,\r
- ( buttons,\r
- (int) ( axes[ 0 ] * 1000.0f ),\r
- (int) ( axes[ 1 ] * 1000.0f ),\r
- (int) ( axes[ 2 ] * 1000.0f ) )\r
- );\r
- }\r
- }\r
-}\r
-\r
-/*\r
- * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)\r
- */\r
-int fgJoystickDetect( void )\r
-{\r
- int ident;\r
-\r
- fgInitialiseJoysticks ();\r
-\r
- if ( !fgState.JoysticksInitialised )\r
- return 0;\r
-\r
- for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )\r
- if( fgJoystick[ident] && !fgJoystick[ident]->error )\r
- return 1;\r
-\r
- return 0;\r
-}\r
-\r
-/*\r
- * Joystick information functions\r
- */\r
-int glutJoystickGetNumAxes( int ident )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );\r
- return fgJoystick[ ident ]->num_axes;\r
-}\r
-int glutJoystickGetNumButtons( int ident )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );\r
- return fgJoystick[ ident ]->num_buttons;\r
-}\r
-int glutJoystickNotWorking( int ident )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );\r
- return fgJoystick[ ident ]->error;\r
-}\r
-\r
-float glutJoystickGetDeadBand( int ident, int axis )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );\r
- return fgJoystick[ ident ]->dead_band [ axis ];\r
-}\r
-void glutJoystickSetDeadBand( int ident, int axis, float db )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );\r
- fgJoystick[ ident ]->dead_band[ axis ] = db;\r
-}\r
-\r
-float glutJoystickGetSaturation( int ident, int axis )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );\r
- return fgJoystick[ ident ]->saturate[ axis ];\r
-}\r
-void glutJoystickSetSaturation( int ident, int axis, float st )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );\r
- fgJoystick[ ident ]->saturate [ axis ] = st;\r
-}\r
-\r
-void glutJoystickSetMinRange( int ident, float *axes )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );\r
- memcpy( fgJoystick[ ident ]->min, axes,\r
- fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickSetMaxRange( int ident, float *axes )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );\r
- memcpy( fgJoystick[ ident ]->max, axes,\r
- fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickSetCenter( int ident, float *axes )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );\r
- memcpy( fgJoystick[ ident ]->center, axes,\r
- fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-\r
-void glutJoystickGetMinRange( int ident, float *axes )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );\r
- memcpy( axes, fgJoystick[ ident ]->min,\r
- fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickGetMaxRange( int ident, float *axes )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );\r
- memcpy( axes, fgJoystick[ ident ]->max,\r
- fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-void glutJoystickGetCenter( int ident, float *axes )\r
-{\r
- FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );\r
- memcpy( axes, fgJoystick[ ident ]->center,\r
- fgJoystick[ ident ]->num_axes * sizeof( float ) );\r
-}\r
-\r
-/*** END OF FILE ***/\r
+/*
+ * freeglut_joystick.c
+ *
+ * Joystick handling code
+ *
+ * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
+ * Written by Steve Baker, <sjbaker1@airmail.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
+ *
+ * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
+ * Many thanks for Steve Baker for permission to pull from that library.
+ */
+
+#include <GL/freeglut.h>
+#include "freeglut_internal.h"
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#define JS_TRUE 1
+#define JS_FALSE 0
+
+/* BSD defines from "jsBSD.cxx" around lines 42-270 */
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+# ifdef HAVE_USB_JS
+# if defined(__NetBSD__)
+/* XXX The below hack is done until freeglut's autoconf is updated. */
+# define HAVE_USBHID_H 1
+# ifdef HAVE_USBHID_H
+# include <usbhid.h>
+# else
+# include <usb.h>
+# endif
+# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# ifdef HAVE_USBHID_H
+# include <usbhid.h>
+# else
+# include <libusbhid.h>
+# endif
+# endif
+# include <legacy/dev/usb/usb.h>
+# include <dev/usb/usbhid.h>
+
+/* Compatibility with older usb.h revisions */
+# if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
+# define USB_MAX_DEVNAMES MAXDEVNAMES
+# endif
+# endif
+
+static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
+static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
+struct os_specific_s {
+ char fname [128 ];
+ int fd;
+ int is_analog;
+ /* The following structure members are specific to analog joysticks */
+ struct joystick ajs;
+# ifdef HAVE_USB_JS
+ /* The following structure members are specific to USB joysticks */
+ struct hid_item *hids;
+ int hid_dlen;
+ int hid_offset;
+ char *hid_data_buf;
+ int axes_usage [ _JS_MAX_AXES ];
+# endif
+ /* We keep button and axes state ourselves, as they might not be updated
+ * on every read of a USB device
+ */
+ int cache_buttons;
+ float cache_axes [ _JS_MAX_AXES ];
+};
+
+/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
+# define USB_IDENT_OFFSET 2
+
+# define USBDEV "/dev/usb"
+# define UHIDDEV "/dev/uhid"
+# define AJSDEV "/dev/joy"
+
+# ifdef HAVE_USB_JS
+/*
+ * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
+ * the full name of a USB device. If /dev/usbN isn't readable, we punt and
+ * return the uhidN device name. We warn the user of this situation once.
+ */
+static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
+{
+ struct usb_device_info di;
+ int i, a;
+ char *cp;
+
+ for (a = 1; a < USB_MAX_DEVICES; a++) {
+ di.udi_addr = a;
+ if (ioctl(f, USB_DEVICEINFO, &di) != 0)
+ return NULL;
+ for (i = 0; i < USB_MAX_DEVNAMES; i++)
+ if (di.udi_devnames[i][0] &&
+ strcmp(di.udi_devnames[i], dev) == 0) {
+ cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
+ strcpy(cp, di.udi_vendor);
+ strcat(cp, " ");
+ strcat(cp, di.udi_product);
+ strncpy(out, cp, outlen - 1);
+ out[outlen - 1] = 0;
+ free( cp );
+ return out;
+ }
+ }
+ return NULL;
+}
+
+static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
+{
+ int i, f;
+ char buf[50];
+ char *cp;
+ static int protection_warned = 0;
+
+ for (i = 0; i < 16; i++) {
+ snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
+ f = open(buf, O_RDONLY);
+ if (f >= 0) {
+ cp = fghJoystickWalkUSBdev(f, name, out, outlen);
+ close(f);
+ if (cp)
+ return 1;
+ }
+#ifdef HAVE_ERRNO_H
+ else if (errno == EACCES) {
+ if (!protection_warned) {
+ fgWarning ( "Can't open %s for read!", buf );
+ protection_warned = 1;
+ }
+ }
+#endif
+ }
+ return 0;
+}
+
+static int fghJoystickInitializeHID(struct os_specific_s *os,
+ int *num_axes, int *num_buttons)
+{
+ int size, is_joystick;
+# ifdef HAVE_USBHID_H
+ int report_id = 0;
+# endif
+ struct hid_data *d;
+ struct hid_item h;
+ report_desc_t rd;
+
+ if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
+ {
+#ifdef HAVE_ERRNO_H
+ fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
+#else
+ fgWarning ( "error: %s", os->fname );
+#endif
+ return FALSE;
+ }
+
+ os->hids = NULL;
+
+# ifdef HAVE_USBHID_H
+ if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
+ {
+ /*** XXX {report_id} may not be the right variable? ***/
+#ifdef HAVE_ERRNO_H
+ fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
+#else
+ fgWarning ( "error: %s%d", UHIDDEV, report_id );
+#endif
+ return FALSE;
+ }
+
+ size = hid_report_size( rd, hid_input, report_id );
+# else
+ size = hid_report_size( rd, 0, hid_input );
+# endif
+ os->hid_data_buf = calloc( 1, size );
+ os->hid_dlen = size;
+
+ is_joystick = 0;
+# ifdef HAVE_USBHID_H
+ d = hid_start_parse( rd, 1 << hid_input, report_id );
+# else
+ d = hid_start_parse( rd, 1 << hid_input );
+# endif
+ while( hid_get_item( d, &h ) )
+ {
+ int usage, page, interesting_hid;
+
+ page = HID_PAGE( h.usage );
+ usage = HID_USAGE( h.usage );
+
+ /* This test is somewhat too simplistic, but this is how MicroSoft
+ * does, so I guess it works for all joysticks/game pads. */
+ is_joystick = is_joystick ||
+ ( h.kind == hid_collection &&
+ page == HUP_GENERIC_DESKTOP &&
+ ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
+
+ if( h.kind != hid_input )
+ continue;
+
+ if( !is_joystick )
+ continue;
+
+ interesting_hid = TRUE;
+ if( page == HUP_GENERIC_DESKTOP )
+ {
+ switch( usage )
+ {
+ case HUG_X:
+ case HUG_RX:
+ case HUG_Y:
+ case HUG_RY:
+ case HUG_Z:
+ case HUG_RZ:
+ case HUG_SLIDER:
+ if( *num_axes < _JS_MAX_AXES )
+ {
+ os->axes_usage[ *num_axes ] = usage;
+ ( *num_axes )++;
+ }
+ break;
+ case HUG_HAT_SWITCH:
+ /* Allocate two axes for a hat */
+ if( *num_axes + 1 < _JS_MAX_AXES )
+ {
+ os->axes_usage[ *num_axes ] = usage;
+ (*num_axes)++;
+ os->axes_usage[ *num_axes ] = usage;
+ (*num_axes)++;
+ }
+ break;
+ default:
+ interesting_hid = FALSE;
+ break;
+ }
+ }
+ else if( page == HUP_BUTTON )
+ {
+ interesting_hid = ( usage > 0 ) &&
+ ( usage <= _JS_MAX_BUTTONS );
+
+ if( interesting_hid && usage - 1 > *num_buttons )
+ *num_buttons = usage - 1;
+ }
+
+ if( interesting_hid )
+ {
+ h.next = os->hids;
+ os->hids = calloc( 1, sizeof ( struct hid_item ) );
+ *os->hids = h;
+ }
+ }
+ hid_end_parse( d );
+
+ return os->hids != NULL;
+}
+# endif
+#endif
+
+/*
+ * Functions associated with the "jsJoystick" class in PLIB
+ */
+#if TARGET_HOST_MAC_OSX
+#define K_NUM_DEVICES 32
+int numDevices;
+io_object_t ioDevices[K_NUM_DEVICES];
+
+static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
+static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
+
+static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
+/* callback for CFArrayApply */
+static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
+
+static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
+static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
+static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
+#endif
+
+
+/* External function declarations (mostly platform-specific) */
+extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
+extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
+extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
+extern void fgPlatformJoystickClose ( int ident );
+
+/*
+ * The static joystick structure pointer
+ */
+#define MAX_NUM_JOYSTICKS 2
+SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
+
+/*
+ * Read the raw joystick data
+ */
+static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+ int i;
+
+ /* Defaults */
+ if( buttons )
+ *buttons = 0;
+
+ if( axes )
+ for( i = 0; i < joy->num_axes; i++ )
+ axes[ i ] = 1500.0f;
+
+ if( joy->error )
+ return;
+
+ fgPlatformJoystickRawRead ( joy, buttons, axes );
+}
+
+/*
+ * Correct the joystick axis data
+ */
+static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
+{
+ if( value < joy->center[ axis ] )
+ {
+ float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
+ joy->min[ axis ] );
+
+ if( xx < -joy->saturate[ axis ] )
+ return -1.0f;
+
+ if( xx > -joy->dead_band [ axis ] )
+ return 0.0f;
+
+ xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
+ joy->dead_band[ axis ] );
+
+ return ( xx < -1.0f ) ? -1.0f : xx;
+ }
+ else
+ {
+ float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
+ joy->center[ axis ] );
+
+ if( xx > joy->saturate[ axis ] )
+ return 1.0f;
+
+ if( xx < joy->dead_band[ axis ] )
+ return 0.0f;
+
+ xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
+ joy->dead_band[ axis ] );
+
+ return ( xx > 1.0f ) ? 1.0f : xx;
+ }
+}
+
+/*
+ * Read the corrected joystick data
+ */
+static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+ float raw_axes[ _JS_MAX_AXES ];
+ int i;
+
+ if( joy->error )
+ {
+ if( buttons )
+ *buttons = 0;
+
+ if( axes )
+ for ( i=0; i<joy->num_axes; i++ )
+ axes[ i ] = 0.0f;
+ }
+
+ fghJoystickRawRead( joy, buttons, raw_axes );
+
+ if( axes )
+ for( i=0; i<joy->num_axes; i++ )
+ axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
+}
+
+/*
+ * Happy happy happy joy joy joy (happy new year toudi :D)
+ */
+
+
+#if TARGET_HOST_MAC_OSX
+/** open the IOKit connection, enumerate all the HID devices, add their
+interface references to the static array. We then use the array index
+as the device number when we come to open() the joystick. */
+static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
+{
+ CFMutableDictionaryRef hidMatch = NULL;
+ IOReturn rv = kIOReturnSuccess;
+
+ io_iterator_t hidIterator;
+ io_object_t ioDev;
+
+ /* build a dictionary matching HID devices */
+ hidMatch = IOServiceMatching(kIOHIDDeviceKey);
+
+ rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
+ if (rv != kIOReturnSuccess || !hidIterator) {
+ fgWarning( "no joystick (HID) devices found" );
+ return;
+ }
+
+ /* iterate */
+ while ((ioDev = IOIteratorNext(hidIterator))) {
+ /* filter out keyboard and mouse devices */
+ CFDictionaryRef properties = getCFProperties(ioDev);
+ long usage, page;
+
+ CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
+ CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
+ CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
+ CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
+
+ /* keep only joystick devices */
+ if ( ( page == kHIDPage_GenericDesktop ) && (
+ (usage == kHIDUsage_GD_Joystick)
+ || (usage == kHIDUsage_GD_GamePad)
+ || (usage == kHIDUsage_GD_MultiAxisController)
+ || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
+ /* add it to the array */
+ ioDevices[numDevices++] = ioDev;
+ }
+
+ IOObjectRelease(hidIterator);
+}
+
+static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
+{
+ IOReturn rv;
+ CFMutableDictionaryRef cfProperties;
+
+#if 0
+ /* comment copied from darwin/SDL_sysjoystick.c */
+ /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
+ * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
+ */
+
+ io_registry_entry_t parent1, parent2;
+
+ rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
+ if (rv != kIOReturnSuccess) {
+ fgWarning ( "error getting device entry parent");
+ return NULL;
+ }
+
+ rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
+ if (rv != kIOReturnSuccess) {
+ fgWarning ( "error getting device entry parent 2");
+ return NULL;
+ }
+#endif
+
+ rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
+ &cfProperties, kCFAllocatorDefault, kNilOptions);
+ if (rv != kIOReturnSuccess || !cfProperties) {
+ fgWarning ( "error getting device properties");
+ return NULL;
+ }
+
+ return cfProperties;
+}
+
+static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
+{
+ if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
+ fgError ( "%s", "element enumerator passed non-dictionary value");
+ return;
+ }
+
+ static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
+}
+
+/** element enumerator function : pass NULL for top-level*/
+static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
+{
+ FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
+ "Joystick element type mismatch",
+ "fghJoystickEnumerateElements" );
+
+ CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
+ CFArrayApplyFunction((CFArrayRef) element, range,
+ &fghJoystickElementEnumerator, joy );
+}
+
+static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
+{
+ long cookie, lmin, lmax;
+ int index = joy->num_axes++;
+
+ CFNumberGetValue ((CFNumberRef)
+ CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
+ kCFNumberLongType, &cookie);
+
+ joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;
+
+ CFNumberGetValue ((CFNumberRef)
+ CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
+ kCFNumberLongType, &lmin);
+
+ CFNumberGetValue ((CFNumberRef)
+ CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
+ kCFNumberLongType, &lmax);
+
+ joy->min[index] = lmin;
+ joy->max[index] = lmax;
+ joy->dead_band[index] = 0.0;
+ joy->saturate[index] = 1.0;
+ joy->center[index] = (lmax + lmin) * 0.5;
+}
+
+static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
+{
+ long cookie;
+ CFNumberGetValue ((CFNumberRef)
+ CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
+ kCFNumberLongType, &cookie);
+
+ joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
+ /* anything else for buttons? */
+}
+
+static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
+{
+ /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
+ /* do we map hats to axes or buttons? */
+}
+#endif
+
+/*
+ * Platform-Specific Code
+ */
+
+#if TARGET_HOST_MACINTOSH
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+ int i;
+
+ if ( buttons )
+ {
+ *buttons = 0;
+
+ for ( i = 0; i < joy->num_buttons; i++ )
+ {
+ UInt32 state;
+ int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);
+ ISP_CHECK_ERR(err)
+
+ *buttons |= state << i;
+ }
+ }
+
+ if ( axes )
+ {
+ for ( i = 0; i < joy->num_axes; i++ )
+ {
+ UInt32 state;
+ int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );
+ ISP_CHECK_ERR(err)
+
+ axes [i] = (float) state;
+ }
+ }
+}
+
+
+void fgPlatformJoystickOpen( SFG_Joystick* joy )
+{
+ int i = 0;
+ OSStatus err;
+
+ /* XXX FIXME: get joystick name in Mac */
+
+ err = ISpStartup( );
+
+ if( err == noErr )
+ {
+#define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
+
+ joy->error = GL_TRUE;
+
+ /* initialize the needs structure */
+ ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =
+ {
+ { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+ { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
+
+ { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
+ };
+
+ memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
+
+
+ /* next two calls allow keyboard and mouse to emulate other input
+ * devices (gamepads, joysticks, etc)
+ */
+ /*
+ err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
+ ISP_CHECK_ERR(err)
+
+
+ err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
+ ISP_CHECK_ERR(err)
+ */
+
+ err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,
+ joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
+ 0 );
+ ISP_CHECK_ERR( err )
+
+ err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
+ 'freeglut', nil, 0, 128, 0 );
+ ISP_CHECK_ERR( err )
+
+ joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;
+ joy->num_axes = ISP_NUM_AXIS;
+
+ for( i = 0; i < joy->num_axes; i++ )
+ {
+ joy->dead_band[ i ] = 0;
+ joy->saturate [ i ] = 1;
+ joy->center [ i ] = kISpAxisMiddle;
+ joy->max [ i ] = kISpAxisMaximum;
+ joy->min [ i ] = kISpAxisMinimum;
+ }
+
+ joy->error = GL_FALSE;
+ }
+ else
+ joy->num_buttons = joy->num_axes = 0;
+}
+
+
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
+{
+ fgJoystick[ ident ]->id = ident;
+ snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */
+ fgJoystick[ ident ]->error = GL_FALSE;
+}
+
+
+void fgPlatformJoystickClose ( int ident )
+{
+ ISpSuspend( );
+ ISpStop( );
+ ISpShutdown( );
+}
+#endif
+
+#if TARGET_HOST_MAC_OSX
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
+{
+ int i;
+
+ if ( buttons != NULL )
+ {
+ *buttons = 0;
+
+ for ( i = 0; i < joy->num_buttons; i++ )
+ {
+ IOHIDEventStruct hidEvent;
+ (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );
+ if ( hidEvent.value )
+ *buttons |= 1 << i;
+ }
+ }
+
+ if ( axes != NULL )
+ {
+ for ( i = 0; i < joy->num_axes; i++ )
+ {
+ IOHIDEventStruct hidEvent;
+ (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );
+ axes[i] = hidEvent.value;
+ }
+ }
+}
+
+
+void fgPlatformJoystickOpen( SFG_Joystick* joy )
+{
+ IOReturn rv;
+ SInt32 score;
+ IOCFPlugInInterface **plugin;
+
+ HRESULT pluginResult;
+
+ CFDictionaryRef props;
+ CFTypeRef topLevelElement;
+
+ if( joy->id >= numDevices )
+ {
+ fgWarning( "device index out of range in fgJoystickOpen()" );
+ return;
+ }
+
+ /* create device interface */
+ rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
+ kIOHIDDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &plugin, &score );
+
+ if( rv != kIOReturnSuccess )
+ {
+ fgWarning( "error creating plugin for io device" );
+ return;
+ }
+
+ pluginResult = ( *plugin )->QueryInterface(
+ plugin,
+ CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
+ &( LPVOID )joy->pJoystick.hidDev
+ );
+
+ if( pluginResult != S_OK )
+ fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
+
+ ( *plugin )->Release( plugin ); /* don't leak a ref */
+ if( joy->pJoystick.hidDev == NULL )
+ return;
+
+ /* store the interface in this instance */
+ rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );
+ if( rv != kIOReturnSuccess )
+ {
+ fgWarning( "error opening device interface");
+ return;
+ }
+
+ props = getCFProperties( ioDevices[ joy->id ] );
+
+ /* recursively enumerate all the bits */
+ CFTypeRef topLevelElement =
+ CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
+ enumerateElements( topLevelElement );
+
+ CFRelease( props );
+}
+
+
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
+{
+ fgJoystick[ ident ]->id = ident;
+ fgJoystick[ ident ]->error = GL_FALSE;
+ fgJoystick[ ident ]->num_axes = 0;
+ fgJoystick[ ident ]->num_buttons = 0;
+
+ if( numDevices < 0 )
+ {
+ /* do first-time init (since we can't over-ride jsInit, hmm */
+ numDevices = 0;
+
+ mach_port_t masterPort;
+ IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
+ if( rv != kIOReturnSuccess )
+ {
+ fgWarning( "error getting master Mach port" );
+ return;
+ }
+ fghJoystickFindDevices( masterPort );
+ }
+
+ if ( ident >= numDevices )
+ {
+ fgJoystick[ ident ]->error = GL_TRUE;
+ return;
+ }
+
+ /* get the name now too */
+ CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
+ CFTypeRef ref = CFDictionaryGetValue( properties,
+ CFSTR( kIOHIDProductKey ) );
+ if (!ref)
+ ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
+
+ if( !ref ||
+ !CFStringGetCString( ( CFStringRef )ref, name, 128,
+ CFStringGetSystemEncoding( ) ) )
+ {
+ fgWarning( "error getting device name" );
+ name[ 0 ] = '\0';
+ }
+}
+
+
+void fgPlatformJoystickClose ( int ident )
+{
+ ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->
+ close( fgJoystick[ ident ]->pJoystick.hidDev );
+}
+#endif
+
+
+
+
+static void fghJoystickOpen( SFG_Joystick* joy )
+{
+ /*
+ * Default values (for no joystick -- each conditional will reset the
+ * error flag)
+ */
+ joy->error = TRUE;
+ joy->num_axes = joy->num_buttons = 0;
+ joy->name[ 0 ] = '\0';
+
+ fgPlatformJoystickOpen ( joy );
+
+}
+
+/*
+ * This function replaces the constructor method in the JS library.
+ */
+static void fghJoystickInit( int ident )
+{
+ if( ident >= MAX_NUM_JOYSTICKS )
+ fgError( "Too large a joystick number: %d", ident );
+
+ if( fgJoystick[ ident ] )
+ fgError( "illegal attempt to initialize joystick device again" );
+
+ fgJoystick[ ident ] =
+ ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
+
+ /* Set defaults */
+ fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
+ fgJoystick[ ident ]->error = GL_TRUE;
+
+ fgPlatformJoystickInit( fgJoystick, ident );
+
+ fghJoystickOpen( fgJoystick[ ident ] );
+}
+
+/*
+ * Try initializing all the joysticks (well, both of them)
+ */
+void fgInitialiseJoysticks ( void )
+{
+ if( !fgState.JoysticksInitialised )
+ {
+ int ident ;
+ for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+ fghJoystickInit( ident );
+
+ fgState.JoysticksInitialised = GL_TRUE;
+ }
+}
+
+
+void fgJoystickClose( void )
+{
+ int ident ;
+ for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+ {
+ if( fgJoystick[ ident ] )
+ {
+ fgPlatformJoystickClose ( ident );
+
+ free( fgJoystick[ ident ] );
+ fgJoystick[ ident ] = NULL;
+ /* show joystick has been deinitialized */
+ }
+ }
+}
+
+/*
+ * Polls the joystick and executes the joystick callback hooked to the
+ * window specified in the function's parameter:
+ */
+void fgJoystickPollWindow( SFG_Window* window )
+{
+ float axes[ _JS_MAX_AXES ];
+ int buttons;
+ int ident;
+
+ freeglut_return_if_fail( window );
+ freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
+
+ for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
+ {
+ if( fgJoystick[ident] )
+ {
+ fghJoystickRead( fgJoystick[ident], &buttons, axes );
+
+ if( !fgJoystick[ident]->error )
+ INVOKE_WCB( *window, Joystick,
+ ( buttons,
+ (int) ( axes[ 0 ] * 1000.0f ),
+ (int) ( axes[ 1 ] * 1000.0f ),
+ (int) ( axes[ 2 ] * 1000.0f ) )
+ );
+ }
+ }
+}
+
+/*
+ * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
+ */
+int fgJoystickDetect( void )
+{
+ int ident;
+
+ fgInitialiseJoysticks ();
+
+ if ( !fgState.JoysticksInitialised )
+ return 0;
+
+ for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
+ if( fgJoystick[ident] && !fgJoystick[ident]->error )
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Joystick information, setup and execution functions
+ */
+
+/*
+ * Forces the joystick callback to be executed
+ */
+void FGAPIENTRY glutForceJoystickFunc( void )
+{
+ FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutForceJoystickFunc" );
+#if !defined(_WIN32_WCE)
+ freeglut_return_if_fail( fgStructure.CurrentWindow != NULL );
+ freeglut_return_if_fail( FETCH_WCB( *( fgStructure.CurrentWindow ), Joystick ) );
+ fgJoystickPollWindow( fgStructure.CurrentWindow );
+#endif /* !defined(_WIN32_WCE) */
+}
+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 ***/