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 /* XXX It might be better to poll the operating system for the numbers of buttons and
\r
46 * XXX axes and then dynamically allocate the arrays.
\r
48 #define _JS_MAX_BUTTONS 32
\r
50 #if TARGET_HOST_MACINTOSH
\r
51 # define _JS_MAX_AXES 9
\r
52 # include <InputSprocket.h>
\r
55 #if TARGET_HOST_MAC_OSX
\r
56 # define _JS_MAX_AXES 16
\r
57 # include <mach/mach.h>
\r
58 # include <IOKit/IOkitLib.h>
\r
59 # include <IOKit/hid/IOHIDLib.h>
\r
62 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
63 # define _JS_MAX_AXES 8
\r
64 # include <windows.h>
\r
65 # include <mmsystem.h>
\r
66 # include <regstr.h>
\r
70 #if TARGET_HOST_POSIX_X11
\r
71 # define _JS_MAX_AXES 16
\r
72 # ifdef HAVE_SYS_IOCTL_H
\r
73 # include <sys/ioctl.h>
\r
75 # ifdef HAVE_FCNTL_H
\r
78 # ifdef HAVE_ERRNO_H
\r
80 # include <string.h>
\r
82 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
83 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
84 # define HAVE_USB_JS 1
\r
86 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
87 # include <sys/joystick.h>
\r
90 * XXX NetBSD/amd64 systems may find that they have to steal the
\r
91 * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
\r
92 * XXX I cannot comment whether that works for the interface, but
\r
93 * XXX it lets you compile...(^& I do not think that we can do away
\r
94 * XXX with this header.
\r
96 # include <machine/joystick.h> /* For analog joysticks */
\r
98 # define JS_DATA_TYPE joystick
\r
99 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
102 # if defined(__linux__)
\r
103 # include <linux/joystick.h>
\r
105 /* check the joystick driver version */
\r
106 # if defined(JS_VERSION) && JS_VERSION >= 0x010000
\r
109 # else /* Not BSD or Linux */
\r
113 * We'll put these values in and that should
\r
114 * allow the code to at least compile when there is
\r
115 * no support. The JS open routine should error out
\r
116 * and shut off all the code downstream anyway and if
\r
117 * the application doesn't use a joystick we'll be fine.
\r
120 struct JS_DATA_TYPE
\r
127 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
135 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
\r
137 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
139 # ifdef HAVE_USB_JS
\r
140 # if defined(__NetBSD__)
\r
141 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
142 # define HAVE_USBHID_H 1
\r
143 # ifdef HAVE_USBHID_H
\r
144 # include <usbhid.h>
\r
148 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
149 # ifdef HAVE_USBHID_H
\r
150 # include <usbhid.h>
\r
152 # include <libusbhid.h>
\r
155 # include <legacy/dev/usb/usb.h>
\r
156 # include <dev/usb/usbhid.h>
\r
158 /* Compatibility with older usb.h revisions */
\r
159 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
\r
160 # define USB_MAX_DEVNAMES MAXDEVNAMES
\r
164 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
\r
165 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
\r
166 struct os_specific_s {
\r
170 /* The following structure members are specific to analog joysticks */
\r
171 struct joystick ajs;
\r
172 # ifdef HAVE_USB_JS
\r
173 /* The following structure members are specific to USB joysticks */
\r
174 struct hid_item *hids;
\r
177 char *hid_data_buf;
\r
178 int axes_usage [ _JS_MAX_AXES ];
\r
180 /* We keep button and axes state ourselves, as they might not be updated
\r
181 * on every read of a USB device
\r
184 float cache_axes [ _JS_MAX_AXES ];
\r
187 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
\r
188 # define USB_IDENT_OFFSET 2
\r
190 # define USBDEV "/dev/usb"
\r
191 # define UHIDDEV "/dev/uhid"
\r
192 # define AJSDEV "/dev/joy"
\r
194 # ifdef HAVE_USB_JS
\r
196 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
\r
197 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
\r
198 * return the uhidN device name. We warn the user of this situation once.
\r
200 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
\r
202 struct usb_device_info di;
\r
206 for (a = 1; a < USB_MAX_DEVICES; a++) {
\r
208 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
\r
210 for (i = 0; i < USB_MAX_DEVNAMES; i++)
\r
211 if (di.udi_devnames[i][0] &&
\r
212 strcmp(di.udi_devnames[i], dev) == 0) {
\r
213 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
\r
214 strcpy(cp, di.udi_vendor);
\r
216 strcat(cp, di.udi_product);
\r
217 strncpy(out, cp, outlen - 1);
\r
218 out[outlen - 1] = 0;
\r
226 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
\r
231 static int protection_warned = 0;
\r
233 for (i = 0; i < 16; i++) {
\r
234 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
\r
235 f = open(buf, O_RDONLY);
\r
237 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
\r
242 #ifdef HAVE_ERRNO_H
\r
243 else if (errno == EACCES) {
\r
244 if (!protection_warned) {
\r
245 fgWarning ( "Can't open %s for read!", buf );
\r
246 protection_warned = 1;
\r
254 static int fghJoystickInitializeHID(struct os_specific_s *os,
\r
255 int *num_axes, int *num_buttons)
\r
257 int size, is_joystick;
\r
258 # ifdef HAVE_USBHID_H
\r
261 struct hid_data *d;
\r
265 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
\r
267 #ifdef HAVE_ERRNO_H
\r
268 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
\r
270 fgWarning ( "error: %s", os->fname );
\r
277 # ifdef HAVE_USBHID_H
\r
278 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
\r
280 /*** XXX {report_id} may not be the right variable? ***/
\r
281 #ifdef HAVE_ERRNO_H
\r
282 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
\r
284 fgWarning ( "error: %s%d", UHIDDEV, report_id );
\r
289 size = hid_report_size( rd, hid_input, report_id );
\r
291 size = hid_report_size( rd, 0, hid_input );
\r
293 os->hid_data_buf = calloc( 1, size );
\r
294 os->hid_dlen = size;
\r
297 # ifdef HAVE_USBHID_H
\r
298 d = hid_start_parse( rd, 1 << hid_input, report_id );
\r
300 d = hid_start_parse( rd, 1 << hid_input );
\r
302 while( hid_get_item( d, &h ) )
\r
304 int usage, page, interesting_hid;
\r
306 page = HID_PAGE( h.usage );
\r
307 usage = HID_USAGE( h.usage );
\r
309 /* This test is somewhat too simplistic, but this is how MicroSoft
\r
310 * does, so I guess it works for all joysticks/game pads. */
\r
311 is_joystick = is_joystick ||
\r
312 ( h.kind == hid_collection &&
\r
313 page == HUP_GENERIC_DESKTOP &&
\r
314 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
\r
316 if( h.kind != hid_input )
\r
322 interesting_hid = TRUE;
\r
323 if( page == HUP_GENERIC_DESKTOP )
\r
334 if( *num_axes < _JS_MAX_AXES )
\r
336 os->axes_usage[ *num_axes ] = usage;
\r
340 case HUG_HAT_SWITCH:
\r
341 /* Allocate two axes for a hat */
\r
342 if( *num_axes + 1 < _JS_MAX_AXES )
\r
344 os->axes_usage[ *num_axes ] = usage;
\r
346 os->axes_usage[ *num_axes ] = usage;
\r
351 interesting_hid = FALSE;
\r
355 else if( page == HUP_BUTTON )
\r
357 interesting_hid = ( usage > 0 ) &&
\r
358 ( usage <= _JS_MAX_BUTTONS );
\r
360 if( interesting_hid && usage - 1 > *num_buttons )
\r
361 *num_buttons = usage - 1;
\r
364 if( interesting_hid )
\r
367 os->hids = calloc( 1, sizeof ( struct hid_item ) );
\r
371 hid_end_parse( d );
\r
373 return os->hids != NULL;
\r
379 * Definition of "SFG_Joystick" structure -- based on JS's "jsJoystick" object class.
\r
380 * See "js.h" lines 80-178.
\r
382 typedef struct tagSFG_Joystick SFG_Joystick;
\r
383 struct tagSFG_Joystick
\r
385 #if TARGET_HOST_MACINTOSH
\r
386 #define ISP_NUM_AXIS 9
\r
387 #define ISP_NUM_NEEDS 41
\r
388 ISpElementReference isp_elem [ ISP_NUM_NEEDS ];
\r
389 ISpNeed isp_needs [ ISP_NUM_NEEDS ];
\r
392 #if TARGET_HOST_MAC_OSX
\r
393 IOHIDDeviceInterface ** hidDev;
\r
394 IOHIDElementCookie buttonCookies[41];
\r
395 IOHIDElementCookie axisCookies[_JS_MAX_AXES];
\r
396 long minReport[_JS_MAX_AXES],
\r
397 maxReport[_JS_MAX_AXES];
\r
400 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
407 #if TARGET_HOST_POSIX_X11
\r
408 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
409 struct os_specific_s *os;
\r
413 struct js_event js;
\r
415 float tmp_axes [ _JS_MAX_AXES ];
\r
417 struct JS_DATA_TYPE js;
\r
420 char fname [ 128 ];
\r
430 float dead_band[ _JS_MAX_AXES ];
\r
431 float saturate [ _JS_MAX_AXES ];
\r
432 float center [ _JS_MAX_AXES ];
\r
433 float max [ _JS_MAX_AXES ];
\r
434 float min [ _JS_MAX_AXES ];
\r
438 * Functions associated with the "jsJoystick" class in PLIB
\r
440 #if TARGET_HOST_MAC_OSX
\r
441 #define K_NUM_DEVICES 32
\r
443 io_object_t ioDevices[K_NUM_DEVICES];
\r
445 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
\r
446 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
\r
448 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
\r
449 /* callback for CFArrayApply */
\r
450 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
\r
452 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
\r
453 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
\r
454 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
\r
458 /* External function declarations (mostly platform-specific) */
\r
459 extern void fgPlatformJoystickClose ( int ident );
\r
462 * The static joystick structure pointer
\r
464 #define MAX_NUM_JOYSTICKS 2
\r
465 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
469 * Read the raw joystick data
\r
471 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
473 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
479 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
490 for( i = 0; i < joy->num_axes; i++ )
\r
491 axes[ i ] = 1500.0f;
\r
496 #if TARGET_HOST_MACINTOSH
\r
501 for ( i = 0; i < joy->num_buttons; i++ )
\r
504 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
507 *buttons |= state << i;
\r
513 for ( i = 0; i < joy->num_axes; i++ )
\r
516 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
519 axes [i] = (float) state;
\r
524 #if TARGET_HOST_MAC_OSX
\r
525 if ( buttons != NULL )
\r
529 for ( i = 0; i < joy->num_buttons; i++ )
\r
531 IOHIDEventStruct hidEvent;
\r
532 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
533 if ( hidEvent.value )
\r
534 *buttons |= 1 << i;
\r
538 if ( axes != NULL )
\r
540 for ( i = 0; i < joy->num_axes; i++ )
\r
542 IOHIDEventStruct hidEvent;
\r
543 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
544 axes[i] = hidEvent.value;
\r
549 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
550 status = joyGetPosEx( joy->js_id, &joy->js );
\r
552 if ( status != JOYERR_NOERROR )
\r
554 joy->error = GL_TRUE;
\r
559 *buttons = joy->js.dwButtons;
\r
564 * WARNING - Fall through case clauses!!
\r
566 switch ( joy->num_axes )
\r
569 /* Generate two POV axes from the POV hat angle.
\r
570 * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
\r
571 * hundredths of a degree, or 0xFFFF when idle.
\r
573 if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
\r
580 /* This is the contentious bit: how to convert angle to X/Y.
\r
581 * wk: I know of no define for PI that we could use here:
\r
582 * SG_PI would pull in sg, M_PI is undefined for MSVC
\r
583 * But the accuracy of the value of PI is very unimportant at
\r
586 float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
587 float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
589 /* Convert to coordinates on a square so that North-East
\r
590 * is (1,1) not (.7,.7), etc.
\r
591 * s and c cannot both be zero so we won't divide by zero.
\r
593 if ( fabs ( s ) < fabs ( c ) )
\r
595 axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;
\r
596 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
\r
600 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
\r
601 axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;
\r
605 case 6: axes[5] = (float) joy->js.dwVpos;
\r
606 case 5: axes[4] = (float) joy->js.dwUpos;
\r
607 case 4: axes[3] = (float) joy->js.dwRpos;
\r
608 case 3: axes[2] = (float) joy->js.dwZpos;
\r
609 case 2: axes[1] = (float) joy->js.dwYpos;
\r
610 case 1: axes[0] = (float) joy->js.dwXpos;
\r
615 #if TARGET_HOST_POSIX_X11
\r
616 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
617 if ( joy->os->is_analog )
\r
619 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
620 if ( status != sizeof(joy->os->ajs) ) {
\r
621 perror ( joy->os->fname );
\r
622 joy->error = GL_TRUE;
\r
625 if ( buttons != NULL )
\r
626 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
628 if ( axes != NULL )
\r
630 axes[0] = (float) joy->os->ajs.x;
\r
631 axes[1] = (float) joy->os->ajs.y;
\r
637 # ifdef HAVE_USB_JS
\r
638 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
640 struct hid_item *h;
\r
642 for ( h = joy->os->hids; h; h = h->next )
\r
644 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
646 int page = HID_PAGE ( h->usage );
\r
647 int usage = HID_USAGE ( h->usage );
\r
649 if ( page == HUP_GENERIC_DESKTOP )
\r
652 for ( i = 0; i < joy->num_axes; i++ )
\r
653 if (joy->os->axes_usage[i] == usage)
\r
655 if (usage == HUG_HAT_SWITCH)
\r
657 if (d < 0 || d > 8)
\r
658 d = 0; /* safety */
\r
659 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
660 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
664 joy->os->cache_axes[i] = (float)d;
\r
669 else if (page == HUP_BUTTON)
\r
671 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
674 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
676 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
681 #ifdef HAVE_ERRNO_H
\r
682 if ( len < 0 && errno != EAGAIN )
\r
687 perror( joy->os->fname );
\r
690 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
691 if ( axes != NULL )
\r
692 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
700 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
702 if ( status != sizeof( struct js_event ) )
\r
704 #ifdef HAVE_ERRNO_H
\r
705 if ( errno == EAGAIN )
\r
707 /* Use the old values */
\r
709 *buttons = joy->tmp_buttons;
\r
711 memcpy( axes, joy->tmp_axes,
\r
712 sizeof( float ) * joy->num_axes );
\r
717 fgWarning ( "%s", joy->fname );
\r
718 joy->error = GL_TRUE;
\r
722 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
724 case JS_EVENT_BUTTON:
\r
725 if( joy->js.value == 0 ) /* clear the flag */
\r
726 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
728 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
731 case JS_EVENT_AXIS:
\r
732 if ( joy->js.number < joy->num_axes )
\r
734 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
737 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
742 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
744 /* use the old values */
\r
746 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
747 if ( axes != NULL )
\r
748 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
754 *buttons = joy->tmp_buttons;
\r
758 status = read( joy->fd, &joy->js, JS_RETURN );
\r
760 if ( status != JS_RETURN )
\r
762 fgWarning( "%s", joy->fname );
\r
763 joy->error = GL_TRUE;
\r
768 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
769 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
771 *buttons = joy->js.buttons;
\r
776 axes[ 0 ] = (float) joy->js.x;
\r
777 axes[ 1 ] = (float) joy->js.y;
\r
784 * Correct the joystick axis data
\r
786 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
788 if( value < joy->center[ axis ] )
\r
790 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
791 joy->min[ axis ] );
\r
793 if( xx < -joy->saturate[ axis ] )
\r
796 if( xx > -joy->dead_band [ axis ] )
\r
799 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
800 joy->dead_band[ axis ] );
\r
802 return ( xx < -1.0f ) ? -1.0f : xx;
\r
806 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
807 joy->center[ axis ] );
\r
809 if( xx > joy->saturate[ axis ] )
\r
812 if( xx < joy->dead_band[ axis ] )
\r
815 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
816 joy->dead_band[ axis ] );
\r
818 return ( xx > 1.0f ) ? 1.0f : xx;
\r
823 * Read the corrected joystick data
\r
825 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
827 float raw_axes[ _JS_MAX_AXES ];
\r
836 for ( i=0; i<joy->num_axes; i++ )
\r
840 fghJoystickRawRead( joy, buttons, raw_axes );
\r
843 for( i=0; i<joy->num_axes; i++ )
\r
844 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
848 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
852 #if TARGET_HOST_MAC_OSX
\r
853 /** open the IOKit connection, enumerate all the HID devices, add their
\r
854 interface references to the static array. We then use the array index
\r
855 as the device number when we come to open() the joystick. */
\r
856 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
858 CFMutableDictionaryRef hidMatch = NULL;
\r
859 IOReturn rv = kIOReturnSuccess;
\r
861 io_iterator_t hidIterator;
\r
864 /* build a dictionary matching HID devices */
\r
865 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
867 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
868 if (rv != kIOReturnSuccess || !hidIterator) {
\r
869 fgWarning( "no joystick (HID) devices found" );
\r
874 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
875 /* filter out keyboard and mouse devices */
\r
876 CFDictionaryRef properties = getCFProperties(ioDev);
\r
879 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
880 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
881 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
882 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
884 /* keep only joystick devices */
\r
885 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
886 (usage == kHIDUsage_GD_Joystick)
\r
887 || (usage == kHIDUsage_GD_GamePad)
\r
888 || (usage == kHIDUsage_GD_MultiAxisController)
\r
889 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
890 /* add it to the array */
\r
891 ioDevices[numDevices++] = ioDev;
\r
894 IOObjectRelease(hidIterator);
\r
897 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
900 CFMutableDictionaryRef cfProperties;
\r
903 /* comment copied from darwin/SDL_sysjoystick.c */
\r
904 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
905 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
908 io_registry_entry_t parent1, parent2;
\r
910 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
911 if (rv != kIOReturnSuccess) {
\r
912 fgWarning ( "error getting device entry parent");
\r
916 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
917 if (rv != kIOReturnSuccess) {
\r
918 fgWarning ( "error getting device entry parent 2");
\r
923 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
924 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
925 if (rv != kIOReturnSuccess || !cfProperties) {
\r
926 fgWarning ( "error getting device properties");
\r
930 return cfProperties;
\r
933 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
935 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
936 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
940 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
943 /** element enumerator function : pass NULL for top-level*/
\r
944 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
946 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
947 "Joystick element type mismatch",
\r
948 "fghJoystickEnumerateElements" );
\r
950 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
951 CFArrayApplyFunction((CFArrayRef) element, range,
\r
952 &fghJoystickElementEnumerator, joy );
\r
955 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
957 long cookie, lmin, lmax;
\r
958 int index = joy->num_axes++;
\r
960 CFNumberGetValue ((CFNumberRef)
\r
961 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
962 kCFNumberLongType, &cookie);
\r
964 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
966 CFNumberGetValue ((CFNumberRef)
\r
967 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
968 kCFNumberLongType, &lmin);
\r
970 CFNumberGetValue ((CFNumberRef)
\r
971 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
972 kCFNumberLongType, &lmax);
\r
974 joy->min[index] = lmin;
\r
975 joy->max[index] = lmax;
\r
976 joy->dead_band[index] = 0.0;
\r
977 joy->saturate[index] = 1.0;
\r
978 joy->center[index] = (lmax + lmin) * 0.5;
\r
981 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
984 CFNumberGetValue ((CFNumberRef)
\r
985 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
986 kCFNumberLongType, &cookie);
\r
988 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
989 /* anything else for buttons? */
\r
992 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
994 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
995 /* do we map hats to axes or buttons? */
\r
999 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1001 http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
\r
1003 # if FREEGLUT_LIB_PRAGMAS
\r
1004 # pragma comment (lib, "advapi32.lib")
\r
1007 static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )
\r
1009 char buffer [ 256 ];
\r
1011 char OEMKey [ 256 ];
\r
1020 /* Open .. MediaResources\CurrentJoystickSettings */
\r
1021 _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",
\r
1022 REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,
\r
1023 REGSTR_KEY_JOYCURR );
\r
1025 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
\r
1027 if ( lr != ERROR_SUCCESS ) return 0;
\r
1029 /* Get OEM Key name */
\r
1030 dwcb = sizeof(OEMKey);
\r
1032 /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */
\r
1033 _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );
\r
1035 lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);
\r
1036 RegCloseKey ( hKey );
\r
1038 if ( lr != ERROR_SUCCESS ) return 0;
\r
1040 /* Open OEM Key from ...MediaProperties */
\r
1041 _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );
\r
1043 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );
\r
1045 if ( lr != ERROR_SUCCESS ) return 0;
\r
1047 /* Get OEM Name */
\r
1050 lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,
\r
1052 RegCloseKey ( hKey );
\r
1054 if ( lr != ERROR_SUCCESS ) return 0;
\r
1061 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1064 #if TARGET_HOST_MACINTOSH
\r
1067 #if TARGET_HOST_MAC_OSX
\r
1070 IOCFPlugInInterface **plugin;
\r
1072 HRESULT pluginResult;
\r
1074 CFDictionaryRef props;
\r
1075 CFTypeRef topLevelElement;
\r
1077 #if TARGET_HOST_POSIX_X11
\r
1078 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1084 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1090 /* Silence gcc, the correct #ifdefs would be too fragile... */
\r
1094 * Default values (for no joystick -- each conditional will reset the
\r
1097 joy->error = TRUE;
\r
1098 joy->num_axes = joy->num_buttons = 0;
\r
1099 joy->name[ 0 ] = '\0';
\r
1101 #if TARGET_HOST_MACINTOSH
\r
1102 /* XXX FIXME: get joystick name in Mac */
\r
1104 err = ISpStartup( );
\r
1106 if( err == noErr )
\r
1108 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
1110 joy->error = GL_TRUE;
\r
1112 /* initialize the needs structure */
\r
1113 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
1115 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1116 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1117 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1118 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1119 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1120 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1121 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1122 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1123 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1125 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1126 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1127 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1128 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1129 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1130 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1131 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1132 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1133 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1134 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1135 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1136 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1137 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1138 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1139 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1140 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1141 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1142 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1143 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1144 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1145 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1146 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1147 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1148 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1149 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1150 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1151 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1152 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1153 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1154 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1155 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1156 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1159 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
1162 /* next two calls allow keyboard and mouse to emulate other input
\r
1163 * devices (gamepads, joysticks, etc)
\r
1166 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
1167 ISP_CHECK_ERR(err)
\r
1170 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
1171 ISP_CHECK_ERR(err)
\r
1174 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
1175 joy->isp_needs, joy->isp_elem,
\r
1177 ISP_CHECK_ERR( err )
\r
1179 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
1180 'freeglut', nil, 0, 128, 0 );
\r
1181 ISP_CHECK_ERR( err )
\r
1183 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
1184 joy->num_axes = joy->isp_num_axis;
\r
1186 for( i = 0; i < joy->num_axes; i++ )
\r
1188 joy->dead_band[ i ] = 0;
\r
1189 joy->saturate [ i ] = 1;
\r
1190 joy->center [ i ] = kISpAxisMiddle;
\r
1191 joy->max [ i ] = kISpAxisMaximum;
\r
1192 joy->min [ i ] = kISpAxisMinimum;
\r
1195 joy->error = GL_FALSE;
\r
1198 joy->num_buttons = joy->num_axes = 0;
\r
1201 #if TARGET_HOST_MAC_OSX
\r
1202 if( joy->id >= numDevices )
\r
1204 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
1208 /* create device interface */
\r
1209 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
1210 kIOHIDDeviceUserClientTypeID,
\r
1211 kIOCFPlugInInterfaceID,
\r
1212 &plugin, &score );
\r
1214 if( rv != kIOReturnSuccess )
\r
1216 fgWarning( "error creating plugin for io device" );
\r
1220 pluginResult = ( *plugin )->QueryInterface(
\r
1222 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
1223 &( LPVOID )joy->hidDev
\r
1226 if( pluginResult != S_OK )
\r
1227 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
1229 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
1230 if( joy->hidDev == NULL )
\r
1233 /* store the interface in this instance */
\r
1234 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
1235 if( rv != kIOReturnSuccess )
\r
1237 fgWarning( "error opening device interface");
\r
1241 props = getCFProperties( ioDevices[ joy->id ] );
\r
1243 /* recursively enumerate all the bits */
\r
1244 CFTypeRef topLevelElement =
\r
1245 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
1246 enumerateElements( topLevelElement );
\r
1248 CFRelease( props );
\r
1251 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1252 joy->js.dwFlags = JOY_RETURNALL;
\r
1253 joy->js.dwSize = sizeof( joy->js );
\r
1255 memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
\r
1258 ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
\r
1261 if( joy->jsCaps.wNumAxes == 0 )
\r
1263 joy->num_axes = 0;
\r
1264 joy->error = GL_TRUE;
\r
1268 /* Device name from jsCaps is often "Microsoft PC-joystick driver",
\r
1269 * at least for USB. Try to get the real name from the registry.
\r
1271 if ( ! fghJoystickGetOEMProductName( joy, joy->name,
\r
1272 sizeof( joy->name ) ) )
\r
1274 fgWarning( "JS: Failed to read joystick name from registry" );
\r
1275 strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );
\r
1278 /* Windows joystick drivers may provide any combination of
\r
1279 * X,Y,Z,R,U,V,POV - not necessarily the first n of these.
\r
1281 if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )
\r
1283 joy->num_axes = _JS_MAX_AXES;
\r
1284 joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */
\r
1285 joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */
\r
1288 joy->num_axes = 6;
\r
1290 joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;
\r
1291 joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;
\r
1292 joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;
\r
1293 joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;
\r
1294 joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;
\r
1295 joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;
\r
1296 joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;
\r
1297 joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;
\r
1298 joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;
\r
1299 joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;
\r
1300 joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;
\r
1301 joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;
\r
1304 /* Guess all the rest judging on the axes extremals */
\r
1305 for( i = 0; i < joy->num_axes; i++ )
\r
1307 joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
\r
1308 joy->dead_band[ i ] = 0.0f;
\r
1309 joy->saturate [ i ] = 1.0f;
\r
1313 #if TARGET_HOST_POSIX_X11
\r
1314 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1315 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1316 joy->os->cache_axes[ i ] = 0.0f;
\r
1318 joy->os->cache_buttons = 0;
\r
1320 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1322 #ifdef HAVE_ERRNO_H
\r
1323 if( joy->os->fd < 0 && errno == EACCES )
\r
1324 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1327 joy->error =( joy->os->fd < 0 );
\r
1332 joy->num_axes = 0;
\r
1333 joy->num_buttons = 0;
\r
1334 if( joy->os->is_analog )
\r
1337 char joyfname[ 1024 ];
\r
1338 int noargs, in_no_axes;
\r
1340 float axes [ _JS_MAX_AXES ];
\r
1341 int buttons[ _JS_MAX_AXES ];
\r
1343 joy->num_axes = 2;
\r
1344 joy->num_buttons = 32;
\r
1346 fghJoystickRawRead( joy, buttons, axes );
\r
1347 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1351 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1353 joyfile = fopen( joyfname, "r" );
\r
1354 joy->error =( joyfile == NULL );
\r
1358 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1359 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1360 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1361 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1362 fclose( joyfile );
\r
1366 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1368 joy->dead_band[ i ] = 0.0f;
\r
1369 joy->saturate [ i ] = 1.0f;
\r
1372 return; /* End of analog code */
\r
1375 # ifdef HAVE_USB_JS
\r
1376 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1377 &joy->num_buttons ) )
\r
1379 close( joy->os->fd );
\r
1380 joy->error = GL_TRUE;
\r
1384 cp = strrchr( joy->os->fname, '/' );
\r
1387 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1389 strcpy( joy->name, &cp[1] );
\r
1392 if( joy->num_axes > _JS_MAX_AXES )
\r
1393 joy->num_axes = _JS_MAX_AXES;
\r
1395 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1397 /* We really should get this from the HID, but that data seems
\r
1398 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1401 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1403 joy->max [ i ] = 1.0f;
\r
1404 joy->center[ i ] = 0.0f;
\r
1405 joy->min [ i ] = -1.0f;
\r
1409 joy->max [ i ] = 255.0f;
\r
1410 joy->center[ i ] = 127.0f;
\r
1411 joy->min [ i ] = 0.0f;
\r
1414 joy->dead_band[ i ] = 0.0f;
\r
1415 joy->saturate[ i ] = 1.0f;
\r
1420 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1421 /* Default for older Linux systems. */
\r
1422 joy->num_axes = 2;
\r
1423 joy->num_buttons = 32;
\r
1426 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1427 joy->tmp_axes[ i ] = 0.0f;
\r
1429 joy->tmp_buttons = 0;
\r
1432 joy->fd = open( joy->fname, O_RDONLY );
\r
1434 joy->error =( joy->fd < 0 );
\r
1439 /* Set the correct number of axes for the linux driver */
\r
1441 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1442 * to the upper byte of an uninitialized word doesn't work.
\r
1445 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1446 joy->num_axes = u;
\r
1447 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1448 joy->num_buttons = u;
\r
1449 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1450 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1454 * The Linux driver seems to return 512 for all axes
\r
1455 * when no stick is present - but there is a chance
\r
1456 * that could happen by accident - so it's gotta happen
\r
1457 * on both axes for at least 100 attempts.
\r
1459 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1466 fghJoystickRawRead( joy, NULL, joy->center );
\r
1468 } while( !joy->error &&
\r
1470 joy->center[ 0 ] == 512.0f &&
\r
1471 joy->center[ 1 ] == 512.0f );
\r
1473 if ( counter >= 100 )
\r
1474 joy->error = GL_TRUE;
\r
1477 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1480 joy->max [ i ] = 32767.0f;
\r
1481 joy->center[ i ] = 0.0f;
\r
1482 joy->min [ i ] = -32767.0f;
\r
1484 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1485 joy->min[ i ] = 0.0f;
\r
1487 joy->dead_band[ i ] = 0.0f;
\r
1488 joy->saturate [ i ] = 1.0f;
\r
1495 * This function replaces the constructor method in the JS library.
\r
1497 static void fghJoystickInit( int ident )
\r
1499 if( ident >= MAX_NUM_JOYSTICKS )
\r
1500 fgError( "Too large a joystick number: %d", ident );
\r
1502 if( fgJoystick[ ident ] )
\r
1503 fgError( "illegal attempt to initialize joystick device again" );
\r
1505 fgJoystick[ ident ] =
\r
1506 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1508 /* Set defaults */
\r
1509 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1510 fgJoystick[ ident ]->error = GL_TRUE;
\r
1512 #if TARGET_HOST_MACINTOSH
\r
1513 fgJoystick[ ident ]->id = ident;
\r
1514 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
1515 fgJoystick[ ident ]->error = GL_FALSE;
\r
1518 #if TARGET_HOST_MAC_OSX
\r
1519 fgJoystick[ ident ]->id = ident;
\r
1520 fgJoystick[ ident ]->error = GL_FALSE;
\r
1521 fgJoystick[ ident ]->num_axes = 0;
\r
1522 fgJoystick[ ident ]->num_buttons = 0;
\r
1524 if( numDevices < 0 )
\r
1526 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
1529 mach_port_t masterPort;
\r
1530 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
1531 if( rv != kIOReturnSuccess )
\r
1533 fgWarning( "error getting master Mach port" );
\r
1536 fghJoystickFindDevices( masterPort );
\r
1539 if ( ident >= numDevices )
\r
1541 fgJoystick[ ident ]->error = GL_TRUE;
\r
1545 /* get the name now too */
\r
1546 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
1547 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
1548 CFSTR( kIOHIDProductKey ) );
\r
1550 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
1553 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
1554 CFStringGetSystemEncoding( ) ) )
\r
1556 fgWarning( "error getting device name" );
\r
1561 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1565 fgJoystick[ ident ]->js_id = JOYSTICKID1;
\r
1566 fgJoystick[ ident ]->error = GL_FALSE;
\r
1569 fgJoystick[ ident ]->js_id = JOYSTICKID2;
\r
1570 fgJoystick[ ident ]->error = GL_FALSE;
\r
1573 fgJoystick[ ident ]->num_axes = 0;
\r
1574 fgJoystick[ ident ]->error = GL_TRUE;
\r
1579 #if TARGET_HOST_POSIX_X11
\r
1580 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1581 fgJoystick[ ident ]->id = ident;
\r
1582 fgJoystick[ ident ]->error = GL_FALSE;
\r
1584 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1585 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
1586 if( ident < USB_IDENT_OFFSET )
\r
1587 fgJoystick[ ident ]->os->is_analog = 1;
\r
1588 if( fgJoystick[ ident ]->os->is_analog )
\r
1589 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
1591 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
1592 ident - USB_IDENT_OFFSET );
\r
1593 # elif defined( __linux__ )
\r
1594 fgJoystick[ ident ]->id = ident;
\r
1595 fgJoystick[ ident ]->error = GL_FALSE;
\r
1597 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
1599 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
1600 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
1604 fghJoystickOpen( fgJoystick[ ident ] );
\r
1608 * Try initializing all the joysticks (well, both of them)
\r
1610 void fgInitialiseJoysticks ( void )
\r
1612 if( !fgState.JoysticksInitialised )
\r
1615 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1616 fghJoystickInit( ident );
\r
1618 fgState.JoysticksInitialised = GL_TRUE;
\r
1626 #if TARGET_HOST_MACINTOSH
\r
1627 void fgPlatformJoystickClose ( int ident )
\r
1635 #if TARGET_HOST_MAC_OSX
\r
1636 void fgPlatformJoystickClose ( int ident )
\r
1638 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
1639 close( fgJoystick[ ident ]->hidDev );
\r
1643 #if TARGET_HOST_POSIX_X11
\r
1644 void fgPlatformJoystickClose ( int ident )
\r
1646 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1647 if( fgJoystick[ident]->os )
\r
1649 if( ! fgJoystick[ ident ]->error )
\r
1650 close( fgJoystick[ ident ]->os->fd );
\r
1651 #ifdef HAVE_USB_JS
\r
1652 if( fgJoystick[ ident ]->os->hids )
\r
1653 free (fgJoystick[ ident ]->os->hids);
\r
1654 if( fgJoystick[ ident ]->os->hid_data_buf )
\r
1655 free( fgJoystick[ ident ]->os->hid_data_buf );
\r
1657 free( fgJoystick[ident]->os );
\r
1661 if( ! fgJoystick[ident]->error )
\r
1662 close( fgJoystick[ ident ]->fd );
\r
1667 void fgJoystickClose( void )
\r
1670 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1672 if( fgJoystick[ ident ] )
\r
1674 fgPlatformJoystickClose ( ident );
\r
1676 free( fgJoystick[ ident ] );
\r
1677 fgJoystick[ ident ] = NULL;
\r
1678 /* show joystick has been deinitialized */
\r
1684 * Polls the joystick and executes the joystick callback hooked to the
\r
1685 * window specified in the function's parameter:
\r
1687 void fgJoystickPollWindow( SFG_Window* window )
\r
1689 float axes[ _JS_MAX_AXES ];
\r
1693 freeglut_return_if_fail( window );
\r
1694 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1696 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1698 if( fgJoystick[ident] )
\r
1700 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1702 if( !fgJoystick[ident]->error )
\r
1703 INVOKE_WCB( *window, Joystick,
\r
1705 (int) ( axes[ 0 ] * 1000.0f ),
\r
1706 (int) ( axes[ 1 ] * 1000.0f ),
\r
1707 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1714 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1716 int fgJoystickDetect( void )
\r
1720 fgInitialiseJoysticks ();
\r
1722 if ( !fgState.JoysticksInitialised )
\r
1725 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1726 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1733 * Joystick information functions
\r
1735 int glutJoystickGetNumAxes( int ident )
\r
1737 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1738 return fgJoystick[ ident ]->num_axes;
\r
1740 int glutJoystickGetNumButtons( int ident )
\r
1742 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1743 return fgJoystick[ ident ]->num_buttons;
\r
1745 int glutJoystickNotWorking( int ident )
\r
1747 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1748 return fgJoystick[ ident ]->error;
\r
1751 float glutJoystickGetDeadBand( int ident, int axis )
\r
1753 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1754 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1756 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1758 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1759 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1762 float glutJoystickGetSaturation( int ident, int axis )
\r
1764 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1765 return fgJoystick[ ident ]->saturate[ axis ];
\r
1767 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1769 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1770 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1773 void glutJoystickSetMinRange( int ident, float *axes )
\r
1775 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1776 memcpy( fgJoystick[ ident ]->min, axes,
\r
1777 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1779 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1781 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1782 memcpy( fgJoystick[ ident ]->max, axes,
\r
1783 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1785 void glutJoystickSetCenter( int ident, float *axes )
\r
1787 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1788 memcpy( fgJoystick[ ident ]->center, axes,
\r
1789 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1792 void glutJoystickGetMinRange( int ident, float *axes )
\r
1794 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1795 memcpy( axes, fgJoystick[ ident ]->min,
\r
1796 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1798 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1800 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1801 memcpy( axes, fgJoystick[ ident ]->max,
\r
1802 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1804 void glutJoystickGetCenter( int ident, float *axes )
\r
1806 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1807 memcpy( axes, fgJoystick[ ident ]->center,
\r
1808 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1811 /*** END OF FILE ***/
\r