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
459 * The static joystick structure pointer
\r
461 #define MAX_NUM_JOYSTICKS 2
\r
462 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
466 * Read the raw joystick data
\r
468 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
470 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
476 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
487 for( i = 0; i < joy->num_axes; i++ )
\r
488 axes[ i ] = 1500.0f;
\r
493 #if TARGET_HOST_MACINTOSH
\r
498 for ( i = 0; i < joy->num_buttons; i++ )
\r
501 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
504 *buttons |= state << i;
\r
510 for ( i = 0; i < joy->num_axes; i++ )
\r
513 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
516 axes [i] = (float) state;
\r
521 #if TARGET_HOST_MAC_OSX
\r
522 if ( buttons != NULL )
\r
526 for ( i = 0; i < joy->num_buttons; i++ )
\r
528 IOHIDEventStruct hidEvent;
\r
529 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
530 if ( hidEvent.value )
\r
531 *buttons |= 1 << i;
\r
535 if ( axes != NULL )
\r
537 for ( i = 0; i < joy->num_axes; i++ )
\r
539 IOHIDEventStruct hidEvent;
\r
540 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
541 axes[i] = hidEvent.value;
\r
546 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
547 status = joyGetPosEx( joy->js_id, &joy->js );
\r
549 if ( status != JOYERR_NOERROR )
\r
551 joy->error = GL_TRUE;
\r
556 *buttons = joy->js.dwButtons;
\r
561 * WARNING - Fall through case clauses!!
\r
563 switch ( joy->num_axes )
\r
566 /* Generate two POV axes from the POV hat angle.
\r
567 * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
\r
568 * hundredths of a degree, or 0xFFFF when idle.
\r
570 if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
\r
577 /* This is the contentious bit: how to convert angle to X/Y.
\r
578 * wk: I know of no define for PI that we could use here:
\r
579 * SG_PI would pull in sg, M_PI is undefined for MSVC
\r
580 * But the accuracy of the value of PI is very unimportant at
\r
583 float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
584 float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
586 /* Convert to coordinates on a square so that North-East
\r
587 * is (1,1) not (.7,.7), etc.
\r
588 * s and c cannot both be zero so we won't divide by zero.
\r
590 if ( fabs ( s ) < fabs ( c ) )
\r
592 axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;
\r
593 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
\r
597 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
\r
598 axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;
\r
602 case 6: axes[5] = (float) joy->js.dwVpos;
\r
603 case 5: axes[4] = (float) joy->js.dwUpos;
\r
604 case 4: axes[3] = (float) joy->js.dwRpos;
\r
605 case 3: axes[2] = (float) joy->js.dwZpos;
\r
606 case 2: axes[1] = (float) joy->js.dwYpos;
\r
607 case 1: axes[0] = (float) joy->js.dwXpos;
\r
612 #if TARGET_HOST_POSIX_X11
\r
613 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
614 if ( joy->os->is_analog )
\r
616 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
617 if ( status != sizeof(joy->os->ajs) ) {
\r
618 perror ( joy->os->fname );
\r
619 joy->error = GL_TRUE;
\r
622 if ( buttons != NULL )
\r
623 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
625 if ( axes != NULL )
\r
627 axes[0] = (float) joy->os->ajs.x;
\r
628 axes[1] = (float) joy->os->ajs.y;
\r
634 # ifdef HAVE_USB_JS
\r
635 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
637 struct hid_item *h;
\r
639 for ( h = joy->os->hids; h; h = h->next )
\r
641 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
643 int page = HID_PAGE ( h->usage );
\r
644 int usage = HID_USAGE ( h->usage );
\r
646 if ( page == HUP_GENERIC_DESKTOP )
\r
649 for ( i = 0; i < joy->num_axes; i++ )
\r
650 if (joy->os->axes_usage[i] == usage)
\r
652 if (usage == HUG_HAT_SWITCH)
\r
654 if (d < 0 || d > 8)
\r
655 d = 0; /* safety */
\r
656 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
657 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
661 joy->os->cache_axes[i] = (float)d;
\r
666 else if (page == HUP_BUTTON)
\r
668 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
671 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
673 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
678 #ifdef HAVE_ERRNO_H
\r
679 if ( len < 0 && errno != EAGAIN )
\r
684 perror( joy->os->fname );
\r
687 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
688 if ( axes != NULL )
\r
689 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
697 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
699 if ( status != sizeof( struct js_event ) )
\r
701 #ifdef HAVE_ERRNO_H
\r
702 if ( errno == EAGAIN )
\r
704 /* Use the old values */
\r
706 *buttons = joy->tmp_buttons;
\r
708 memcpy( axes, joy->tmp_axes,
\r
709 sizeof( float ) * joy->num_axes );
\r
714 fgWarning ( "%s", joy->fname );
\r
715 joy->error = GL_TRUE;
\r
719 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
721 case JS_EVENT_BUTTON:
\r
722 if( joy->js.value == 0 ) /* clear the flag */
\r
723 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
725 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
728 case JS_EVENT_AXIS:
\r
729 if ( joy->js.number < joy->num_axes )
\r
731 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
734 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
739 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
741 /* use the old values */
\r
743 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
744 if ( axes != NULL )
\r
745 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
751 *buttons = joy->tmp_buttons;
\r
755 status = read( joy->fd, &joy->js, JS_RETURN );
\r
757 if ( status != JS_RETURN )
\r
759 fgWarning( "%s", joy->fname );
\r
760 joy->error = GL_TRUE;
\r
765 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
766 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
768 *buttons = joy->js.buttons;
\r
773 axes[ 0 ] = (float) joy->js.x;
\r
774 axes[ 1 ] = (float) joy->js.y;
\r
781 * Correct the joystick axis data
\r
783 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
785 if( value < joy->center[ axis ] )
\r
787 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
788 joy->min[ axis ] );
\r
790 if( xx < -joy->saturate[ axis ] )
\r
793 if( xx > -joy->dead_band [ axis ] )
\r
796 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
797 joy->dead_band[ axis ] );
\r
799 return ( xx < -1.0f ) ? -1.0f : xx;
\r
803 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
804 joy->center[ axis ] );
\r
806 if( xx > joy->saturate[ axis ] )
\r
809 if( xx < joy->dead_band[ axis ] )
\r
812 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
813 joy->dead_band[ axis ] );
\r
815 return ( xx > 1.0f ) ? 1.0f : xx;
\r
820 * Read the corrected joystick data
\r
822 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
824 float raw_axes[ _JS_MAX_AXES ];
\r
833 for ( i=0; i<joy->num_axes; i++ )
\r
837 fghJoystickRawRead( joy, buttons, raw_axes );
\r
840 for( i=0; i<joy->num_axes; i++ )
\r
841 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
845 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
849 #if TARGET_HOST_MAC_OSX
\r
850 /** open the IOKit connection, enumerate all the HID devices, add their
\r
851 interface references to the static array. We then use the array index
\r
852 as the device number when we come to open() the joystick. */
\r
853 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
855 CFMutableDictionaryRef hidMatch = NULL;
\r
856 IOReturn rv = kIOReturnSuccess;
\r
858 io_iterator_t hidIterator;
\r
861 /* build a dictionary matching HID devices */
\r
862 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
864 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
865 if (rv != kIOReturnSuccess || !hidIterator) {
\r
866 fgWarning( "no joystick (HID) devices found" );
\r
871 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
872 /* filter out keyboard and mouse devices */
\r
873 CFDictionaryRef properties = getCFProperties(ioDev);
\r
876 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
877 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
878 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
879 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
881 /* keep only joystick devices */
\r
882 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
883 (usage == kHIDUsage_GD_Joystick)
\r
884 || (usage == kHIDUsage_GD_GamePad)
\r
885 || (usage == kHIDUsage_GD_MultiAxisController)
\r
886 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
887 /* add it to the array */
\r
888 ioDevices[numDevices++] = ioDev;
\r
891 IOObjectRelease(hidIterator);
\r
894 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
897 CFMutableDictionaryRef cfProperties;
\r
900 /* comment copied from darwin/SDL_sysjoystick.c */
\r
901 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
902 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
905 io_registry_entry_t parent1, parent2;
\r
907 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
908 if (rv != kIOReturnSuccess) {
\r
909 fgWarning ( "error getting device entry parent");
\r
913 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
914 if (rv != kIOReturnSuccess) {
\r
915 fgWarning ( "error getting device entry parent 2");
\r
920 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
921 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
922 if (rv != kIOReturnSuccess || !cfProperties) {
\r
923 fgWarning ( "error getting device properties");
\r
927 return cfProperties;
\r
930 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
932 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
933 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
937 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
940 /** element enumerator function : pass NULL for top-level*/
\r
941 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
943 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
944 "Joystick element type mismatch",
\r
945 "fghJoystickEnumerateElements" );
\r
947 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
948 CFArrayApplyFunction((CFArrayRef) element, range,
\r
949 &fghJoystickElementEnumerator, joy );
\r
952 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
954 long cookie, lmin, lmax;
\r
955 int index = joy->num_axes++;
\r
957 CFNumberGetValue ((CFNumberRef)
\r
958 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
959 kCFNumberLongType, &cookie);
\r
961 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
963 CFNumberGetValue ((CFNumberRef)
\r
964 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
965 kCFNumberLongType, &lmin);
\r
967 CFNumberGetValue ((CFNumberRef)
\r
968 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
969 kCFNumberLongType, &lmax);
\r
971 joy->min[index] = lmin;
\r
972 joy->max[index] = lmax;
\r
973 joy->dead_band[index] = 0.0;
\r
974 joy->saturate[index] = 1.0;
\r
975 joy->center[index] = (lmax + lmin) * 0.5;
\r
978 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
981 CFNumberGetValue ((CFNumberRef)
\r
982 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
983 kCFNumberLongType, &cookie);
\r
985 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
986 /* anything else for buttons? */
\r
989 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
991 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
992 /* do we map hats to axes or buttons? */
\r
996 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
998 http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
\r
1000 # if FREEGLUT_LIB_PRAGMAS
\r
1001 # pragma comment (lib, "advapi32.lib")
\r
1004 static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )
\r
1006 char buffer [ 256 ];
\r
1008 char OEMKey [ 256 ];
\r
1017 /* Open .. MediaResources\CurrentJoystickSettings */
\r
1018 _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",
\r
1019 REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,
\r
1020 REGSTR_KEY_JOYCURR );
\r
1022 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
\r
1024 if ( lr != ERROR_SUCCESS ) return 0;
\r
1026 /* Get OEM Key name */
\r
1027 dwcb = sizeof(OEMKey);
\r
1029 /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */
\r
1030 _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );
\r
1032 lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);
\r
1033 RegCloseKey ( hKey );
\r
1035 if ( lr != ERROR_SUCCESS ) return 0;
\r
1037 /* Open OEM Key from ...MediaProperties */
\r
1038 _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );
\r
1040 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );
\r
1042 if ( lr != ERROR_SUCCESS ) return 0;
\r
1044 /* Get OEM Name */
\r
1047 lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,
\r
1049 RegCloseKey ( hKey );
\r
1051 if ( lr != ERROR_SUCCESS ) return 0;
\r
1058 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1061 #if TARGET_HOST_MACINTOSH
\r
1064 #if TARGET_HOST_MAC_OSX
\r
1067 IOCFPlugInInterface **plugin;
\r
1069 HRESULT pluginResult;
\r
1071 CFDictionaryRef props;
\r
1072 CFTypeRef topLevelElement;
\r
1074 #if TARGET_HOST_POSIX_X11
\r
1075 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1081 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1087 /* Silence gcc, the correct #ifdefs would be too fragile... */
\r
1091 * Default values (for no joystick -- each conditional will reset the
\r
1094 joy->error = TRUE;
\r
1095 joy->num_axes = joy->num_buttons = 0;
\r
1096 joy->name[ 0 ] = '\0';
\r
1098 #if TARGET_HOST_MACINTOSH
\r
1099 /* XXX FIXME: get joystick name in Mac */
\r
1101 err = ISpStartup( );
\r
1103 if( err == noErr )
\r
1105 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
1107 joy->error = GL_TRUE;
\r
1109 /* initialize the needs structure */
\r
1110 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
1112 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1113 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1114 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1115 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1116 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1117 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1118 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1119 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1120 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1122 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1123 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1124 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1125 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1126 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1127 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1128 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1129 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1130 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1131 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1132 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1133 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1134 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1135 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1136 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1137 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1138 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1139 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1140 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1141 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1142 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1143 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1144 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1145 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1146 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1147 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1148 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1149 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1150 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1151 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1152 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1153 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1156 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
1159 /* next two calls allow keyboard and mouse to emulate other input
\r
1160 * devices (gamepads, joysticks, etc)
\r
1163 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
1164 ISP_CHECK_ERR(err)
\r
1167 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
1168 ISP_CHECK_ERR(err)
\r
1171 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
1172 joy->isp_needs, joy->isp_elem,
\r
1174 ISP_CHECK_ERR( err )
\r
1176 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
1177 'freeglut', nil, 0, 128, 0 );
\r
1178 ISP_CHECK_ERR( err )
\r
1180 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
1181 joy->num_axes = joy->isp_num_axis;
\r
1183 for( i = 0; i < joy->num_axes; i++ )
\r
1185 joy->dead_band[ i ] = 0;
\r
1186 joy->saturate [ i ] = 1;
\r
1187 joy->center [ i ] = kISpAxisMiddle;
\r
1188 joy->max [ i ] = kISpAxisMaximum;
\r
1189 joy->min [ i ] = kISpAxisMinimum;
\r
1192 joy->error = GL_FALSE;
\r
1195 joy->num_buttons = joy->num_axes = 0;
\r
1198 #if TARGET_HOST_MAC_OSX
\r
1199 if( joy->id >= numDevices )
\r
1201 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
1205 /* create device interface */
\r
1206 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
1207 kIOHIDDeviceUserClientTypeID,
\r
1208 kIOCFPlugInInterfaceID,
\r
1209 &plugin, &score );
\r
1211 if( rv != kIOReturnSuccess )
\r
1213 fgWarning( "error creating plugin for io device" );
\r
1217 pluginResult = ( *plugin )->QueryInterface(
\r
1219 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
1220 &( LPVOID )joy->hidDev
\r
1223 if( pluginResult != S_OK )
\r
1224 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
1226 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
1227 if( joy->hidDev == NULL )
\r
1230 /* store the interface in this instance */
\r
1231 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
1232 if( rv != kIOReturnSuccess )
\r
1234 fgWarning( "error opening device interface");
\r
1238 props = getCFProperties( ioDevices[ joy->id ] );
\r
1240 /* recursively enumerate all the bits */
\r
1241 CFTypeRef topLevelElement =
\r
1242 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
1243 enumerateElements( topLevelElement );
\r
1245 CFRelease( props );
\r
1248 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1249 joy->js.dwFlags = JOY_RETURNALL;
\r
1250 joy->js.dwSize = sizeof( joy->js );
\r
1252 memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
\r
1255 ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
\r
1258 if( joy->jsCaps.wNumAxes == 0 )
\r
1260 joy->num_axes = 0;
\r
1261 joy->error = GL_TRUE;
\r
1265 /* Device name from jsCaps is often "Microsoft PC-joystick driver",
\r
1266 * at least for USB. Try to get the real name from the registry.
\r
1268 if ( ! fghJoystickGetOEMProductName( joy, joy->name,
\r
1269 sizeof( joy->name ) ) )
\r
1271 fgWarning( "JS: Failed to read joystick name from registry" );
\r
1272 strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );
\r
1275 /* Windows joystick drivers may provide any combination of
\r
1276 * X,Y,Z,R,U,V,POV - not necessarily the first n of these.
\r
1278 if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )
\r
1280 joy->num_axes = _JS_MAX_AXES;
\r
1281 joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */
\r
1282 joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */
\r
1285 joy->num_axes = 6;
\r
1287 joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;
\r
1288 joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;
\r
1289 joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;
\r
1290 joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;
\r
1291 joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;
\r
1292 joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;
\r
1293 joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;
\r
1294 joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;
\r
1295 joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;
\r
1296 joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;
\r
1297 joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;
\r
1298 joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;
\r
1301 /* Guess all the rest judging on the axes extremals */
\r
1302 for( i = 0; i < joy->num_axes; i++ )
\r
1304 joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
\r
1305 joy->dead_band[ i ] = 0.0f;
\r
1306 joy->saturate [ i ] = 1.0f;
\r
1310 #if TARGET_HOST_POSIX_X11
\r
1311 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1312 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1313 joy->os->cache_axes[ i ] = 0.0f;
\r
1315 joy->os->cache_buttons = 0;
\r
1317 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1319 #ifdef HAVE_ERRNO_H
\r
1320 if( joy->os->fd < 0 && errno == EACCES )
\r
1321 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1324 joy->error =( joy->os->fd < 0 );
\r
1329 joy->num_axes = 0;
\r
1330 joy->num_buttons = 0;
\r
1331 if( joy->os->is_analog )
\r
1334 char joyfname[ 1024 ];
\r
1335 int noargs, in_no_axes;
\r
1337 float axes [ _JS_MAX_AXES ];
\r
1338 int buttons[ _JS_MAX_AXES ];
\r
1340 joy->num_axes = 2;
\r
1341 joy->num_buttons = 32;
\r
1343 fghJoystickRawRead( joy, buttons, axes );
\r
1344 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1348 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1350 joyfile = fopen( joyfname, "r" );
\r
1351 joy->error =( joyfile == NULL );
\r
1355 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1356 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1357 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1358 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1359 fclose( joyfile );
\r
1363 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1365 joy->dead_band[ i ] = 0.0f;
\r
1366 joy->saturate [ i ] = 1.0f;
\r
1369 return; /* End of analog code */
\r
1372 # ifdef HAVE_USB_JS
\r
1373 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1374 &joy->num_buttons ) )
\r
1376 close( joy->os->fd );
\r
1377 joy->error = GL_TRUE;
\r
1381 cp = strrchr( joy->os->fname, '/' );
\r
1384 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1386 strcpy( joy->name, &cp[1] );
\r
1389 if( joy->num_axes > _JS_MAX_AXES )
\r
1390 joy->num_axes = _JS_MAX_AXES;
\r
1392 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1394 /* We really should get this from the HID, but that data seems
\r
1395 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1398 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1400 joy->max [ i ] = 1.0f;
\r
1401 joy->center[ i ] = 0.0f;
\r
1402 joy->min [ i ] = -1.0f;
\r
1406 joy->max [ i ] = 255.0f;
\r
1407 joy->center[ i ] = 127.0f;
\r
1408 joy->min [ i ] = 0.0f;
\r
1411 joy->dead_band[ i ] = 0.0f;
\r
1412 joy->saturate[ i ] = 1.0f;
\r
1417 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1418 /* Default for older Linux systems. */
\r
1419 joy->num_axes = 2;
\r
1420 joy->num_buttons = 32;
\r
1423 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1424 joy->tmp_axes[ i ] = 0.0f;
\r
1426 joy->tmp_buttons = 0;
\r
1429 joy->fd = open( joy->fname, O_RDONLY );
\r
1431 joy->error =( joy->fd < 0 );
\r
1436 /* Set the correct number of axes for the linux driver */
\r
1438 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1439 * to the upper byte of an uninitialized word doesn't work.
\r
1442 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1443 joy->num_axes = u;
\r
1444 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1445 joy->num_buttons = u;
\r
1446 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1447 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1451 * The Linux driver seems to return 512 for all axes
\r
1452 * when no stick is present - but there is a chance
\r
1453 * that could happen by accident - so it's gotta happen
\r
1454 * on both axes for at least 100 attempts.
\r
1456 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1463 fghJoystickRawRead( joy, NULL, joy->center );
\r
1465 } while( !joy->error &&
\r
1467 joy->center[ 0 ] == 512.0f &&
\r
1468 joy->center[ 1 ] == 512.0f );
\r
1470 if ( counter >= 100 )
\r
1471 joy->error = GL_TRUE;
\r
1474 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1477 joy->max [ i ] = 32767.0f;
\r
1478 joy->center[ i ] = 0.0f;
\r
1479 joy->min [ i ] = -32767.0f;
\r
1481 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1482 joy->min[ i ] = 0.0f;
\r
1484 joy->dead_band[ i ] = 0.0f;
\r
1485 joy->saturate [ i ] = 1.0f;
\r
1492 * This function replaces the constructor method in the JS library.
\r
1494 static void fghJoystickInit( int ident )
\r
1496 if( ident >= MAX_NUM_JOYSTICKS )
\r
1497 fgError( "Too large a joystick number: %d", ident );
\r
1499 if( fgJoystick[ ident ] )
\r
1500 fgError( "illegal attempt to initialize joystick device again" );
\r
1502 fgJoystick[ ident ] =
\r
1503 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1505 /* Set defaults */
\r
1506 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1507 fgJoystick[ ident ]->error = GL_TRUE;
\r
1509 #if TARGET_HOST_MACINTOSH
\r
1510 fgJoystick[ ident ]->id = ident;
\r
1511 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
1512 fgJoystick[ ident ]->error = GL_FALSE;
\r
1515 #if TARGET_HOST_MAC_OSX
\r
1516 fgJoystick[ ident ]->id = ident;
\r
1517 fgJoystick[ ident ]->error = GL_FALSE;
\r
1518 fgJoystick[ ident ]->num_axes = 0;
\r
1519 fgJoystick[ ident ]->num_buttons = 0;
\r
1521 if( numDevices < 0 )
\r
1523 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
1526 mach_port_t masterPort;
\r
1527 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
1528 if( rv != kIOReturnSuccess )
\r
1530 fgWarning( "error getting master Mach port" );
\r
1533 fghJoystickFindDevices( masterPort );
\r
1536 if ( ident >= numDevices )
\r
1538 fgJoystick[ ident ]->error = GL_TRUE;
\r
1542 /* get the name now too */
\r
1543 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
1544 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
1545 CFSTR( kIOHIDProductKey ) );
\r
1547 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
1550 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
1551 CFStringGetSystemEncoding( ) ) )
\r
1553 fgWarning( "error getting device name" );
\r
1558 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1562 fgJoystick[ ident ]->js_id = JOYSTICKID1;
\r
1563 fgJoystick[ ident ]->error = GL_FALSE;
\r
1566 fgJoystick[ ident ]->js_id = JOYSTICKID2;
\r
1567 fgJoystick[ ident ]->error = GL_FALSE;
\r
1570 fgJoystick[ ident ]->num_axes = 0;
\r
1571 fgJoystick[ ident ]->error = GL_TRUE;
\r
1576 #if TARGET_HOST_POSIX_X11
\r
1577 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1578 fgJoystick[ ident ]->id = ident;
\r
1579 fgJoystick[ ident ]->error = GL_FALSE;
\r
1581 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1582 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
1583 if( ident < USB_IDENT_OFFSET )
\r
1584 fgJoystick[ ident ]->os->is_analog = 1;
\r
1585 if( fgJoystick[ ident ]->os->is_analog )
\r
1586 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
1588 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
1589 ident - USB_IDENT_OFFSET );
\r
1590 # elif defined( __linux__ )
\r
1591 fgJoystick[ ident ]->id = ident;
\r
1592 fgJoystick[ ident ]->error = GL_FALSE;
\r
1594 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
1596 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
1597 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
1601 fghJoystickOpen( fgJoystick[ ident ] );
\r
1605 * Try initializing all the joysticks (well, both of them)
\r
1607 void fgInitialiseJoysticks ( void )
\r
1609 if( !fgState.JoysticksInitialised )
\r
1612 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1613 fghJoystickInit( ident );
\r
1615 fgState.JoysticksInitialised = GL_TRUE;
\r
1622 void fgJoystickClose( void )
\r
1625 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1627 if( fgJoystick[ ident ] )
\r
1630 #if TARGET_HOST_MACINTOSH
\r
1636 #if TARGET_HOST_MAC_OSX
\r
1637 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
1638 close( fgJoystick[ ident ]->hidDev );
\r
1641 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1642 /* Do nothing special */
\r
1645 #if TARGET_HOST_POSIX_X11
\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
1665 free( fgJoystick[ ident ] );
\r
1666 fgJoystick[ ident ] = NULL;
\r
1667 /* show joystick has been deinitialized */
\r
1673 * Polls the joystick and executes the joystick callback hooked to the
\r
1674 * window specified in the function's parameter:
\r
1676 void fgJoystickPollWindow( SFG_Window* window )
\r
1678 float axes[ _JS_MAX_AXES ];
\r
1682 freeglut_return_if_fail( window );
\r
1683 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1685 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1687 if( fgJoystick[ident] )
\r
1689 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1691 if( !fgJoystick[ident]->error )
\r
1692 INVOKE_WCB( *window, Joystick,
\r
1694 (int) ( axes[ 0 ] * 1000.0f ),
\r
1695 (int) ( axes[ 1 ] * 1000.0f ),
\r
1696 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1703 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1705 int fgJoystickDetect( void )
\r
1709 fgInitialiseJoysticks ();
\r
1711 if ( !fgState.JoysticksInitialised )
\r
1714 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1715 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1722 * Joystick information functions
\r
1724 int glutJoystickGetNumAxes( int ident )
\r
1726 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1727 return fgJoystick[ ident ]->num_axes;
\r
1729 int glutJoystickGetNumButtons( int ident )
\r
1731 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1732 return fgJoystick[ ident ]->num_buttons;
\r
1734 int glutJoystickNotWorking( int ident )
\r
1736 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1737 return fgJoystick[ ident ]->error;
\r
1740 float glutJoystickGetDeadBand( int ident, int axis )
\r
1742 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1743 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1745 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1747 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1748 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1751 float glutJoystickGetSaturation( int ident, int axis )
\r
1753 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1754 return fgJoystick[ ident ]->saturate[ axis ];
\r
1756 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1758 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1759 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1762 void glutJoystickSetMinRange( int ident, float *axes )
\r
1764 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1765 memcpy( fgJoystick[ ident ]->min, axes,
\r
1766 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1768 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1770 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1771 memcpy( fgJoystick[ ident ]->max, axes,
\r
1772 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1774 void glutJoystickSetCenter( int ident, float *axes )
\r
1776 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1777 memcpy( fgJoystick[ ident ]->center, axes,
\r
1778 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1781 void glutJoystickGetMinRange( int ident, float *axes )
\r
1783 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1784 memcpy( axes, fgJoystick[ ident ]->min,
\r
1785 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1787 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1789 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1790 memcpy( axes, fgJoystick[ ident ]->max,
\r
1791 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1793 void glutJoystickGetCenter( int ident, float *axes )
\r
1795 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1796 memcpy( axes, fgJoystick[ ident ]->center,
\r
1797 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1800 /*** END OF FILE ***/
\r