2 * freeglut_joystick.c
\r
4 * Joystick handling code
\r
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
\r
7 * Written by Steve Baker, <sjbaker1@airmail.net>
\r
9 * Permission is hereby granted, free of charge, to any person obtaining a
\r
10 * copy of this software and associated documentation files (the "Software"),
\r
11 * to deal in the Software without restriction, including without limitation
\r
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
\r
13 * and/or sell copies of the Software, and to permit persons to whom the
\r
14 * Software is furnished to do so, subject to the following conditions:
\r
16 * The above copyright notice and this permission notice shall be included
\r
17 * in all copies or substantial portions of the Software.
\r
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
\r
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
\r
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
\r
22 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
28 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
\r
30 * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
\r
31 * Many thanks for Steve Baker for permission to pull from that library.
\r
34 #include <GL/freeglut.h>
\r
35 #include "freeglut_internal.h"
\r
36 #ifdef HAVE_SYS_PARAM_H
\r
37 # include <sys/param.h>
\r
41 * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
\r
45 #if TARGET_HOST_MACINTOSH
\r
46 # include <InputSprocket.h>
\r
49 #if TARGET_HOST_MAC_OSX
\r
50 # include <mach/mach.h>
\r
51 # include <IOKit/IOkitLib.h>
\r
52 # include <IOKit/hid/IOHIDLib.h>
\r
55 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
56 # include <windows.h>
\r
57 # include <mmsystem.h>
\r
58 # include <regstr.h>
\r
62 #if TARGET_HOST_POSIX_X11
\r
63 # ifdef HAVE_SYS_IOCTL_H
\r
64 # include <sys/ioctl.h>
\r
66 # ifdef HAVE_FCNTL_H
\r
69 # ifdef HAVE_ERRNO_H
\r
71 # include <string.h>
\r
73 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
74 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
75 # define HAVE_USB_JS 1
\r
77 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
78 # include <sys/joystick.h>
\r
81 * XXX NetBSD/amd64 systems may find that they have to steal the
\r
82 * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
\r
83 * XXX I cannot comment whether that works for the interface, but
\r
84 * XXX it lets you compile...(^& I do not think that we can do away
\r
85 * XXX with this header.
\r
87 # include <machine/joystick.h> /* For analog joysticks */
\r
89 # define JS_DATA_TYPE joystick
\r
90 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
93 # if defined(__linux__)
\r
94 # include <linux/joystick.h>
\r
96 /* check the joystick driver version */
\r
97 # if defined(JS_VERSION) && JS_VERSION >= 0x010000
\r
100 # else /* Not BSD or Linux */
\r
104 * We'll put these values in and that should
\r
105 * allow the code to at least compile when there is
\r
106 * no support. The JS open routine should error out
\r
107 * and shut off all the code downstream anyway and if
\r
108 * the application doesn't use a joystick we'll be fine.
\r
111 struct JS_DATA_TYPE
\r
118 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
126 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
\r
128 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
130 # ifdef HAVE_USB_JS
\r
131 # if defined(__NetBSD__)
\r
132 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
133 # define HAVE_USBHID_H 1
\r
134 # ifdef HAVE_USBHID_H
\r
135 # include <usbhid.h>
\r
139 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
140 # ifdef HAVE_USBHID_H
\r
141 # include <usbhid.h>
\r
143 # include <libusbhid.h>
\r
146 # include <legacy/dev/usb/usb.h>
\r
147 # include <dev/usb/usbhid.h>
\r
149 /* Compatibility with older usb.h revisions */
\r
150 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
\r
151 # define USB_MAX_DEVNAMES MAXDEVNAMES
\r
155 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
\r
156 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
\r
157 struct os_specific_s {
\r
161 /* The following structure members are specific to analog joysticks */
\r
162 struct joystick ajs;
\r
163 # ifdef HAVE_USB_JS
\r
164 /* The following structure members are specific to USB joysticks */
\r
165 struct hid_item *hids;
\r
168 char *hid_data_buf;
\r
169 int axes_usage [ _JS_MAX_AXES ];
\r
171 /* We keep button and axes state ourselves, as they might not be updated
\r
172 * on every read of a USB device
\r
175 float cache_axes [ _JS_MAX_AXES ];
\r
178 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
\r
179 # define USB_IDENT_OFFSET 2
\r
181 # define USBDEV "/dev/usb"
\r
182 # define UHIDDEV "/dev/uhid"
\r
183 # define AJSDEV "/dev/joy"
\r
185 # ifdef HAVE_USB_JS
\r
187 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
\r
188 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
\r
189 * return the uhidN device name. We warn the user of this situation once.
\r
191 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
\r
193 struct usb_device_info di;
\r
197 for (a = 1; a < USB_MAX_DEVICES; a++) {
\r
199 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
\r
201 for (i = 0; i < USB_MAX_DEVNAMES; i++)
\r
202 if (di.udi_devnames[i][0] &&
\r
203 strcmp(di.udi_devnames[i], dev) == 0) {
\r
204 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
\r
205 strcpy(cp, di.udi_vendor);
\r
207 strcat(cp, di.udi_product);
\r
208 strncpy(out, cp, outlen - 1);
\r
209 out[outlen - 1] = 0;
\r
217 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
\r
222 static int protection_warned = 0;
\r
224 for (i = 0; i < 16; i++) {
\r
225 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
\r
226 f = open(buf, O_RDONLY);
\r
228 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
\r
233 #ifdef HAVE_ERRNO_H
\r
234 else if (errno == EACCES) {
\r
235 if (!protection_warned) {
\r
236 fgWarning ( "Can't open %s for read!", buf );
\r
237 protection_warned = 1;
\r
245 static int fghJoystickInitializeHID(struct os_specific_s *os,
\r
246 int *num_axes, int *num_buttons)
\r
248 int size, is_joystick;
\r
249 # ifdef HAVE_USBHID_H
\r
252 struct hid_data *d;
\r
256 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
\r
258 #ifdef HAVE_ERRNO_H
\r
259 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
\r
261 fgWarning ( "error: %s", os->fname );
\r
268 # ifdef HAVE_USBHID_H
\r
269 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
\r
271 /*** XXX {report_id} may not be the right variable? ***/
\r
272 #ifdef HAVE_ERRNO_H
\r
273 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
\r
275 fgWarning ( "error: %s%d", UHIDDEV, report_id );
\r
280 size = hid_report_size( rd, hid_input, report_id );
\r
282 size = hid_report_size( rd, 0, hid_input );
\r
284 os->hid_data_buf = calloc( 1, size );
\r
285 os->hid_dlen = size;
\r
288 # ifdef HAVE_USBHID_H
\r
289 d = hid_start_parse( rd, 1 << hid_input, report_id );
\r
291 d = hid_start_parse( rd, 1 << hid_input );
\r
293 while( hid_get_item( d, &h ) )
\r
295 int usage, page, interesting_hid;
\r
297 page = HID_PAGE( h.usage );
\r
298 usage = HID_USAGE( h.usage );
\r
300 /* This test is somewhat too simplistic, but this is how MicroSoft
\r
301 * does, so I guess it works for all joysticks/game pads. */
\r
302 is_joystick = is_joystick ||
\r
303 ( h.kind == hid_collection &&
\r
304 page == HUP_GENERIC_DESKTOP &&
\r
305 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
\r
307 if( h.kind != hid_input )
\r
313 interesting_hid = TRUE;
\r
314 if( page == HUP_GENERIC_DESKTOP )
\r
325 if( *num_axes < _JS_MAX_AXES )
\r
327 os->axes_usage[ *num_axes ] = usage;
\r
331 case HUG_HAT_SWITCH:
\r
332 /* Allocate two axes for a hat */
\r
333 if( *num_axes + 1 < _JS_MAX_AXES )
\r
335 os->axes_usage[ *num_axes ] = usage;
\r
337 os->axes_usage[ *num_axes ] = usage;
\r
342 interesting_hid = FALSE;
\r
346 else if( page == HUP_BUTTON )
\r
348 interesting_hid = ( usage > 0 ) &&
\r
349 ( usage <= _JS_MAX_BUTTONS );
\r
351 if( interesting_hid && usage - 1 > *num_buttons )
\r
352 *num_buttons = usage - 1;
\r
355 if( interesting_hid )
\r
358 os->hids = calloc( 1, sizeof ( struct hid_item ) );
\r
362 hid_end_parse( d );
\r
364 return os->hids != NULL;
\r
370 * Functions associated with the "jsJoystick" class in PLIB
\r
372 #if TARGET_HOST_MAC_OSX
\r
373 #define K_NUM_DEVICES 32
\r
375 io_object_t ioDevices[K_NUM_DEVICES];
\r
377 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
\r
378 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
\r
380 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
\r
381 /* callback for CFArrayApply */
\r
382 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
\r
384 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
\r
385 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
\r
386 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
\r
390 /* External function declarations (mostly platform-specific) */
\r
391 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
\r
392 extern void fgPlatformJoystickClose ( int ident );
\r
395 * The static joystick structure pointer
\r
397 #define MAX_NUM_JOYSTICKS 2
\r
398 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
401 * Platform-Specific Code
\r
404 #if TARGET_HOST_MACINTOSH
\r
405 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
407 fgJoystick[ ident ]->id = ident;
\r
408 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
409 fgJoystick[ ident ]->error = GL_FALSE;
\r
413 void fgPlatformJoystickClose ( int ident )
\r
421 #if TARGET_HOST_MAC_OSX
\r
422 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
424 fgJoystick[ ident ]->id = ident;
\r
425 fgJoystick[ ident ]->error = GL_FALSE;
\r
426 fgJoystick[ ident ]->num_axes = 0;
\r
427 fgJoystick[ ident ]->num_buttons = 0;
\r
429 if( numDevices < 0 )
\r
431 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
434 mach_port_t masterPort;
\r
435 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
436 if( rv != kIOReturnSuccess )
\r
438 fgWarning( "error getting master Mach port" );
\r
441 fghJoystickFindDevices( masterPort );
\r
444 if ( ident >= numDevices )
\r
446 fgJoystick[ ident ]->error = GL_TRUE;
\r
450 /* get the name now too */
\r
451 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
452 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
453 CFSTR( kIOHIDProductKey ) );
\r
455 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
458 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
459 CFStringGetSystemEncoding( ) ) )
\r
461 fgWarning( "error getting device name" );
\r
467 void fgPlatformJoystickClose ( int ident )
\r
469 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
470 close( fgJoystick[ ident ]->hidDev );
\r
474 #if TARGET_HOST_POSIX_X11
\r
475 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
477 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
478 fgJoystick[ ident ]->id = ident;
\r
479 fgJoystick[ ident ]->error = GL_FALSE;
\r
481 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
482 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
483 if( ident < USB_IDENT_OFFSET )
\r
484 fgJoystick[ ident ]->os->is_analog = 1;
\r
485 if( fgJoystick[ ident ]->os->is_analog )
\r
486 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
488 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
489 ident - USB_IDENT_OFFSET );
\r
490 #elif defined( __linux__ )
\r
491 fgJoystick[ ident ]->id = ident;
\r
492 fgJoystick[ ident ]->error = GL_FALSE;
\r
494 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
496 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
497 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
502 void fgPlatformJoystickClose ( int ident )
\r
504 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
505 if( fgJoystick[ident]->os )
\r
507 if( ! fgJoystick[ ident ]->error )
\r
508 close( fgJoystick[ ident ]->os->fd );
\r
510 if( fgJoystick[ ident ]->os->hids )
\r
511 free (fgJoystick[ ident ]->os->hids);
\r
512 if( fgJoystick[ ident ]->os->hid_data_buf )
\r
513 free( fgJoystick[ ident ]->os->hid_data_buf );
\r
515 free( fgJoystick[ident]->os );
\r
519 if( ! fgJoystick[ident]->error )
\r
520 close( fgJoystick[ ident ]->fd );
\r
527 * Read the raw joystick data
\r
529 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
531 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
537 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
548 for( i = 0; i < joy->num_axes; i++ )
\r
549 axes[ i ] = 1500.0f;
\r
554 #if TARGET_HOST_MACINTOSH
\r
559 for ( i = 0; i < joy->num_buttons; i++ )
\r
562 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
565 *buttons |= state << i;
\r
571 for ( i = 0; i < joy->num_axes; i++ )
\r
574 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
577 axes [i] = (float) state;
\r
582 #if TARGET_HOST_MAC_OSX
\r
583 if ( buttons != NULL )
\r
587 for ( i = 0; i < joy->num_buttons; i++ )
\r
589 IOHIDEventStruct hidEvent;
\r
590 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
591 if ( hidEvent.value )
\r
592 *buttons |= 1 << i;
\r
596 if ( axes != NULL )
\r
598 for ( i = 0; i < joy->num_axes; i++ )
\r
600 IOHIDEventStruct hidEvent;
\r
601 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
602 axes[i] = hidEvent.value;
\r
607 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
608 status = joyGetPosEx( joy->js_id, &joy->js );
\r
610 if ( status != JOYERR_NOERROR )
\r
612 joy->error = GL_TRUE;
\r
617 *buttons = joy->js.dwButtons;
\r
622 * WARNING - Fall through case clauses!!
\r
624 switch ( joy->num_axes )
\r
627 /* Generate two POV axes from the POV hat angle.
\r
628 * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
\r
629 * hundredths of a degree, or 0xFFFF when idle.
\r
631 if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
\r
638 /* This is the contentious bit: how to convert angle to X/Y.
\r
639 * wk: I know of no define for PI that we could use here:
\r
640 * SG_PI would pull in sg, M_PI is undefined for MSVC
\r
641 * But the accuracy of the value of PI is very unimportant at
\r
644 float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
645 float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
647 /* Convert to coordinates on a square so that North-East
\r
648 * is (1,1) not (.7,.7), etc.
\r
649 * s and c cannot both be zero so we won't divide by zero.
\r
651 if ( fabs ( s ) < fabs ( c ) )
\r
653 axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;
\r
654 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
\r
658 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
\r
659 axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;
\r
663 case 6: axes[5] = (float) joy->js.dwVpos;
\r
664 case 5: axes[4] = (float) joy->js.dwUpos;
\r
665 case 4: axes[3] = (float) joy->js.dwRpos;
\r
666 case 3: axes[2] = (float) joy->js.dwZpos;
\r
667 case 2: axes[1] = (float) joy->js.dwYpos;
\r
668 case 1: axes[0] = (float) joy->js.dwXpos;
\r
673 #if TARGET_HOST_POSIX_X11
\r
674 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
675 if ( joy->os->is_analog )
\r
677 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
678 if ( status != sizeof(joy->os->ajs) ) {
\r
679 perror ( joy->os->fname );
\r
680 joy->error = GL_TRUE;
\r
683 if ( buttons != NULL )
\r
684 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
686 if ( axes != NULL )
\r
688 axes[0] = (float) joy->os->ajs.x;
\r
689 axes[1] = (float) joy->os->ajs.y;
\r
695 # ifdef HAVE_USB_JS
\r
696 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
698 struct hid_item *h;
\r
700 for ( h = joy->os->hids; h; h = h->next )
\r
702 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
704 int page = HID_PAGE ( h->usage );
\r
705 int usage = HID_USAGE ( h->usage );
\r
707 if ( page == HUP_GENERIC_DESKTOP )
\r
710 for ( i = 0; i < joy->num_axes; i++ )
\r
711 if (joy->os->axes_usage[i] == usage)
\r
713 if (usage == HUG_HAT_SWITCH)
\r
715 if (d < 0 || d > 8)
\r
716 d = 0; /* safety */
\r
717 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
718 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
722 joy->os->cache_axes[i] = (float)d;
\r
727 else if (page == HUP_BUTTON)
\r
729 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
732 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
734 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
739 #ifdef HAVE_ERRNO_H
\r
740 if ( len < 0 && errno != EAGAIN )
\r
745 perror( joy->os->fname );
\r
748 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
749 if ( axes != NULL )
\r
750 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
758 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
760 if ( status != sizeof( struct js_event ) )
\r
762 #ifdef HAVE_ERRNO_H
\r
763 if ( errno == EAGAIN )
\r
765 /* Use the old values */
\r
767 *buttons = joy->tmp_buttons;
\r
769 memcpy( axes, joy->tmp_axes,
\r
770 sizeof( float ) * joy->num_axes );
\r
775 fgWarning ( "%s", joy->fname );
\r
776 joy->error = GL_TRUE;
\r
780 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
782 case JS_EVENT_BUTTON:
\r
783 if( joy->js.value == 0 ) /* clear the flag */
\r
784 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
786 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
789 case JS_EVENT_AXIS:
\r
790 if ( joy->js.number < joy->num_axes )
\r
792 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
795 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
800 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
802 /* use the old values */
\r
804 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
805 if ( axes != NULL )
\r
806 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
812 *buttons = joy->tmp_buttons;
\r
816 status = read( joy->fd, &joy->js, JS_RETURN );
\r
818 if ( status != JS_RETURN )
\r
820 fgWarning( "%s", joy->fname );
\r
821 joy->error = GL_TRUE;
\r
826 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
827 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
829 *buttons = joy->js.buttons;
\r
834 axes[ 0 ] = (float) joy->js.x;
\r
835 axes[ 1 ] = (float) joy->js.y;
\r
842 * Correct the joystick axis data
\r
844 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
846 if( value < joy->center[ axis ] )
\r
848 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
849 joy->min[ axis ] );
\r
851 if( xx < -joy->saturate[ axis ] )
\r
854 if( xx > -joy->dead_band [ axis ] )
\r
857 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
858 joy->dead_band[ axis ] );
\r
860 return ( xx < -1.0f ) ? -1.0f : xx;
\r
864 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
865 joy->center[ axis ] );
\r
867 if( xx > joy->saturate[ axis ] )
\r
870 if( xx < joy->dead_band[ axis ] )
\r
873 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
874 joy->dead_band[ axis ] );
\r
876 return ( xx > 1.0f ) ? 1.0f : xx;
\r
881 * Read the corrected joystick data
\r
883 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
885 float raw_axes[ _JS_MAX_AXES ];
\r
894 for ( i=0; i<joy->num_axes; i++ )
\r
898 fghJoystickRawRead( joy, buttons, raw_axes );
\r
901 for( i=0; i<joy->num_axes; i++ )
\r
902 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
906 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
910 #if TARGET_HOST_MAC_OSX
\r
911 /** open the IOKit connection, enumerate all the HID devices, add their
\r
912 interface references to the static array. We then use the array index
\r
913 as the device number when we come to open() the joystick. */
\r
914 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
916 CFMutableDictionaryRef hidMatch = NULL;
\r
917 IOReturn rv = kIOReturnSuccess;
\r
919 io_iterator_t hidIterator;
\r
922 /* build a dictionary matching HID devices */
\r
923 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
925 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
926 if (rv != kIOReturnSuccess || !hidIterator) {
\r
927 fgWarning( "no joystick (HID) devices found" );
\r
932 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
933 /* filter out keyboard and mouse devices */
\r
934 CFDictionaryRef properties = getCFProperties(ioDev);
\r
937 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
938 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
939 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
940 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
942 /* keep only joystick devices */
\r
943 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
944 (usage == kHIDUsage_GD_Joystick)
\r
945 || (usage == kHIDUsage_GD_GamePad)
\r
946 || (usage == kHIDUsage_GD_MultiAxisController)
\r
947 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
948 /* add it to the array */
\r
949 ioDevices[numDevices++] = ioDev;
\r
952 IOObjectRelease(hidIterator);
\r
955 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
958 CFMutableDictionaryRef cfProperties;
\r
961 /* comment copied from darwin/SDL_sysjoystick.c */
\r
962 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
963 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
966 io_registry_entry_t parent1, parent2;
\r
968 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
969 if (rv != kIOReturnSuccess) {
\r
970 fgWarning ( "error getting device entry parent");
\r
974 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
975 if (rv != kIOReturnSuccess) {
\r
976 fgWarning ( "error getting device entry parent 2");
\r
981 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
982 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
983 if (rv != kIOReturnSuccess || !cfProperties) {
\r
984 fgWarning ( "error getting device properties");
\r
988 return cfProperties;
\r
991 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
993 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
994 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
998 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
1001 /** element enumerator function : pass NULL for top-level*/
\r
1002 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
1004 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
1005 "Joystick element type mismatch",
\r
1006 "fghJoystickEnumerateElements" );
\r
1008 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
1009 CFArrayApplyFunction((CFArrayRef) element, range,
\r
1010 &fghJoystickElementEnumerator, joy );
\r
1013 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
1015 long cookie, lmin, lmax;
\r
1016 int index = joy->num_axes++;
\r
1018 CFNumberGetValue ((CFNumberRef)
\r
1019 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
1020 kCFNumberLongType, &cookie);
\r
1022 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
1024 CFNumberGetValue ((CFNumberRef)
\r
1025 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
1026 kCFNumberLongType, &lmin);
\r
1028 CFNumberGetValue ((CFNumberRef)
\r
1029 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
1030 kCFNumberLongType, &lmax);
\r
1032 joy->min[index] = lmin;
\r
1033 joy->max[index] = lmax;
\r
1034 joy->dead_band[index] = 0.0;
\r
1035 joy->saturate[index] = 1.0;
\r
1036 joy->center[index] = (lmax + lmin) * 0.5;
\r
1039 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
1042 CFNumberGetValue ((CFNumberRef)
\r
1043 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
1044 kCFNumberLongType, &cookie);
\r
1046 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
1047 /* anything else for buttons? */
\r
1050 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
1052 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
1053 /* do we map hats to axes or buttons? */
\r
1057 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1059 http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
\r
1061 # if FREEGLUT_LIB_PRAGMAS
\r
1062 # pragma comment (lib, "advapi32.lib")
\r
1065 static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )
\r
1067 char buffer [ 256 ];
\r
1069 char OEMKey [ 256 ];
\r
1078 /* Open .. MediaResources\CurrentJoystickSettings */
\r
1079 _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",
\r
1080 REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,
\r
1081 REGSTR_KEY_JOYCURR );
\r
1083 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
\r
1085 if ( lr != ERROR_SUCCESS ) return 0;
\r
1087 /* Get OEM Key name */
\r
1088 dwcb = sizeof(OEMKey);
\r
1090 /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */
\r
1091 _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );
\r
1093 lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);
\r
1094 RegCloseKey ( hKey );
\r
1096 if ( lr != ERROR_SUCCESS ) return 0;
\r
1098 /* Open OEM Key from ...MediaProperties */
\r
1099 _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );
\r
1101 lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );
\r
1103 if ( lr != ERROR_SUCCESS ) return 0;
\r
1105 /* Get OEM Name */
\r
1108 lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,
\r
1110 RegCloseKey ( hKey );
\r
1112 if ( lr != ERROR_SUCCESS ) return 0;
\r
1119 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1122 #if TARGET_HOST_MACINTOSH
\r
1125 #if TARGET_HOST_MAC_OSX
\r
1128 IOCFPlugInInterface **plugin;
\r
1130 HRESULT pluginResult;
\r
1132 CFDictionaryRef props;
\r
1133 CFTypeRef topLevelElement;
\r
1135 #if TARGET_HOST_POSIX_X11
\r
1136 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1142 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1148 /* Silence gcc, the correct #ifdefs would be too fragile... */
\r
1152 * Default values (for no joystick -- each conditional will reset the
\r
1155 joy->error = TRUE;
\r
1156 joy->num_axes = joy->num_buttons = 0;
\r
1157 joy->name[ 0 ] = '\0';
\r
1159 #if TARGET_HOST_MACINTOSH
\r
1160 /* XXX FIXME: get joystick name in Mac */
\r
1162 err = ISpStartup( );
\r
1164 if( err == noErr )
\r
1166 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
1168 joy->error = GL_TRUE;
\r
1170 /* initialize the needs structure */
\r
1171 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
1173 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1174 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1175 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1176 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1177 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1178 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1179 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1180 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1181 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
1183 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1184 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1185 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1186 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1187 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1188 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1189 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1190 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1191 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1192 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1193 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1194 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1195 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1196 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1197 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1198 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1199 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1200 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1201 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1202 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1203 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1204 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1205 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1206 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1207 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1208 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1209 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1210 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1211 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1212 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1213 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1214 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
1217 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
1220 /* next two calls allow keyboard and mouse to emulate other input
\r
1221 * devices (gamepads, joysticks, etc)
\r
1224 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
1225 ISP_CHECK_ERR(err)
\r
1228 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
1229 ISP_CHECK_ERR(err)
\r
1232 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
1233 joy->isp_needs, joy->isp_elem,
\r
1235 ISP_CHECK_ERR( err )
\r
1237 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
1238 'freeglut', nil, 0, 128, 0 );
\r
1239 ISP_CHECK_ERR( err )
\r
1241 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
1242 joy->num_axes = joy->isp_num_axis;
\r
1244 for( i = 0; i < joy->num_axes; i++ )
\r
1246 joy->dead_band[ i ] = 0;
\r
1247 joy->saturate [ i ] = 1;
\r
1248 joy->center [ i ] = kISpAxisMiddle;
\r
1249 joy->max [ i ] = kISpAxisMaximum;
\r
1250 joy->min [ i ] = kISpAxisMinimum;
\r
1253 joy->error = GL_FALSE;
\r
1256 joy->num_buttons = joy->num_axes = 0;
\r
1259 #if TARGET_HOST_MAC_OSX
\r
1260 if( joy->id >= numDevices )
\r
1262 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
1266 /* create device interface */
\r
1267 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
1268 kIOHIDDeviceUserClientTypeID,
\r
1269 kIOCFPlugInInterfaceID,
\r
1270 &plugin, &score );
\r
1272 if( rv != kIOReturnSuccess )
\r
1274 fgWarning( "error creating plugin for io device" );
\r
1278 pluginResult = ( *plugin )->QueryInterface(
\r
1280 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
1281 &( LPVOID )joy->hidDev
\r
1284 if( pluginResult != S_OK )
\r
1285 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
1287 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
1288 if( joy->hidDev == NULL )
\r
1291 /* store the interface in this instance */
\r
1292 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
1293 if( rv != kIOReturnSuccess )
\r
1295 fgWarning( "error opening device interface");
\r
1299 props = getCFProperties( ioDevices[ joy->id ] );
\r
1301 /* recursively enumerate all the bits */
\r
1302 CFTypeRef topLevelElement =
\r
1303 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
1304 enumerateElements( topLevelElement );
\r
1306 CFRelease( props );
\r
1309 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
1310 joy->js.dwFlags = JOY_RETURNALL;
\r
1311 joy->js.dwSize = sizeof( joy->js );
\r
1313 memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
\r
1316 ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
\r
1319 if( joy->jsCaps.wNumAxes == 0 )
\r
1321 joy->num_axes = 0;
\r
1322 joy->error = GL_TRUE;
\r
1326 /* Device name from jsCaps is often "Microsoft PC-joystick driver",
\r
1327 * at least for USB. Try to get the real name from the registry.
\r
1329 if ( ! fghJoystickGetOEMProductName( joy, joy->name,
\r
1330 sizeof( joy->name ) ) )
\r
1332 fgWarning( "JS: Failed to read joystick name from registry" );
\r
1333 strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );
\r
1336 /* Windows joystick drivers may provide any combination of
\r
1337 * X,Y,Z,R,U,V,POV - not necessarily the first n of these.
\r
1339 if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )
\r
1341 joy->num_axes = _JS_MAX_AXES;
\r
1342 joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0; /* POV Y */
\r
1343 joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0; /* POV X */
\r
1346 joy->num_axes = 6;
\r
1348 joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;
\r
1349 joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;
\r
1350 joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;
\r
1351 joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;
\r
1352 joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;
\r
1353 joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;
\r
1354 joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;
\r
1355 joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;
\r
1356 joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;
\r
1357 joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;
\r
1358 joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;
\r
1359 joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;
\r
1362 /* Guess all the rest judging on the axes extremals */
\r
1363 for( i = 0; i < joy->num_axes; i++ )
\r
1365 joy->center [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
\r
1366 joy->dead_band[ i ] = 0.0f;
\r
1367 joy->saturate [ i ] = 1.0f;
\r
1371 #if TARGET_HOST_POSIX_X11
\r
1372 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1373 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1374 joy->os->cache_axes[ i ] = 0.0f;
\r
1376 joy->os->cache_buttons = 0;
\r
1378 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1380 #ifdef HAVE_ERRNO_H
\r
1381 if( joy->os->fd < 0 && errno == EACCES )
\r
1382 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1385 joy->error =( joy->os->fd < 0 );
\r
1390 joy->num_axes = 0;
\r
1391 joy->num_buttons = 0;
\r
1392 if( joy->os->is_analog )
\r
1395 char joyfname[ 1024 ];
\r
1396 int noargs, in_no_axes;
\r
1398 float axes [ _JS_MAX_AXES ];
\r
1399 int buttons[ _JS_MAX_AXES ];
\r
1401 joy->num_axes = 2;
\r
1402 joy->num_buttons = 32;
\r
1404 fghJoystickRawRead( joy, buttons, axes );
\r
1405 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1409 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1411 joyfile = fopen( joyfname, "r" );
\r
1412 joy->error =( joyfile == NULL );
\r
1416 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1417 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1418 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1419 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1420 fclose( joyfile );
\r
1424 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1426 joy->dead_band[ i ] = 0.0f;
\r
1427 joy->saturate [ i ] = 1.0f;
\r
1430 return; /* End of analog code */
\r
1433 # ifdef HAVE_USB_JS
\r
1434 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1435 &joy->num_buttons ) )
\r
1437 close( joy->os->fd );
\r
1438 joy->error = GL_TRUE;
\r
1442 cp = strrchr( joy->os->fname, '/' );
\r
1445 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1447 strcpy( joy->name, &cp[1] );
\r
1450 if( joy->num_axes > _JS_MAX_AXES )
\r
1451 joy->num_axes = _JS_MAX_AXES;
\r
1453 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1455 /* We really should get this from the HID, but that data seems
\r
1456 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1459 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1461 joy->max [ i ] = 1.0f;
\r
1462 joy->center[ i ] = 0.0f;
\r
1463 joy->min [ i ] = -1.0f;
\r
1467 joy->max [ i ] = 255.0f;
\r
1468 joy->center[ i ] = 127.0f;
\r
1469 joy->min [ i ] = 0.0f;
\r
1472 joy->dead_band[ i ] = 0.0f;
\r
1473 joy->saturate[ i ] = 1.0f;
\r
1478 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1479 /* Default for older Linux systems. */
\r
1480 joy->num_axes = 2;
\r
1481 joy->num_buttons = 32;
\r
1484 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1485 joy->tmp_axes[ i ] = 0.0f;
\r
1487 joy->tmp_buttons = 0;
\r
1490 joy->fd = open( joy->fname, O_RDONLY );
\r
1492 joy->error =( joy->fd < 0 );
\r
1497 /* Set the correct number of axes for the linux driver */
\r
1499 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1500 * to the upper byte of an uninitialized word doesn't work.
\r
1503 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1504 joy->num_axes = u;
\r
1505 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1506 joy->num_buttons = u;
\r
1507 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1508 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1512 * The Linux driver seems to return 512 for all axes
\r
1513 * when no stick is present - but there is a chance
\r
1514 * that could happen by accident - so it's gotta happen
\r
1515 * on both axes for at least 100 attempts.
\r
1517 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1524 fghJoystickRawRead( joy, NULL, joy->center );
\r
1526 } while( !joy->error &&
\r
1528 joy->center[ 0 ] == 512.0f &&
\r
1529 joy->center[ 1 ] == 512.0f );
\r
1531 if ( counter >= 100 )
\r
1532 joy->error = GL_TRUE;
\r
1535 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1538 joy->max [ i ] = 32767.0f;
\r
1539 joy->center[ i ] = 0.0f;
\r
1540 joy->min [ i ] = -32767.0f;
\r
1542 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1543 joy->min[ i ] = 0.0f;
\r
1545 joy->dead_band[ i ] = 0.0f;
\r
1546 joy->saturate [ i ] = 1.0f;
\r
1553 * This function replaces the constructor method in the JS library.
\r
1555 static void fghJoystickInit( int ident )
\r
1557 if( ident >= MAX_NUM_JOYSTICKS )
\r
1558 fgError( "Too large a joystick number: %d", ident );
\r
1560 if( fgJoystick[ ident ] )
\r
1561 fgError( "illegal attempt to initialize joystick device again" );
\r
1563 fgJoystick[ ident ] =
\r
1564 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1566 /* Set defaults */
\r
1567 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1568 fgJoystick[ ident ]->error = GL_TRUE;
\r
1570 fgPlatformJoystickInit( fgJoystick, ident );
\r
1572 fghJoystickOpen( fgJoystick[ ident ] );
\r
1576 * Try initializing all the joysticks (well, both of them)
\r
1578 void fgInitialiseJoysticks ( void )
\r
1580 if( !fgState.JoysticksInitialised )
\r
1583 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1584 fghJoystickInit( ident );
\r
1586 fgState.JoysticksInitialised = GL_TRUE;
\r
1591 void fgJoystickClose( void )
\r
1594 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1596 if( fgJoystick[ ident ] )
\r
1598 fgPlatformJoystickClose ( ident );
\r
1600 free( fgJoystick[ ident ] );
\r
1601 fgJoystick[ ident ] = NULL;
\r
1602 /* show joystick has been deinitialized */
\r
1608 * Polls the joystick and executes the joystick callback hooked to the
\r
1609 * window specified in the function's parameter:
\r
1611 void fgJoystickPollWindow( SFG_Window* window )
\r
1613 float axes[ _JS_MAX_AXES ];
\r
1617 freeglut_return_if_fail( window );
\r
1618 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1620 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1622 if( fgJoystick[ident] )
\r
1624 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1626 if( !fgJoystick[ident]->error )
\r
1627 INVOKE_WCB( *window, Joystick,
\r
1629 (int) ( axes[ 0 ] * 1000.0f ),
\r
1630 (int) ( axes[ 1 ] * 1000.0f ),
\r
1631 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1638 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1640 int fgJoystickDetect( void )
\r
1644 fgInitialiseJoysticks ();
\r
1646 if ( !fgState.JoysticksInitialised )
\r
1649 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1650 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1657 * Joystick information functions
\r
1659 int glutJoystickGetNumAxes( int ident )
\r
1661 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1662 return fgJoystick[ ident ]->num_axes;
\r
1664 int glutJoystickGetNumButtons( int ident )
\r
1666 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1667 return fgJoystick[ ident ]->num_buttons;
\r
1669 int glutJoystickNotWorking( int ident )
\r
1671 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1672 return fgJoystick[ ident ]->error;
\r
1675 float glutJoystickGetDeadBand( int ident, int axis )
\r
1677 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1678 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1680 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1682 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1683 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1686 float glutJoystickGetSaturation( int ident, int axis )
\r
1688 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1689 return fgJoystick[ ident ]->saturate[ axis ];
\r
1691 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1693 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1694 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1697 void glutJoystickSetMinRange( int ident, float *axes )
\r
1699 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1700 memcpy( fgJoystick[ ident ]->min, axes,
\r
1701 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1703 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1705 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1706 memcpy( fgJoystick[ ident ]->max, axes,
\r
1707 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1709 void glutJoystickSetCenter( int ident, float *axes )
\r
1711 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1712 memcpy( fgJoystick[ ident ]->center, axes,
\r
1713 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1716 void glutJoystickGetMinRange( int ident, float *axes )
\r
1718 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1719 memcpy( axes, fgJoystick[ ident ]->min,
\r
1720 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1722 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1724 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1725 memcpy( axes, fgJoystick[ ident ]->max,
\r
1726 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1728 void glutJoystickGetCenter( int ident, float *axes )
\r
1730 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1731 memcpy( axes, fgJoystick[ ident ]->center,
\r
1732 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1735 /*** END OF FILE ***/
\r