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 fgPlatformJoystickOpen( SFG_Joystick* joy );
\r
392 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
\r
393 extern void fgPlatformJoystickClose ( int ident );
\r
396 * The static joystick structure pointer
\r
398 #define MAX_NUM_JOYSTICKS 2
\r
399 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
402 * Read the raw joystick data
\r
404 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
406 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
412 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
423 for( i = 0; i < joy->num_axes; i++ )
\r
424 axes[ i ] = 1500.0f;
\r
429 #if TARGET_HOST_MACINTOSH
\r
434 for ( i = 0; i < joy->num_buttons; i++ )
\r
437 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
440 *buttons |= state << i;
\r
446 for ( i = 0; i < joy->num_axes; i++ )
\r
449 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
452 axes [i] = (float) state;
\r
457 #if TARGET_HOST_MAC_OSX
\r
458 if ( buttons != NULL )
\r
462 for ( i = 0; i < joy->num_buttons; i++ )
\r
464 IOHIDEventStruct hidEvent;
\r
465 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
466 if ( hidEvent.value )
\r
467 *buttons |= 1 << i;
\r
471 if ( axes != NULL )
\r
473 for ( i = 0; i < joy->num_axes; i++ )
\r
475 IOHIDEventStruct hidEvent;
\r
476 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
477 axes[i] = hidEvent.value;
\r
482 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
\r
483 status = joyGetPosEx( joy->js_id, &joy->js );
\r
485 if ( status != JOYERR_NOERROR )
\r
487 joy->error = GL_TRUE;
\r
492 *buttons = joy->js.dwButtons;
\r
497 * WARNING - Fall through case clauses!!
\r
499 switch ( joy->num_axes )
\r
502 /* Generate two POV axes from the POV hat angle.
\r
503 * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
\r
504 * hundredths of a degree, or 0xFFFF when idle.
\r
506 if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
\r
513 /* This is the contentious bit: how to convert angle to X/Y.
\r
514 * wk: I know of no define for PI that we could use here:
\r
515 * SG_PI would pull in sg, M_PI is undefined for MSVC
\r
516 * But the accuracy of the value of PI is very unimportant at
\r
519 float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
520 float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
\r
522 /* Convert to coordinates on a square so that North-East
\r
523 * is (1,1) not (.7,.7), etc.
\r
524 * s and c cannot both be zero so we won't divide by zero.
\r
526 if ( fabs ( s ) < fabs ( c ) )
\r
528 axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;
\r
529 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
\r
533 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
\r
534 axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;
\r
538 case 6: axes[5] = (float) joy->js.dwVpos;
\r
539 case 5: axes[4] = (float) joy->js.dwUpos;
\r
540 case 4: axes[3] = (float) joy->js.dwRpos;
\r
541 case 3: axes[2] = (float) joy->js.dwZpos;
\r
542 case 2: axes[1] = (float) joy->js.dwYpos;
\r
543 case 1: axes[0] = (float) joy->js.dwXpos;
\r
548 #if TARGET_HOST_POSIX_X11
\r
549 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
550 if ( joy->os->is_analog )
\r
552 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
553 if ( status != sizeof(joy->os->ajs) ) {
\r
554 perror ( joy->os->fname );
\r
555 joy->error = GL_TRUE;
\r
558 if ( buttons != NULL )
\r
559 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
561 if ( axes != NULL )
\r
563 axes[0] = (float) joy->os->ajs.x;
\r
564 axes[1] = (float) joy->os->ajs.y;
\r
570 # ifdef HAVE_USB_JS
\r
571 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
573 struct hid_item *h;
\r
575 for ( h = joy->os->hids; h; h = h->next )
\r
577 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
579 int page = HID_PAGE ( h->usage );
\r
580 int usage = HID_USAGE ( h->usage );
\r
582 if ( page == HUP_GENERIC_DESKTOP )
\r
585 for ( i = 0; i < joy->num_axes; i++ )
\r
586 if (joy->os->axes_usage[i] == usage)
\r
588 if (usage == HUG_HAT_SWITCH)
\r
590 if (d < 0 || d > 8)
\r
591 d = 0; /* safety */
\r
592 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
593 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
597 joy->os->cache_axes[i] = (float)d;
\r
602 else if (page == HUP_BUTTON)
\r
604 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
607 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
609 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
614 #ifdef HAVE_ERRNO_H
\r
615 if ( len < 0 && errno != EAGAIN )
\r
620 perror( joy->os->fname );
\r
623 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
624 if ( axes != NULL )
\r
625 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
633 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
635 if ( status != sizeof( struct js_event ) )
\r
637 #ifdef HAVE_ERRNO_H
\r
638 if ( errno == EAGAIN )
\r
640 /* Use the old values */
\r
642 *buttons = joy->tmp_buttons;
\r
644 memcpy( axes, joy->tmp_axes,
\r
645 sizeof( float ) * joy->num_axes );
\r
650 fgWarning ( "%s", joy->fname );
\r
651 joy->error = GL_TRUE;
\r
655 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
657 case JS_EVENT_BUTTON:
\r
658 if( joy->js.value == 0 ) /* clear the flag */
\r
659 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
661 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
664 case JS_EVENT_AXIS:
\r
665 if ( joy->js.number < joy->num_axes )
\r
667 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
670 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
675 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
677 /* use the old values */
\r
679 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
680 if ( axes != NULL )
\r
681 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
687 *buttons = joy->tmp_buttons;
\r
691 status = read( joy->fd, &joy->js, JS_RETURN );
\r
693 if ( status != JS_RETURN )
\r
695 fgWarning( "%s", joy->fname );
\r
696 joy->error = GL_TRUE;
\r
701 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
702 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
704 *buttons = joy->js.buttons;
\r
709 axes[ 0 ] = (float) joy->js.x;
\r
710 axes[ 1 ] = (float) joy->js.y;
\r
717 * Correct the joystick axis data
\r
719 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
721 if( value < joy->center[ axis ] )
\r
723 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
724 joy->min[ axis ] );
\r
726 if( xx < -joy->saturate[ axis ] )
\r
729 if( xx > -joy->dead_band [ axis ] )
\r
732 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
733 joy->dead_band[ axis ] );
\r
735 return ( xx < -1.0f ) ? -1.0f : xx;
\r
739 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
740 joy->center[ axis ] );
\r
742 if( xx > joy->saturate[ axis ] )
\r
745 if( xx < joy->dead_band[ axis ] )
\r
748 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
749 joy->dead_band[ axis ] );
\r
751 return ( xx > 1.0f ) ? 1.0f : xx;
\r
756 * Read the corrected joystick data
\r
758 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
760 float raw_axes[ _JS_MAX_AXES ];
\r
769 for ( i=0; i<joy->num_axes; i++ )
\r
773 fghJoystickRawRead( joy, buttons, raw_axes );
\r
776 for( i=0; i<joy->num_axes; i++ )
\r
777 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
781 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
785 #if TARGET_HOST_MAC_OSX
\r
786 /** open the IOKit connection, enumerate all the HID devices, add their
\r
787 interface references to the static array. We then use the array index
\r
788 as the device number when we come to open() the joystick. */
\r
789 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
791 CFMutableDictionaryRef hidMatch = NULL;
\r
792 IOReturn rv = kIOReturnSuccess;
\r
794 io_iterator_t hidIterator;
\r
797 /* build a dictionary matching HID devices */
\r
798 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
800 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
801 if (rv != kIOReturnSuccess || !hidIterator) {
\r
802 fgWarning( "no joystick (HID) devices found" );
\r
807 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
808 /* filter out keyboard and mouse devices */
\r
809 CFDictionaryRef properties = getCFProperties(ioDev);
\r
812 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
813 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
814 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
815 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
817 /* keep only joystick devices */
\r
818 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
819 (usage == kHIDUsage_GD_Joystick)
\r
820 || (usage == kHIDUsage_GD_GamePad)
\r
821 || (usage == kHIDUsage_GD_MultiAxisController)
\r
822 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
823 /* add it to the array */
\r
824 ioDevices[numDevices++] = ioDev;
\r
827 IOObjectRelease(hidIterator);
\r
830 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
833 CFMutableDictionaryRef cfProperties;
\r
836 /* comment copied from darwin/SDL_sysjoystick.c */
\r
837 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
838 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
841 io_registry_entry_t parent1, parent2;
\r
843 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
844 if (rv != kIOReturnSuccess) {
\r
845 fgWarning ( "error getting device entry parent");
\r
849 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
850 if (rv != kIOReturnSuccess) {
\r
851 fgWarning ( "error getting device entry parent 2");
\r
856 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
857 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
858 if (rv != kIOReturnSuccess || !cfProperties) {
\r
859 fgWarning ( "error getting device properties");
\r
863 return cfProperties;
\r
866 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
868 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
869 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
873 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
876 /** element enumerator function : pass NULL for top-level*/
\r
877 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
879 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
880 "Joystick element type mismatch",
\r
881 "fghJoystickEnumerateElements" );
\r
883 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
884 CFArrayApplyFunction((CFArrayRef) element, range,
\r
885 &fghJoystickElementEnumerator, joy );
\r
888 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
890 long cookie, lmin, lmax;
\r
891 int index = joy->num_axes++;
\r
893 CFNumberGetValue ((CFNumberRef)
\r
894 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
895 kCFNumberLongType, &cookie);
\r
897 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
899 CFNumberGetValue ((CFNumberRef)
\r
900 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
901 kCFNumberLongType, &lmin);
\r
903 CFNumberGetValue ((CFNumberRef)
\r
904 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
905 kCFNumberLongType, &lmax);
\r
907 joy->min[index] = lmin;
\r
908 joy->max[index] = lmax;
\r
909 joy->dead_band[index] = 0.0;
\r
910 joy->saturate[index] = 1.0;
\r
911 joy->center[index] = (lmax + lmin) * 0.5;
\r
914 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
917 CFNumberGetValue ((CFNumberRef)
\r
918 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
919 kCFNumberLongType, &cookie);
\r
921 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
922 /* anything else for buttons? */
\r
925 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
927 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
928 /* do we map hats to axes or buttons? */
\r
933 * Platform-Specific Code
\r
936 #if TARGET_HOST_MACINTOSH
\r
937 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
942 /* XXX FIXME: get joystick name in Mac */
\r
944 err = ISpStartup( );
\r
948 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
950 joy->error = GL_TRUE;
\r
952 /* initialize the needs structure */
\r
953 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
955 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
956 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
957 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
958 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
959 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
960 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
961 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
962 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
963 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
965 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
966 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
967 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
968 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
969 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
970 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
971 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
972 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
973 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
974 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
975 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
976 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
977 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
978 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
979 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
980 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
981 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
982 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
983 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
984 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
985 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
986 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
987 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
988 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
989 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
990 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
991 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
992 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
993 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
994 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
995 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
996 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
999 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
1002 /* next two calls allow keyboard and mouse to emulate other input
\r
1003 * devices (gamepads, joysticks, etc)
\r
1006 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
1007 ISP_CHECK_ERR(err)
\r
1010 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
1011 ISP_CHECK_ERR(err)
\r
1014 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
1015 joy->isp_needs, joy->isp_elem,
\r
1017 ISP_CHECK_ERR( err )
\r
1019 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
1020 'freeglut', nil, 0, 128, 0 );
\r
1021 ISP_CHECK_ERR( err )
\r
1023 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
1024 joy->num_axes = joy->isp_num_axis;
\r
1026 for( i = 0; i < joy->num_axes; i++ )
\r
1028 joy->dead_band[ i ] = 0;
\r
1029 joy->saturate [ i ] = 1;
\r
1030 joy->center [ i ] = kISpAxisMiddle;
\r
1031 joy->max [ i ] = kISpAxisMaximum;
\r
1032 joy->min [ i ] = kISpAxisMinimum;
\r
1035 joy->error = GL_FALSE;
\r
1038 joy->num_buttons = joy->num_axes = 0;
\r
1042 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
1044 fgJoystick[ ident ]->id = ident;
\r
1045 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
1046 fgJoystick[ ident ]->error = GL_FALSE;
\r
1050 void fgPlatformJoystickClose ( int ident )
\r
1058 #if TARGET_HOST_MAC_OSX
\r
1059 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
1063 IOCFPlugInInterface **plugin;
\r
1065 HRESULT pluginResult;
\r
1067 CFDictionaryRef props;
\r
1068 CFTypeRef topLevelElement;
\r
1070 if( joy->id >= numDevices )
\r
1072 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
1076 /* create device interface */
\r
1077 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
1078 kIOHIDDeviceUserClientTypeID,
\r
1079 kIOCFPlugInInterfaceID,
\r
1080 &plugin, &score );
\r
1082 if( rv != kIOReturnSuccess )
\r
1084 fgWarning( "error creating plugin for io device" );
\r
1088 pluginResult = ( *plugin )->QueryInterface(
\r
1090 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
1091 &( LPVOID )joy->hidDev
\r
1094 if( pluginResult != S_OK )
\r
1095 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
1097 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
1098 if( joy->hidDev == NULL )
\r
1101 /* store the interface in this instance */
\r
1102 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
1103 if( rv != kIOReturnSuccess )
\r
1105 fgWarning( "error opening device interface");
\r
1109 props = getCFProperties( ioDevices[ joy->id ] );
\r
1111 /* recursively enumerate all the bits */
\r
1112 CFTypeRef topLevelElement =
\r
1113 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
1114 enumerateElements( topLevelElement );
\r
1116 CFRelease( props );
\r
1120 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
1122 fgJoystick[ ident ]->id = ident;
\r
1123 fgJoystick[ ident ]->error = GL_FALSE;
\r
1124 fgJoystick[ ident ]->num_axes = 0;
\r
1125 fgJoystick[ ident ]->num_buttons = 0;
\r
1127 if( numDevices < 0 )
\r
1129 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
1132 mach_port_t masterPort;
\r
1133 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
1134 if( rv != kIOReturnSuccess )
\r
1136 fgWarning( "error getting master Mach port" );
\r
1139 fghJoystickFindDevices( masterPort );
\r
1142 if ( ident >= numDevices )
\r
1144 fgJoystick[ ident ]->error = GL_TRUE;
\r
1148 /* get the name now too */
\r
1149 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
1150 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
1151 CFSTR( kIOHIDProductKey ) );
\r
1153 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
1156 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
1157 CFStringGetSystemEncoding( ) ) )
\r
1159 fgWarning( "error getting device name" );
\r
1165 void fgPlatformJoystickClose ( int ident )
\r
1167 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
1168 close( fgJoystick[ ident ]->hidDev );
\r
1172 #if TARGET_HOST_POSIX_X11
\r
1173 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
1175 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1182 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1188 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1189 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1190 joy->os->cache_axes[ i ] = 0.0f;
\r
1192 joy->os->cache_buttons = 0;
\r
1194 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1196 #ifdef HAVE_ERRNO_H
\r
1197 if( joy->os->fd < 0 && errno == EACCES )
\r
1198 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1201 joy->error =( joy->os->fd < 0 );
\r
1206 joy->num_axes = 0;
\r
1207 joy->num_buttons = 0;
\r
1208 if( joy->os->is_analog )
\r
1211 char joyfname[ 1024 ];
\r
1212 int noargs, in_no_axes;
\r
1214 float axes [ _JS_MAX_AXES ];
\r
1215 int buttons[ _JS_MAX_AXES ];
\r
1217 joy->num_axes = 2;
\r
1218 joy->num_buttons = 32;
\r
1220 fghJoystickRawRead( joy, buttons, axes );
\r
1221 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1225 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1227 joyfile = fopen( joyfname, "r" );
\r
1228 joy->error =( joyfile == NULL );
\r
1232 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1233 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1234 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1235 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1236 fclose( joyfile );
\r
1240 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1242 joy->dead_band[ i ] = 0.0f;
\r
1243 joy->saturate [ i ] = 1.0f;
\r
1246 return; /* End of analog code */
\r
1249 # ifdef HAVE_USB_JS
\r
1250 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1251 &joy->num_buttons ) )
\r
1253 close( joy->os->fd );
\r
1254 joy->error = GL_TRUE;
\r
1258 cp = strrchr( joy->os->fname, '/' );
\r
1261 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1263 strcpy( joy->name, &cp[1] );
\r
1266 if( joy->num_axes > _JS_MAX_AXES )
\r
1267 joy->num_axes = _JS_MAX_AXES;
\r
1269 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1271 /* We really should get this from the HID, but that data seems
\r
1272 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1275 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1277 joy->max [ i ] = 1.0f;
\r
1278 joy->center[ i ] = 0.0f;
\r
1279 joy->min [ i ] = -1.0f;
\r
1283 joy->max [ i ] = 255.0f;
\r
1284 joy->center[ i ] = 127.0f;
\r
1285 joy->min [ i ] = 0.0f;
\r
1288 joy->dead_band[ i ] = 0.0f;
\r
1289 joy->saturate[ i ] = 1.0f;
\r
1294 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1295 /* Default for older Linux systems. */
\r
1296 joy->num_axes = 2;
\r
1297 joy->num_buttons = 32;
\r
1300 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1301 joy->tmp_axes[ i ] = 0.0f;
\r
1303 joy->tmp_buttons = 0;
\r
1306 joy->fd = open( joy->fname, O_RDONLY );
\r
1308 joy->error =( joy->fd < 0 );
\r
1313 /* Set the correct number of axes for the linux driver */
\r
1315 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1316 * to the upper byte of an uninitialized word doesn't work.
\r
1319 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1320 joy->num_axes = u;
\r
1321 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1322 joy->num_buttons = u;
\r
1323 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1324 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1328 * The Linux driver seems to return 512 for all axes
\r
1329 * when no stick is present - but there is a chance
\r
1330 * that could happen by accident - so it's gotta happen
\r
1331 * on both axes for at least 100 attempts.
\r
1333 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1340 fghJoystickRawRead( joy, NULL, joy->center );
\r
1342 } while( !joy->error &&
\r
1344 joy->center[ 0 ] == 512.0f &&
\r
1345 joy->center[ 1 ] == 512.0f );
\r
1347 if ( counter >= 100 )
\r
1348 joy->error = GL_TRUE;
\r
1351 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1354 joy->max [ i ] = 32767.0f;
\r
1355 joy->center[ i ] = 0.0f;
\r
1356 joy->min [ i ] = -32767.0f;
\r
1358 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1359 joy->min[ i ] = 0.0f;
\r
1361 joy->dead_band[ i ] = 0.0f;
\r
1362 joy->saturate [ i ] = 1.0f;
\r
1368 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
1370 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1371 fgJoystick[ ident ]->id = ident;
\r
1372 fgJoystick[ ident ]->error = GL_FALSE;
\r
1374 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1375 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
1376 if( ident < USB_IDENT_OFFSET )
\r
1377 fgJoystick[ ident ]->os->is_analog = 1;
\r
1378 if( fgJoystick[ ident ]->os->is_analog )
\r
1379 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
1381 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
1382 ident - USB_IDENT_OFFSET );
\r
1383 #elif defined( __linux__ )
\r
1384 fgJoystick[ ident ]->id = ident;
\r
1385 fgJoystick[ ident ]->error = GL_FALSE;
\r
1387 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
1389 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
1390 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
1395 void fgPlatformJoystickClose ( int ident )
\r
1397 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1398 if( fgJoystick[ident]->os )
\r
1400 if( ! fgJoystick[ ident ]->error )
\r
1401 close( fgJoystick[ ident ]->os->fd );
\r
1402 #ifdef HAVE_USB_JS
\r
1403 if( fgJoystick[ ident ]->os->hids )
\r
1404 free (fgJoystick[ ident ]->os->hids);
\r
1405 if( fgJoystick[ ident ]->os->hid_data_buf )
\r
1406 free( fgJoystick[ ident ]->os->hid_data_buf );
\r
1408 free( fgJoystick[ident]->os );
\r
1412 if( ! fgJoystick[ident]->error )
\r
1413 close( fgJoystick[ ident ]->fd );
\r
1422 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1425 * Default values (for no joystick -- each conditional will reset the
\r
1428 joy->error = TRUE;
\r
1429 joy->num_axes = joy->num_buttons = 0;
\r
1430 joy->name[ 0 ] = '\0';
\r
1432 fgPlatformJoystickOpen ( joy );
\r
1437 * This function replaces the constructor method in the JS library.
\r
1439 static void fghJoystickInit( int ident )
\r
1441 if( ident >= MAX_NUM_JOYSTICKS )
\r
1442 fgError( "Too large a joystick number: %d", ident );
\r
1444 if( fgJoystick[ ident ] )
\r
1445 fgError( "illegal attempt to initialize joystick device again" );
\r
1447 fgJoystick[ ident ] =
\r
1448 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1450 /* Set defaults */
\r
1451 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1452 fgJoystick[ ident ]->error = GL_TRUE;
\r
1454 fgPlatformJoystickInit( fgJoystick, ident );
\r
1456 fghJoystickOpen( fgJoystick[ ident ] );
\r
1460 * Try initializing all the joysticks (well, both of them)
\r
1462 void fgInitialiseJoysticks ( void )
\r
1464 if( !fgState.JoysticksInitialised )
\r
1467 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1468 fghJoystickInit( ident );
\r
1470 fgState.JoysticksInitialised = GL_TRUE;
\r
1475 void fgJoystickClose( void )
\r
1478 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1480 if( fgJoystick[ ident ] )
\r
1482 fgPlatformJoystickClose ( ident );
\r
1484 free( fgJoystick[ ident ] );
\r
1485 fgJoystick[ ident ] = NULL;
\r
1486 /* show joystick has been deinitialized */
\r
1492 * Polls the joystick and executes the joystick callback hooked to the
\r
1493 * window specified in the function's parameter:
\r
1495 void fgJoystickPollWindow( SFG_Window* window )
\r
1497 float axes[ _JS_MAX_AXES ];
\r
1501 freeglut_return_if_fail( window );
\r
1502 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1504 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1506 if( fgJoystick[ident] )
\r
1508 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1510 if( !fgJoystick[ident]->error )
\r
1511 INVOKE_WCB( *window, Joystick,
\r
1513 (int) ( axes[ 0 ] * 1000.0f ),
\r
1514 (int) ( axes[ 1 ] * 1000.0f ),
\r
1515 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1522 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1524 int fgJoystickDetect( void )
\r
1528 fgInitialiseJoysticks ();
\r
1530 if ( !fgState.JoysticksInitialised )
\r
1533 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1534 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1541 * Joystick information functions
\r
1543 int glutJoystickGetNumAxes( int ident )
\r
1545 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1546 return fgJoystick[ ident ]->num_axes;
\r
1548 int glutJoystickGetNumButtons( int ident )
\r
1550 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1551 return fgJoystick[ ident ]->num_buttons;
\r
1553 int glutJoystickNotWorking( int ident )
\r
1555 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1556 return fgJoystick[ ident ]->error;
\r
1559 float glutJoystickGetDeadBand( int ident, int axis )
\r
1561 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1562 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1564 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1566 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1567 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1570 float glutJoystickGetSaturation( int ident, int axis )
\r
1572 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1573 return fgJoystick[ ident ]->saturate[ axis ];
\r
1575 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1577 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1578 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1581 void glutJoystickSetMinRange( int ident, float *axes )
\r
1583 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1584 memcpy( fgJoystick[ ident ]->min, axes,
\r
1585 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1587 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1589 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1590 memcpy( fgJoystick[ ident ]->max, axes,
\r
1591 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1593 void glutJoystickSetCenter( int ident, float *axes )
\r
1595 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1596 memcpy( fgJoystick[ ident ]->center, axes,
\r
1597 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1600 void glutJoystickGetMinRange( int ident, float *axes )
\r
1602 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1603 memcpy( axes, fgJoystick[ ident ]->min,
\r
1604 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1606 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1608 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1609 memcpy( axes, fgJoystick[ ident ]->max,
\r
1610 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1612 void glutJoystickGetCenter( int ident, float *axes )
\r
1614 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1615 memcpy( axes, fgJoystick[ ident ]->center,
\r
1616 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1619 /*** END OF FILE ***/
\r