2 * freeglut_joystick.c
\r
4 * Joystick handling code
\r
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
\r
7 * Written by Steve Baker, <sjbaker1@airmail.net>
\r
9 * Permission is hereby granted, free of charge, to any person obtaining a
\r
10 * copy of this software and associated documentation files (the "Software"),
\r
11 * to deal in the Software without restriction, including without limitation
\r
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
\r
13 * and/or sell copies of the Software, and to permit persons to whom the
\r
14 * Software is furnished to do so, subject to the following conditions:
\r
16 * The above copyright notice and this permission notice shall be included
\r
17 * in all copies or substantial portions of the Software.
\r
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
\r
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
\r
22 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
28 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
\r
30 * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
\r
31 * Many thanks for Steve Baker for permission to pull from that library.
\r
34 #include <GL/freeglut.h>
\r
35 #include "freeglut_internal.h"
\r
36 #ifdef HAVE_SYS_PARAM_H
\r
37 # include <sys/param.h>
\r
41 * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
\r
45 #if TARGET_HOST_MACINTOSH
\r
46 # include <InputSprocket.h>
\r
49 #if TARGET_HOST_MAC_OSX
\r
50 # include <mach/mach.h>
\r
51 # include <IOKit/IOkitLib.h>
\r
52 # include <IOKit/hid/IOHIDLib.h>
\r
55 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
56 # include <windows.h>
\r
57 # include <mmsystem.h>
\r
58 # include <regstr.h>
\r
62 #if TARGET_HOST_POSIX_X11
\r
63 # ifdef HAVE_SYS_IOCTL_H
\r
64 # include <sys/ioctl.h>
\r
66 # ifdef HAVE_FCNTL_H
\r
69 # ifdef HAVE_ERRNO_H
\r
71 # include <string.h>
\r
73 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
74 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
75 # define HAVE_USB_JS 1
\r
77 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
78 # include <sys/joystick.h>
\r
81 * XXX NetBSD/amd64 systems may find that they have to steal the
\r
82 * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
\r
83 * XXX I cannot comment whether that works for the interface, but
\r
84 * XXX it lets you compile...(^& I do not think that we can do away
\r
85 * XXX with this header.
\r
87 # include <machine/joystick.h> /* For analog joysticks */
\r
89 # define JS_DATA_TYPE joystick
\r
90 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
93 # if defined(__linux__)
\r
94 # include <linux/joystick.h>
\r
96 /* check the joystick driver version */
\r
97 # if defined(JS_VERSION) && JS_VERSION >= 0x010000
\r
100 # else /* Not BSD or Linux */
\r
104 * We'll put these values in and that should
\r
105 * allow the code to at least compile when there is
\r
106 * no support. The JS open routine should error out
\r
107 * and shut off all the code downstream anyway and if
\r
108 * the application doesn't use a joystick we'll be fine.
\r
111 struct JS_DATA_TYPE
\r
118 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
126 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
\r
128 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
130 # ifdef HAVE_USB_JS
\r
131 # if defined(__NetBSD__)
\r
132 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
133 # define HAVE_USBHID_H 1
\r
134 # ifdef HAVE_USBHID_H
\r
135 # include <usbhid.h>
\r
139 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
140 # ifdef HAVE_USBHID_H
\r
141 # include <usbhid.h>
\r
143 # include <libusbhid.h>
\r
146 # include <legacy/dev/usb/usb.h>
\r
147 # include <dev/usb/usbhid.h>
\r
149 /* Compatibility with older usb.h revisions */
\r
150 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
\r
151 # define USB_MAX_DEVNAMES MAXDEVNAMES
\r
155 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
\r
156 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
\r
157 struct os_specific_s {
\r
161 /* The following structure members are specific to analog joysticks */
\r
162 struct joystick ajs;
\r
163 # ifdef HAVE_USB_JS
\r
164 /* The following structure members are specific to USB joysticks */
\r
165 struct hid_item *hids;
\r
168 char *hid_data_buf;
\r
169 int axes_usage [ _JS_MAX_AXES ];
\r
171 /* We keep button and axes state ourselves, as they might not be updated
\r
172 * on every read of a USB device
\r
175 float cache_axes [ _JS_MAX_AXES ];
\r
178 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
\r
179 # define USB_IDENT_OFFSET 2
\r
181 # define USBDEV "/dev/usb"
\r
182 # define UHIDDEV "/dev/uhid"
\r
183 # define AJSDEV "/dev/joy"
\r
185 # ifdef HAVE_USB_JS
\r
187 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
\r
188 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
\r
189 * return the uhidN device name. We warn the user of this situation once.
\r
191 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
\r
193 struct usb_device_info di;
\r
197 for (a = 1; a < USB_MAX_DEVICES; a++) {
\r
199 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
\r
201 for (i = 0; i < USB_MAX_DEVNAMES; i++)
\r
202 if (di.udi_devnames[i][0] &&
\r
203 strcmp(di.udi_devnames[i], dev) == 0) {
\r
204 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
\r
205 strcpy(cp, di.udi_vendor);
\r
207 strcat(cp, di.udi_product);
\r
208 strncpy(out, cp, outlen - 1);
\r
209 out[outlen - 1] = 0;
\r
217 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
\r
222 static int protection_warned = 0;
\r
224 for (i = 0; i < 16; i++) {
\r
225 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
\r
226 f = open(buf, O_RDONLY);
\r
228 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
\r
233 #ifdef HAVE_ERRNO_H
\r
234 else if (errno == EACCES) {
\r
235 if (!protection_warned) {
\r
236 fgWarning ( "Can't open %s for read!", buf );
\r
237 protection_warned = 1;
\r
245 static int fghJoystickInitializeHID(struct os_specific_s *os,
\r
246 int *num_axes, int *num_buttons)
\r
248 int size, is_joystick;
\r
249 # ifdef HAVE_USBHID_H
\r
252 struct hid_data *d;
\r
256 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
\r
258 #ifdef HAVE_ERRNO_H
\r
259 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
\r
261 fgWarning ( "error: %s", os->fname );
\r
268 # ifdef HAVE_USBHID_H
\r
269 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
\r
271 /*** XXX {report_id} may not be the right variable? ***/
\r
272 #ifdef HAVE_ERRNO_H
\r
273 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
\r
275 fgWarning ( "error: %s%d", UHIDDEV, report_id );
\r
280 size = hid_report_size( rd, hid_input, report_id );
\r
282 size = hid_report_size( rd, 0, hid_input );
\r
284 os->hid_data_buf = calloc( 1, size );
\r
285 os->hid_dlen = size;
\r
288 # ifdef HAVE_USBHID_H
\r
289 d = hid_start_parse( rd, 1 << hid_input, report_id );
\r
291 d = hid_start_parse( rd, 1 << hid_input );
\r
293 while( hid_get_item( d, &h ) )
\r
295 int usage, page, interesting_hid;
\r
297 page = HID_PAGE( h.usage );
\r
298 usage = HID_USAGE( h.usage );
\r
300 /* This test is somewhat too simplistic, but this is how MicroSoft
\r
301 * does, so I guess it works for all joysticks/game pads. */
\r
302 is_joystick = is_joystick ||
\r
303 ( h.kind == hid_collection &&
\r
304 page == HUP_GENERIC_DESKTOP &&
\r
305 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
\r
307 if( h.kind != hid_input )
\r
313 interesting_hid = TRUE;
\r
314 if( page == HUP_GENERIC_DESKTOP )
\r
325 if( *num_axes < _JS_MAX_AXES )
\r
327 os->axes_usage[ *num_axes ] = usage;
\r
331 case HUG_HAT_SWITCH:
\r
332 /* Allocate two axes for a hat */
\r
333 if( *num_axes + 1 < _JS_MAX_AXES )
\r
335 os->axes_usage[ *num_axes ] = usage;
\r
337 os->axes_usage[ *num_axes ] = usage;
\r
342 interesting_hid = FALSE;
\r
346 else if( page == HUP_BUTTON )
\r
348 interesting_hid = ( usage > 0 ) &&
\r
349 ( usage <= _JS_MAX_BUTTONS );
\r
351 if( interesting_hid && usage - 1 > *num_buttons )
\r
352 *num_buttons = usage - 1;
\r
355 if( interesting_hid )
\r
358 os->hids = calloc( 1, sizeof ( struct hid_item ) );
\r
362 hid_end_parse( d );
\r
364 return os->hids != NULL;
\r
370 * Functions associated with the "jsJoystick" class in PLIB
\r
372 #if TARGET_HOST_MAC_OSX
\r
373 #define K_NUM_DEVICES 32
\r
375 io_object_t ioDevices[K_NUM_DEVICES];
\r
377 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
\r
378 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
\r
380 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
\r
381 /* callback for CFArrayApply */
\r
382 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
\r
384 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
\r
385 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
\r
386 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
\r
390 /* External function declarations (mostly platform-specific) */
\r
391 extern void fgPlatformJoystickClose ( int ident );
\r
394 * The static joystick structure pointer
\r
396 #define MAX_NUM_JOYSTICKS 2
\r
397 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
400 * Platform-Specific Code
\r
403 #if TARGET_HOST_MACINTOSH
\r
404 void fgPlatformJoystickClose ( int ident )
\r
412 #if TARGET_HOST_MAC_OSX
\r
413 void fgPlatformJoystickClose ( int ident )
\r
415 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
416 close( fgJoystick[ ident ]->hidDev );
\r
420 #if TARGET_HOST_POSIX_X11
\r
421 void fgPlatformJoystickClose ( int ident )
\r
423 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
424 if( fgJoystick[ident]->os )
\r
426 if( ! fgJoystick[ ident ]->error )
\r
427 close( fgJoystick[ ident ]->os->fd );
\r
429 if( fgJoystick[ ident ]->os->hids )
\r
430 free (fgJoystick[ ident ]->os->hids);
\r
431 if( fgJoystick[ ident ]->os->hid_data_buf )
\r
432 free( fgJoystick[ ident ]->os->hid_data_buf );
\r
434 free( fgJoystick[ident]->os );
\r
438 if( ! fgJoystick[ident]->error )
\r
439 close( fgJoystick[ ident ]->fd );
\r
446 * Read the raw joystick data
\r
448 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
450 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
456 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
467 for( i = 0; i < joy->num_axes; i++ )
\r
468 axes[ i ] = 1500.0f;
\r
473 #if TARGET_HOST_MACINTOSH
\r
478 for ( i = 0; i < joy->num_buttons; i++ )
\r
481 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
484 *buttons |= state << i;
\r
490 for ( i = 0; i < joy->num_axes; i++ )
\r
493 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
496 axes [i] = (float) state;
\r
501 #if TARGET_HOST_MAC_OSX
\r
502 if ( buttons != NULL )
\r
506 for ( i = 0; i < joy->num_buttons; i++ )
\r
508 IOHIDEventStruct hidEvent;
\r
509 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
510 if ( hidEvent.value )
\r
511 *buttons |= 1 << i;
\r
515 if ( axes != NULL )
\r
517 for ( i = 0; i < joy->num_axes; i++ )
\r
519 IOHIDEventStruct hidEvent;
\r
520 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
521 axes[i] = hidEvent.value;
\r
526 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
527 status = joyGetPosEx( joy->js_id, &joy->js );
\r
529 if ( status != JOYERR_NOERROR )
\r
531 joy->error = GL_TRUE;
\r
536 *buttons = joy->js.dwButtons;
\r
541 * WARNING - Fall through case clauses!!
\r
543 switch ( joy->num_axes )
\r
546 /* Generate two POV axes from the POV hat angle.
\r
547 * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
\r
548 * hundredths of a degree, or 0xFFFF when idle.
\r
550 if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
\r
557 /* This is the contentious bit: how to convert angle to X/Y.
\r
558 * wk: I know of no define for PI that we could use here:
\r
559 * SG_PI would pull in sg, M_PI is undefined for MSVC
\r
560 * But the accuracy of the value of PI is very unimportant at
\r
563 float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
564 float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
566 /* Convert to coordinates on a square so that North-East
\r
567 * is (1,1) not (.7,.7), etc.
\r
568 * s and c cannot both be zero so we won't divide by zero.
\r
570 if ( fabs ( s ) < fabs ( c ) )
\r
572 axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;
\r
573 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
\r
577 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
\r
578 axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;
\r
582 case 6: axes[5] = (float) joy->js.dwVpos;
\r
583 case 5: axes[4] = (float) joy->js.dwUpos;
\r
584 case 4: axes[3] = (float) joy->js.dwRpos;
\r
585 case 3: axes[2] = (float) joy->js.dwZpos;
\r
586 case 2: axes[1] = (float) joy->js.dwYpos;
\r
587 case 1: axes[0] = (float) joy->js.dwXpos;
\r
592 #if TARGET_HOST_POSIX_X11
\r
593 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
594 if ( joy->os->is_analog )
\r
596 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
597 if ( status != sizeof(joy->os->ajs) ) {
\r
598 perror ( joy->os->fname );
\r
599 joy->error = GL_TRUE;
\r
602 if ( buttons != NULL )
\r
603 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
605 if ( axes != NULL )
\r
607 axes[0] = (float) joy->os->ajs.x;
\r
608 axes[1] = (float) joy->os->ajs.y;
\r
614 # ifdef HAVE_USB_JS
\r
615 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
617 struct hid_item *h;
\r
619 for ( h = joy->os->hids; h; h = h->next )
\r
621 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
623 int page = HID_PAGE ( h->usage );
\r
624 int usage = HID_USAGE ( h->usage );
\r
626 if ( page == HUP_GENERIC_DESKTOP )
\r
629 for ( i = 0; i < joy->num_axes; i++ )
\r
630 if (joy->os->axes_usage[i] == usage)
\r
632 if (usage == HUG_HAT_SWITCH)
\r
634 if (d < 0 || d > 8)
\r
635 d = 0; /* safety */
\r
636 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
637 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
641 joy->os->cache_axes[i] = (float)d;
\r
646 else if (page == HUP_BUTTON)
\r
648 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
651 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
653 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
658 #ifdef HAVE_ERRNO_H
\r
659 if ( len < 0 && errno != EAGAIN )
\r
664 perror( joy->os->fname );
\r
667 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
668 if ( axes != NULL )
\r
669 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
677 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
679 if ( status != sizeof( struct js_event ) )
\r
681 #ifdef HAVE_ERRNO_H
\r
682 if ( errno == EAGAIN )
\r
684 /* Use the old values */
\r
686 *buttons = joy->tmp_buttons;
\r
688 memcpy( axes, joy->tmp_axes,
\r
689 sizeof( float ) * joy->num_axes );
\r
694 fgWarning ( "%s", joy->fname );
\r
695 joy->error = GL_TRUE;
\r
699 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
701 case JS_EVENT_BUTTON:
\r
702 if( joy->js.value == 0 ) /* clear the flag */
\r
703 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
705 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
708 case JS_EVENT_AXIS:
\r
709 if ( joy->js.number < joy->num_axes )
\r
711 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
714 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
719 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
721 /* use the old values */
\r
723 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
724 if ( axes != NULL )
\r
725 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
731 *buttons = joy->tmp_buttons;
\r
735 status = read( joy->fd, &joy->js, JS_RETURN );
\r
737 if ( status != JS_RETURN )
\r
739 fgWarning( "%s", joy->fname );
\r
740 joy->error = GL_TRUE;
\r
745 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
746 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
748 *buttons = joy->js.buttons;
\r
753 axes[ 0 ] = (float) joy->js.x;
\r
754 axes[ 1 ] = (float) joy->js.y;
\r
761 * Correct the joystick axis data
\r
763 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
765 if( value < joy->center[ axis ] )
\r
767 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
768 joy->min[ axis ] );
\r
770 if( xx < -joy->saturate[ axis ] )
\r
773 if( xx > -joy->dead_band [ axis ] )
\r
776 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
777 joy->dead_band[ axis ] );
\r
779 return ( xx < -1.0f ) ? -1.0f : xx;
\r
783 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
784 joy->center[ axis ] );
\r
786 if( xx > joy->saturate[ axis ] )
\r
789 if( xx < joy->dead_band[ axis ] )
\r
792 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
793 joy->dead_band[ axis ] );
\r
795 return ( xx > 1.0f ) ? 1.0f : xx;
\r
800 * Read the corrected joystick data
\r
802 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
804 float raw_axes[ _JS_MAX_AXES ];
\r
813 for ( i=0; i<joy->num_axes; i++ )
\r
817 fghJoystickRawRead( joy, buttons, raw_axes );
\r
820 for( i=0; i<joy->num_axes; i++ )
\r
821 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
825 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
829 #if TARGET_HOST_MAC_OSX
\r
830 /** open the IOKit connection, enumerate all the HID devices, add their
\r
831 interface references to the static array. We then use the array index
\r
832 as the device number when we come to open() the joystick. */
\r
833 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
835 CFMutableDictionaryRef hidMatch = NULL;
\r
836 IOReturn rv = kIOReturnSuccess;
\r
838 io_iterator_t hidIterator;
\r
841 /* build a dictionary matching HID devices */
\r
842 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
844 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
845 if (rv != kIOReturnSuccess || !hidIterator) {
\r
846 fgWarning( "no joystick (HID) devices found" );
\r
851 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
852 /* filter out keyboard and mouse devices */
\r
853 CFDictionaryRef properties = getCFProperties(ioDev);
\r
856 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
857 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
858 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
859 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
861 /* keep only joystick devices */
\r
862 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
863 (usage == kHIDUsage_GD_Joystick)
\r
864 || (usage == kHIDUsage_GD_GamePad)
\r
865 || (usage == kHIDUsage_GD_MultiAxisController)
\r
866 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
867 /* add it to the array */
\r
868 ioDevices[numDevices++] = ioDev;
\r
871 IOObjectRelease(hidIterator);
\r
874 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
877 CFMutableDictionaryRef cfProperties;
\r
880 /* comment copied from darwin/SDL_sysjoystick.c */
\r
881 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
882 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
885 io_registry_entry_t parent1, parent2;
\r
887 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
888 if (rv != kIOReturnSuccess) {
\r
889 fgWarning ( "error getting device entry parent");
\r
893 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
894 if (rv != kIOReturnSuccess) {
\r
895 fgWarning ( "error getting device entry parent 2");
\r
900 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
901 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
902 if (rv != kIOReturnSuccess || !cfProperties) {
\r
903 fgWarning ( "error getting device properties");
\r
907 return cfProperties;
\r
910 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
912 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
913 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
917 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
920 /** element enumerator function : pass NULL for top-level*/
\r
921 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
923 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
924 "Joystick element type mismatch",
\r
925 "fghJoystickEnumerateElements" );
\r
927 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
928 CFArrayApplyFunction((CFArrayRef) element, range,
\r
929 &fghJoystickElementEnumerator, joy );
\r
932 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
934 long cookie, lmin, lmax;
\r
935 int index = joy->num_axes++;
\r
937 CFNumberGetValue ((CFNumberRef)
\r
938 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
939 kCFNumberLongType, &cookie);
\r
941 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
943 CFNumberGetValue ((CFNumberRef)
\r
944 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
945 kCFNumberLongType, &lmin);
\r
947 CFNumberGetValue ((CFNumberRef)
\r
948 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
949 kCFNumberLongType, &lmax);
\r
951 joy->min[index] = lmin;
\r
952 joy->max[index] = lmax;
\r
953 joy->dead_band[index] = 0.0;
\r
954 joy->saturate[index] = 1.0;
\r
955 joy->center[index] = (lmax + lmin) * 0.5;
\r
958 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
961 CFNumberGetValue ((CFNumberRef)
\r
962 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
963 kCFNumberLongType, &cookie);
\r
965 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
966 /* anything else for buttons? */
\r
969 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
971 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
972 /* do we map hats to axes or buttons? */
\r
976 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
978 http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
\r
980 # if FREEGLUT_LIB_PRAGMAS
\r
981 # pragma comment (lib, "advapi32.lib")
\r
984 static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )
\r
986 char buffer [ 256 ];
\r
988 char OEMKey [ 256 ];
\r
997 /* Open .. MediaResources\CurrentJoystickSettings */
\r
998 _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",
\r
999 REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,
\r
1000 REGSTR_KEY_JOYCURR );
\r
1002 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
\r
1004 if ( lr != ERROR_SUCCESS ) return 0;
\r
1006 /* Get OEM Key name */
\r
1007 dwcb = sizeof(OEMKey);
\r
1009 /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */
\r
1010 _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );
\r
1012 lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);
\r
1013 RegCloseKey ( hKey );
\r
1015 if ( lr != ERROR_SUCCESS ) return 0;
\r
1017 /* Open OEM Key from ...MediaProperties */
\r
1018 _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );
\r
1020 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );
\r
1022 if ( lr != ERROR_SUCCESS ) return 0;
\r
1024 /* Get OEM Name */
\r
1027 lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,
\r
1029 RegCloseKey ( hKey );
\r
1031 if ( lr != ERROR_SUCCESS ) return 0;
\r
1038 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1041 #if TARGET_HOST_MACINTOSH
\r
1044 #if TARGET_HOST_MAC_OSX
\r
1047 IOCFPlugInInterface **plugin;
\r
1049 HRESULT pluginResult;
\r
1051 CFDictionaryRef props;
\r
1052 CFTypeRef topLevelElement;
\r
1054 #if TARGET_HOST_POSIX_X11
\r
1055 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1061 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1067 /* Silence gcc, the correct #ifdefs would be too fragile... */
\r
1071 * Default values (for no joystick -- each conditional will reset the
\r
1074 joy->error = TRUE;
\r
1075 joy->num_axes = joy->num_buttons = 0;
\r
1076 joy->name[ 0 ] = '\0';
\r
1078 #if TARGET_HOST_MACINTOSH
\r
1079 /* XXX FIXME: get joystick name in Mac */
\r
1081 err = ISpStartup( );
\r
1083 if( err == noErr )
\r
1085 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
1087 joy->error = GL_TRUE;
\r
1089 /* initialize the needs structure */
\r
1090 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
1092 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1093 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1094 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1095 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1096 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1097 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1098 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1099 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1100 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1102 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1103 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1104 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1105 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1106 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1107 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1108 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1109 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1110 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1111 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1112 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1113 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1114 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1115 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1116 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1117 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1118 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1119 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1120 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1121 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1122 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1123 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1124 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1125 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1126 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1127 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1128 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1129 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1130 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1131 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1132 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1133 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1136 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
1139 /* next two calls allow keyboard and mouse to emulate other input
\r
1140 * devices (gamepads, joysticks, etc)
\r
1143 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
1144 ISP_CHECK_ERR(err)
\r
1147 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
1148 ISP_CHECK_ERR(err)
\r
1151 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
1152 joy->isp_needs, joy->isp_elem,
\r
1154 ISP_CHECK_ERR( err )
\r
1156 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
1157 'freeglut', nil, 0, 128, 0 );
\r
1158 ISP_CHECK_ERR( err )
\r
1160 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
1161 joy->num_axes = joy->isp_num_axis;
\r
1163 for( i = 0; i < joy->num_axes; i++ )
\r
1165 joy->dead_band[ i ] = 0;
\r
1166 joy->saturate [ i ] = 1;
\r
1167 joy->center [ i ] = kISpAxisMiddle;
\r
1168 joy->max [ i ] = kISpAxisMaximum;
\r
1169 joy->min [ i ] = kISpAxisMinimum;
\r
1172 joy->error = GL_FALSE;
\r
1175 joy->num_buttons = joy->num_axes = 0;
\r
1178 #if TARGET_HOST_MAC_OSX
\r
1179 if( joy->id >= numDevices )
\r
1181 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
1185 /* create device interface */
\r
1186 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
1187 kIOHIDDeviceUserClientTypeID,
\r
1188 kIOCFPlugInInterfaceID,
\r
1189 &plugin, &score );
\r
1191 if( rv != kIOReturnSuccess )
\r
1193 fgWarning( "error creating plugin for io device" );
\r
1197 pluginResult = ( *plugin )->QueryInterface(
\r
1199 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
1200 &( LPVOID )joy->hidDev
\r
1203 if( pluginResult != S_OK )
\r
1204 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
1206 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
1207 if( joy->hidDev == NULL )
\r
1210 /* store the interface in this instance */
\r
1211 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
1212 if( rv != kIOReturnSuccess )
\r
1214 fgWarning( "error opening device interface");
\r
1218 props = getCFProperties( ioDevices[ joy->id ] );
\r
1220 /* recursively enumerate all the bits */
\r
1221 CFTypeRef topLevelElement =
\r
1222 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
1223 enumerateElements( topLevelElement );
\r
1225 CFRelease( props );
\r
1228 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1229 joy->js.dwFlags = JOY_RETURNALL;
\r
1230 joy->js.dwSize = sizeof( joy->js );
\r
1232 memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
\r
1235 ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
\r
1238 if( joy->jsCaps.wNumAxes == 0 )
\r
1240 joy->num_axes = 0;
\r
1241 joy->error = GL_TRUE;
\r
1245 /* Device name from jsCaps is often "Microsoft PC-joystick driver",
\r
1246 * at least for USB. Try to get the real name from the registry.
\r
1248 if ( ! fghJoystickGetOEMProductName( joy, joy->name,
\r
1249 sizeof( joy->name ) ) )
\r
1251 fgWarning( "JS: Failed to read joystick name from registry" );
\r
1252 strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );
\r
1255 /* Windows joystick drivers may provide any combination of
\r
1256 * X,Y,Z,R,U,V,POV - not necessarily the first n of these.
\r
1258 if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )
\r
1260 joy->num_axes = _JS_MAX_AXES;
\r
1261 joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */
\r
1262 joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */
\r
1265 joy->num_axes = 6;
\r
1267 joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;
\r
1268 joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;
\r
1269 joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;
\r
1270 joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;
\r
1271 joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;
\r
1272 joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;
\r
1273 joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;
\r
1274 joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;
\r
1275 joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;
\r
1276 joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;
\r
1277 joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;
\r
1278 joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;
\r
1281 /* Guess all the rest judging on the axes extremals */
\r
1282 for( i = 0; i < joy->num_axes; i++ )
\r
1284 joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
\r
1285 joy->dead_band[ i ] = 0.0f;
\r
1286 joy->saturate [ i ] = 1.0f;
\r
1290 #if TARGET_HOST_POSIX_X11
\r
1291 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1292 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1293 joy->os->cache_axes[ i ] = 0.0f;
\r
1295 joy->os->cache_buttons = 0;
\r
1297 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1299 #ifdef HAVE_ERRNO_H
\r
1300 if( joy->os->fd < 0 && errno == EACCES )
\r
1301 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1304 joy->error =( joy->os->fd < 0 );
\r
1309 joy->num_axes = 0;
\r
1310 joy->num_buttons = 0;
\r
1311 if( joy->os->is_analog )
\r
1314 char joyfname[ 1024 ];
\r
1315 int noargs, in_no_axes;
\r
1317 float axes [ _JS_MAX_AXES ];
\r
1318 int buttons[ _JS_MAX_AXES ];
\r
1320 joy->num_axes = 2;
\r
1321 joy->num_buttons = 32;
\r
1323 fghJoystickRawRead( joy, buttons, axes );
\r
1324 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1328 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1330 joyfile = fopen( joyfname, "r" );
\r
1331 joy->error =( joyfile == NULL );
\r
1335 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1336 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1337 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1338 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1339 fclose( joyfile );
\r
1343 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1345 joy->dead_band[ i ] = 0.0f;
\r
1346 joy->saturate [ i ] = 1.0f;
\r
1349 return; /* End of analog code */
\r
1352 # ifdef HAVE_USB_JS
\r
1353 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1354 &joy->num_buttons ) )
\r
1356 close( joy->os->fd );
\r
1357 joy->error = GL_TRUE;
\r
1361 cp = strrchr( joy->os->fname, '/' );
\r
1364 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1366 strcpy( joy->name, &cp[1] );
\r
1369 if( joy->num_axes > _JS_MAX_AXES )
\r
1370 joy->num_axes = _JS_MAX_AXES;
\r
1372 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1374 /* We really should get this from the HID, but that data seems
\r
1375 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1378 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1380 joy->max [ i ] = 1.0f;
\r
1381 joy->center[ i ] = 0.0f;
\r
1382 joy->min [ i ] = -1.0f;
\r
1386 joy->max [ i ] = 255.0f;
\r
1387 joy->center[ i ] = 127.0f;
\r
1388 joy->min [ i ] = 0.0f;
\r
1391 joy->dead_band[ i ] = 0.0f;
\r
1392 joy->saturate[ i ] = 1.0f;
\r
1397 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1398 /* Default for older Linux systems. */
\r
1399 joy->num_axes = 2;
\r
1400 joy->num_buttons = 32;
\r
1403 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1404 joy->tmp_axes[ i ] = 0.0f;
\r
1406 joy->tmp_buttons = 0;
\r
1409 joy->fd = open( joy->fname, O_RDONLY );
\r
1411 joy->error =( joy->fd < 0 );
\r
1416 /* Set the correct number of axes for the linux driver */
\r
1418 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1419 * to the upper byte of an uninitialized word doesn't work.
\r
1422 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1423 joy->num_axes = u;
\r
1424 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1425 joy->num_buttons = u;
\r
1426 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1427 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1431 * The Linux driver seems to return 512 for all axes
\r
1432 * when no stick is present - but there is a chance
\r
1433 * that could happen by accident - so it's gotta happen
\r
1434 * on both axes for at least 100 attempts.
\r
1436 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1443 fghJoystickRawRead( joy, NULL, joy->center );
\r
1445 } while( !joy->error &&
\r
1447 joy->center[ 0 ] == 512.0f &&
\r
1448 joy->center[ 1 ] == 512.0f );
\r
1450 if ( counter >= 100 )
\r
1451 joy->error = GL_TRUE;
\r
1454 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1457 joy->max [ i ] = 32767.0f;
\r
1458 joy->center[ i ] = 0.0f;
\r
1459 joy->min [ i ] = -32767.0f;
\r
1461 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1462 joy->min[ i ] = 0.0f;
\r
1464 joy->dead_band[ i ] = 0.0f;
\r
1465 joy->saturate [ i ] = 1.0f;
\r
1472 * This function replaces the constructor method in the JS library.
\r
1474 static void fghJoystickInit( int ident )
\r
1476 if( ident >= MAX_NUM_JOYSTICKS )
\r
1477 fgError( "Too large a joystick number: %d", ident );
\r
1479 if( fgJoystick[ ident ] )
\r
1480 fgError( "illegal attempt to initialize joystick device again" );
\r
1482 fgJoystick[ ident ] =
\r
1483 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1485 /* Set defaults */
\r
1486 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1487 fgJoystick[ ident ]->error = GL_TRUE;
\r
1489 #if TARGET_HOST_MACINTOSH
\r
1490 fgJoystick[ ident ]->id = ident;
\r
1491 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
1492 fgJoystick[ ident ]->error = GL_FALSE;
\r
1495 #if TARGET_HOST_MAC_OSX
\r
1496 fgJoystick[ ident ]->id = ident;
\r
1497 fgJoystick[ ident ]->error = GL_FALSE;
\r
1498 fgJoystick[ ident ]->num_axes = 0;
\r
1499 fgJoystick[ ident ]->num_buttons = 0;
\r
1501 if( numDevices < 0 )
\r
1503 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
1506 mach_port_t masterPort;
\r
1507 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
1508 if( rv != kIOReturnSuccess )
\r
1510 fgWarning( "error getting master Mach port" );
\r
1513 fghJoystickFindDevices( masterPort );
\r
1516 if ( ident >= numDevices )
\r
1518 fgJoystick[ ident ]->error = GL_TRUE;
\r
1522 /* get the name now too */
\r
1523 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
1524 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
1525 CFSTR( kIOHIDProductKey ) );
\r
1527 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
1530 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
1531 CFStringGetSystemEncoding( ) ) )
\r
1533 fgWarning( "error getting device name" );
\r
1538 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1542 fgJoystick[ ident ]->js_id = JOYSTICKID1;
\r
1543 fgJoystick[ ident ]->error = GL_FALSE;
\r
1546 fgJoystick[ ident ]->js_id = JOYSTICKID2;
\r
1547 fgJoystick[ ident ]->error = GL_FALSE;
\r
1550 fgJoystick[ ident ]->num_axes = 0;
\r
1551 fgJoystick[ ident ]->error = GL_TRUE;
\r
1556 #if TARGET_HOST_POSIX_X11
\r
1557 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1558 fgJoystick[ ident ]->id = ident;
\r
1559 fgJoystick[ ident ]->error = GL_FALSE;
\r
1561 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1562 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
1563 if( ident < USB_IDENT_OFFSET )
\r
1564 fgJoystick[ ident ]->os->is_analog = 1;
\r
1565 if( fgJoystick[ ident ]->os->is_analog )
\r
1566 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
1568 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
1569 ident - USB_IDENT_OFFSET );
\r
1570 # elif defined( __linux__ )
\r
1571 fgJoystick[ ident ]->id = ident;
\r
1572 fgJoystick[ ident ]->error = GL_FALSE;
\r
1574 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
1576 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
1577 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
1581 fghJoystickOpen( fgJoystick[ ident ] );
\r
1585 * Try initializing all the joysticks (well, both of them)
\r
1587 void fgInitialiseJoysticks ( void )
\r
1589 if( !fgState.JoysticksInitialised )
\r
1592 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1593 fghJoystickInit( ident );
\r
1595 fgState.JoysticksInitialised = GL_TRUE;
\r
1600 void fgJoystickClose( void )
\r
1603 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1605 if( fgJoystick[ ident ] )
\r
1607 fgPlatformJoystickClose ( ident );
\r
1609 free( fgJoystick[ ident ] );
\r
1610 fgJoystick[ ident ] = NULL;
\r
1611 /* show joystick has been deinitialized */
\r
1617 * Polls the joystick and executes the joystick callback hooked to the
\r
1618 * window specified in the function's parameter:
\r
1620 void fgJoystickPollWindow( SFG_Window* window )
\r
1622 float axes[ _JS_MAX_AXES ];
\r
1626 freeglut_return_if_fail( window );
\r
1627 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1629 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1631 if( fgJoystick[ident] )
\r
1633 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1635 if( !fgJoystick[ident]->error )
\r
1636 INVOKE_WCB( *window, Joystick,
\r
1638 (int) ( axes[ 0 ] * 1000.0f ),
\r
1639 (int) ( axes[ 1 ] * 1000.0f ),
\r
1640 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1647 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1649 int fgJoystickDetect( void )
\r
1653 fgInitialiseJoysticks ();
\r
1655 if ( !fgState.JoysticksInitialised )
\r
1658 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1659 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1666 * Joystick information functions
\r
1668 int glutJoystickGetNumAxes( int ident )
\r
1670 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1671 return fgJoystick[ ident ]->num_axes;
\r
1673 int glutJoystickGetNumButtons( int ident )
\r
1675 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1676 return fgJoystick[ ident ]->num_buttons;
\r
1678 int glutJoystickNotWorking( int ident )
\r
1680 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1681 return fgJoystick[ ident ]->error;
\r
1684 float glutJoystickGetDeadBand( int ident, int axis )
\r
1686 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1687 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1689 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1691 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1692 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1695 float glutJoystickGetSaturation( int ident, int axis )
\r
1697 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1698 return fgJoystick[ ident ]->saturate[ axis ];
\r
1700 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1702 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1703 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1706 void glutJoystickSetMinRange( int ident, float *axes )
\r
1708 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1709 memcpy( fgJoystick[ ident ]->min, axes,
\r
1710 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1712 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1714 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1715 memcpy( fgJoystick[ ident ]->max, axes,
\r
1716 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1718 void glutJoystickSetCenter( int ident, float *axes )
\r
1720 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1721 memcpy( fgJoystick[ ident ]->center, axes,
\r
1722 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1725 void glutJoystickGetMinRange( int ident, float *axes )
\r
1727 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1728 memcpy( axes, fgJoystick[ ident ]->min,
\r
1729 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1731 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1733 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1734 memcpy( axes, fgJoystick[ ident ]->max,
\r
1735 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1737 void glutJoystickGetCenter( int ident, float *axes )
\r
1739 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1740 memcpy( axes, fgJoystick[ ident ]->center,
\r
1741 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1744 /*** END OF FILE ***/
\r