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
43 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
\r
45 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
48 # if defined(__NetBSD__)
\r
49 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
50 # define HAVE_USBHID_H 1
\r
51 # ifdef HAVE_USBHID_H
\r
52 # include <usbhid.h>
\r
56 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
57 # ifdef HAVE_USBHID_H
\r
58 # include <usbhid.h>
\r
60 # include <libusbhid.h>
\r
63 # include <legacy/dev/usb/usb.h>
\r
64 # include <dev/usb/usbhid.h>
\r
66 /* Compatibility with older usb.h revisions */
\r
67 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
\r
68 # define USB_MAX_DEVNAMES MAXDEVNAMES
\r
72 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
\r
73 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
\r
74 struct os_specific_s {
\r
78 /* The following structure members are specific to analog joysticks */
\r
79 struct joystick ajs;
\r
81 /* The following structure members are specific to USB joysticks */
\r
82 struct hid_item *hids;
\r
86 int axes_usage [ _JS_MAX_AXES ];
\r
88 /* We keep button and axes state ourselves, as they might not be updated
\r
89 * on every read of a USB device
\r
92 float cache_axes [ _JS_MAX_AXES ];
\r
95 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
\r
96 # define USB_IDENT_OFFSET 2
\r
98 # define USBDEV "/dev/usb"
\r
99 # define UHIDDEV "/dev/uhid"
\r
100 # define AJSDEV "/dev/joy"
\r
102 # ifdef HAVE_USB_JS
\r
104 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
\r
105 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
\r
106 * return the uhidN device name. We warn the user of this situation once.
\r
108 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
\r
110 struct usb_device_info di;
\r
114 for (a = 1; a < USB_MAX_DEVICES; a++) {
\r
116 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
\r
118 for (i = 0; i < USB_MAX_DEVNAMES; i++)
\r
119 if (di.udi_devnames[i][0] &&
\r
120 strcmp(di.udi_devnames[i], dev) == 0) {
\r
121 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
\r
122 strcpy(cp, di.udi_vendor);
\r
124 strcat(cp, di.udi_product);
\r
125 strncpy(out, cp, outlen - 1);
\r
126 out[outlen - 1] = 0;
\r
134 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
\r
139 static int protection_warned = 0;
\r
141 for (i = 0; i < 16; i++) {
\r
142 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
\r
143 f = open(buf, O_RDONLY);
\r
145 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
\r
150 #ifdef HAVE_ERRNO_H
\r
151 else if (errno == EACCES) {
\r
152 if (!protection_warned) {
\r
153 fgWarning ( "Can't open %s for read!", buf );
\r
154 protection_warned = 1;
\r
162 static int fghJoystickInitializeHID(struct os_specific_s *os,
\r
163 int *num_axes, int *num_buttons)
\r
165 int size, is_joystick;
\r
166 # ifdef HAVE_USBHID_H
\r
169 struct hid_data *d;
\r
173 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
\r
175 #ifdef HAVE_ERRNO_H
\r
176 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
\r
178 fgWarning ( "error: %s", os->fname );
\r
185 # ifdef HAVE_USBHID_H
\r
186 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
\r
188 /*** XXX {report_id} may not be the right variable? ***/
\r
189 #ifdef HAVE_ERRNO_H
\r
190 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
\r
192 fgWarning ( "error: %s%d", UHIDDEV, report_id );
\r
197 size = hid_report_size( rd, hid_input, report_id );
\r
199 size = hid_report_size( rd, 0, hid_input );
\r
201 os->hid_data_buf = calloc( 1, size );
\r
202 os->hid_dlen = size;
\r
205 # ifdef HAVE_USBHID_H
\r
206 d = hid_start_parse( rd, 1 << hid_input, report_id );
\r
208 d = hid_start_parse( rd, 1 << hid_input );
\r
210 while( hid_get_item( d, &h ) )
\r
212 int usage, page, interesting_hid;
\r
214 page = HID_PAGE( h.usage );
\r
215 usage = HID_USAGE( h.usage );
\r
217 /* This test is somewhat too simplistic, but this is how MicroSoft
\r
218 * does, so I guess it works for all joysticks/game pads. */
\r
219 is_joystick = is_joystick ||
\r
220 ( h.kind == hid_collection &&
\r
221 page == HUP_GENERIC_DESKTOP &&
\r
222 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
\r
224 if( h.kind != hid_input )
\r
230 interesting_hid = TRUE;
\r
231 if( page == HUP_GENERIC_DESKTOP )
\r
242 if( *num_axes < _JS_MAX_AXES )
\r
244 os->axes_usage[ *num_axes ] = usage;
\r
248 case HUG_HAT_SWITCH:
\r
249 /* Allocate two axes for a hat */
\r
250 if( *num_axes + 1 < _JS_MAX_AXES )
\r
252 os->axes_usage[ *num_axes ] = usage;
\r
254 os->axes_usage[ *num_axes ] = usage;
\r
259 interesting_hid = FALSE;
\r
263 else if( page == HUP_BUTTON )
\r
265 interesting_hid = ( usage > 0 ) &&
\r
266 ( usage <= _JS_MAX_BUTTONS );
\r
268 if( interesting_hid && usage - 1 > *num_buttons )
\r
269 *num_buttons = usage - 1;
\r
272 if( interesting_hid )
\r
275 os->hids = calloc( 1, sizeof ( struct hid_item ) );
\r
279 hid_end_parse( d );
\r
281 return os->hids != NULL;
\r
287 * Functions associated with the "jsJoystick" class in PLIB
\r
289 #if TARGET_HOST_MAC_OSX
\r
290 #define K_NUM_DEVICES 32
\r
292 io_object_t ioDevices[K_NUM_DEVICES];
\r
294 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
\r
295 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
\r
297 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
\r
298 /* callback for CFArrayApply */
\r
299 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
\r
301 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
\r
302 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
\r
303 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
\r
307 /* External function declarations (mostly platform-specific) */
\r
308 extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
\r
309 extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
\r
310 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
\r
311 extern void fgPlatformJoystickClose ( int ident );
\r
314 * The static joystick structure pointer
\r
316 #define MAX_NUM_JOYSTICKS 2
\r
317 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
320 * Read the raw joystick data
\r
322 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
331 for( i = 0; i < joy->num_axes; i++ )
\r
332 axes[ i ] = 1500.0f;
\r
337 fgPlatformJoystickRawRead ( joy, buttons, axes );
\r
341 * Correct the joystick axis data
\r
343 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
345 if( value < joy->center[ axis ] )
\r
347 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
348 joy->min[ axis ] );
\r
350 if( xx < -joy->saturate[ axis ] )
\r
353 if( xx > -joy->dead_band [ axis ] )
\r
356 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
357 joy->dead_band[ axis ] );
\r
359 return ( xx < -1.0f ) ? -1.0f : xx;
\r
363 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
364 joy->center[ axis ] );
\r
366 if( xx > joy->saturate[ axis ] )
\r
369 if( xx < joy->dead_band[ axis ] )
\r
372 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
373 joy->dead_band[ axis ] );
\r
375 return ( xx > 1.0f ) ? 1.0f : xx;
\r
380 * Read the corrected joystick data
\r
382 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
384 float raw_axes[ _JS_MAX_AXES ];
\r
393 for ( i=0; i<joy->num_axes; i++ )
\r
397 fghJoystickRawRead( joy, buttons, raw_axes );
\r
400 for( i=0; i<joy->num_axes; i++ )
\r
401 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
405 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
409 #if TARGET_HOST_MAC_OSX
\r
410 /** open the IOKit connection, enumerate all the HID devices, add their
\r
411 interface references to the static array. We then use the array index
\r
412 as the device number when we come to open() the joystick. */
\r
413 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
415 CFMutableDictionaryRef hidMatch = NULL;
\r
416 IOReturn rv = kIOReturnSuccess;
\r
418 io_iterator_t hidIterator;
\r
421 /* build a dictionary matching HID devices */
\r
422 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
424 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
425 if (rv != kIOReturnSuccess || !hidIterator) {
\r
426 fgWarning( "no joystick (HID) devices found" );
\r
431 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
432 /* filter out keyboard and mouse devices */
\r
433 CFDictionaryRef properties = getCFProperties(ioDev);
\r
436 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
437 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
438 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
439 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
441 /* keep only joystick devices */
\r
442 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
443 (usage == kHIDUsage_GD_Joystick)
\r
444 || (usage == kHIDUsage_GD_GamePad)
\r
445 || (usage == kHIDUsage_GD_MultiAxisController)
\r
446 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
447 /* add it to the array */
\r
448 ioDevices[numDevices++] = ioDev;
\r
451 IOObjectRelease(hidIterator);
\r
454 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
457 CFMutableDictionaryRef cfProperties;
\r
460 /* comment copied from darwin/SDL_sysjoystick.c */
\r
461 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
462 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
465 io_registry_entry_t parent1, parent2;
\r
467 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
468 if (rv != kIOReturnSuccess) {
\r
469 fgWarning ( "error getting device entry parent");
\r
473 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
474 if (rv != kIOReturnSuccess) {
\r
475 fgWarning ( "error getting device entry parent 2");
\r
480 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
481 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
482 if (rv != kIOReturnSuccess || !cfProperties) {
\r
483 fgWarning ( "error getting device properties");
\r
487 return cfProperties;
\r
490 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
492 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
493 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
497 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
500 /** element enumerator function : pass NULL for top-level*/
\r
501 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
503 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
504 "Joystick element type mismatch",
\r
505 "fghJoystickEnumerateElements" );
\r
507 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
508 CFArrayApplyFunction((CFArrayRef) element, range,
\r
509 &fghJoystickElementEnumerator, joy );
\r
512 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
514 long cookie, lmin, lmax;
\r
515 int index = joy->num_axes++;
\r
517 CFNumberGetValue ((CFNumberRef)
\r
518 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
519 kCFNumberLongType, &cookie);
\r
521 joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;
\r
523 CFNumberGetValue ((CFNumberRef)
\r
524 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
525 kCFNumberLongType, &lmin);
\r
527 CFNumberGetValue ((CFNumberRef)
\r
528 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
529 kCFNumberLongType, &lmax);
\r
531 joy->min[index] = lmin;
\r
532 joy->max[index] = lmax;
\r
533 joy->dead_band[index] = 0.0;
\r
534 joy->saturate[index] = 1.0;
\r
535 joy->center[index] = (lmax + lmin) * 0.5;
\r
538 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
541 CFNumberGetValue ((CFNumberRef)
\r
542 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
543 kCFNumberLongType, &cookie);
\r
545 joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
546 /* anything else for buttons? */
\r
549 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
551 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
552 /* do we map hats to axes or buttons? */
\r
557 * Platform-Specific Code
\r
560 #if TARGET_HOST_MACINTOSH
\r
561 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
569 for ( i = 0; i < joy->num_buttons; i++ )
\r
572 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);
\r
575 *buttons |= state << i;
\r
581 for ( i = 0; i < joy->num_axes; i++ )
\r
584 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );
\r
587 axes [i] = (float) state;
\r
593 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
598 /* XXX FIXME: get joystick name in Mac */
\r
600 err = ISpStartup( );
\r
604 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
606 joy->error = GL_TRUE;
\r
608 /* initialize the needs structure */
\r
609 ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =
\r
611 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
612 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
613 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
614 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
615 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
616 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
617 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
618 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
619 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
621 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
622 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
623 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
624 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
625 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
626 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
627 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
628 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
629 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
630 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
631 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
632 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
633 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
634 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
635 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
636 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
637 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
638 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
639 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
640 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
641 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
642 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
643 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
644 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
645 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
646 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
647 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
648 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
649 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
650 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
651 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
652 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
655 memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
658 /* next two calls allow keyboard and mouse to emulate other input
\r
659 * devices (gamepads, joysticks, etc)
\r
662 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
666 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
670 err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,
\r
671 joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
\r
673 ISP_CHECK_ERR( err )
\r
675 err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
\r
676 'freeglut', nil, 0, 128, 0 );
\r
677 ISP_CHECK_ERR( err )
\r
679 joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;
\r
680 joy->num_axes = ISP_NUM_AXIS;
\r
682 for( i = 0; i < joy->num_axes; i++ )
\r
684 joy->dead_band[ i ] = 0;
\r
685 joy->saturate [ i ] = 1;
\r
686 joy->center [ i ] = kISpAxisMiddle;
\r
687 joy->max [ i ] = kISpAxisMaximum;
\r
688 joy->min [ i ] = kISpAxisMinimum;
\r
691 joy->error = GL_FALSE;
\r
694 joy->num_buttons = joy->num_axes = 0;
\r
698 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
700 fgJoystick[ ident ]->id = ident;
\r
701 snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */
\r
702 fgJoystick[ ident ]->error = GL_FALSE;
\r
706 void fgPlatformJoystickClose ( int ident )
\r
714 #if TARGET_HOST_MAC_OSX
\r
715 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
719 if ( buttons != NULL )
\r
723 for ( i = 0; i < joy->num_buttons; i++ )
\r
725 IOHIDEventStruct hidEvent;
\r
726 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );
\r
727 if ( hidEvent.value )
\r
728 *buttons |= 1 << i;
\r
732 if ( axes != NULL )
\r
734 for ( i = 0; i < joy->num_axes; i++ )
\r
736 IOHIDEventStruct hidEvent;
\r
737 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );
\r
738 axes[i] = hidEvent.value;
\r
744 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
748 IOCFPlugInInterface **plugin;
\r
750 HRESULT pluginResult;
\r
752 CFDictionaryRef props;
\r
753 CFTypeRef topLevelElement;
\r
755 if( joy->id >= numDevices )
\r
757 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
761 /* create device interface */
\r
762 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
763 kIOHIDDeviceUserClientTypeID,
\r
764 kIOCFPlugInInterfaceID,
\r
767 if( rv != kIOReturnSuccess )
\r
769 fgWarning( "error creating plugin for io device" );
\r
773 pluginResult = ( *plugin )->QueryInterface(
\r
775 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
776 &( LPVOID )joy->pJoystick.hidDev
\r
779 if( pluginResult != S_OK )
\r
780 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
782 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
783 if( joy->pJoystick.hidDev == NULL )
\r
786 /* store the interface in this instance */
\r
787 rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );
\r
788 if( rv != kIOReturnSuccess )
\r
790 fgWarning( "error opening device interface");
\r
794 props = getCFProperties( ioDevices[ joy->id ] );
\r
796 /* recursively enumerate all the bits */
\r
797 CFTypeRef topLevelElement =
\r
798 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
799 enumerateElements( topLevelElement );
\r
801 CFRelease( props );
\r
805 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
807 fgJoystick[ ident ]->id = ident;
\r
808 fgJoystick[ ident ]->error = GL_FALSE;
\r
809 fgJoystick[ ident ]->num_axes = 0;
\r
810 fgJoystick[ ident ]->num_buttons = 0;
\r
812 if( numDevices < 0 )
\r
814 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
817 mach_port_t masterPort;
\r
818 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
819 if( rv != kIOReturnSuccess )
\r
821 fgWarning( "error getting master Mach port" );
\r
824 fghJoystickFindDevices( masterPort );
\r
827 if ( ident >= numDevices )
\r
829 fgJoystick[ ident ]->error = GL_TRUE;
\r
833 /* get the name now too */
\r
834 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
835 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
836 CFSTR( kIOHIDProductKey ) );
\r
838 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
841 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
842 CFStringGetSystemEncoding( ) ) )
\r
844 fgWarning( "error getting device name" );
\r
850 void fgPlatformJoystickClose ( int ident )
\r
852 ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->
\r
853 close( fgJoystick[ ident ]->pJoystick.hidDev );
\r
857 #if TARGET_HOST_POSIX_X11
\r
858 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
864 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
867 if ( joy->pJoystick.os->is_analog )
\r
869 int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) );
\r
870 if ( status != sizeof(joy->pJoystick.os->ajs) ) {
\r
871 perror ( joy->pJoystick.os->fname );
\r
872 joy->error = GL_TRUE;
\r
875 if ( buttons != NULL )
\r
876 *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );
\r
878 if ( axes != NULL )
\r
880 axes[0] = (float) joy->pJoystick.os->ajs.x;
\r
881 axes[1] = (float) joy->pJoystick.os->ajs.y;
\r
887 # ifdef HAVE_USB_JS
\r
888 while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen )
\r
890 struct hid_item *h;
\r
892 for ( h = joy->pJoystick.os->hids; h; h = h->next )
\r
894 int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );
\r
896 int page = HID_PAGE ( h->usage );
\r
897 int usage = HID_USAGE ( h->usage );
\r
899 if ( page == HUP_GENERIC_DESKTOP )
\r
902 for ( i = 0; i < joy->num_axes; i++ )
\r
903 if (joy->pJoystick.os->axes_usage[i] == usage)
\r
905 if (usage == HUG_HAT_SWITCH)
\r
907 if (d < 0 || d > 8)
\r
908 d = 0; /* safety */
\r
909 joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d];
\r
910 joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
914 joy->pJoystick.os->cache_axes[i] = (float)d;
\r
919 else if (page == HUP_BUTTON)
\r
921 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
924 joy->pJoystick.os->cache_buttons |= (1 << ( usage - 1 ));
\r
926 joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
931 # ifdef HAVE_ERRNO_H
\r
932 if ( len < 0 && errno != EAGAIN )
\r
937 perror( joy->pJoystick.os->fname );
\r
940 if ( buttons != NULL ) *buttons = joy->pJoystick.os->cache_buttons;
\r
941 if ( axes != NULL )
\r
942 memcpy ( axes, joy->pJoystick.os->cache_axes, sizeof(float) * joy->num_axes );
\r
950 status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) );
\r
952 if ( status != sizeof( struct js_event ) )
\r
954 # ifdef HAVE_ERRNO_H
\r
955 if ( errno == EAGAIN )
\r
957 /* Use the old values */
\r
959 *buttons = joy->pJoystick.tmp_buttons;
\r
961 memcpy( axes, joy->pJoystick.tmp_axes,
\r
962 sizeof( float ) * joy->num_axes );
\r
967 fgWarning ( "%s", joy->pJoystick.fname );
\r
968 joy->error = GL_TRUE;
\r
972 switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT )
\r
974 case JS_EVENT_BUTTON:
\r
975 if( joy->pJoystick.js.value == 0 ) /* clear the flag */
\r
976 joy->pJoystick.tmp_buttons &= ~( 1 << joy->pJoystick.js.number );
\r
978 joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number );
\r
981 case JS_EVENT_AXIS:
\r
982 if ( joy->pJoystick.js.number < joy->num_axes )
\r
984 joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value;
\r
987 memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
\r
992 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
994 /* use the old values */
\r
996 if ( buttons != NULL ) *buttons = joy->pJoystick.tmp_buttons;
\r
997 if ( axes != NULL )
\r
998 memcpy ( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
\r
1004 *buttons = joy->pJoystick.tmp_buttons;
\r
1008 status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN );
\r
1010 if ( status != JS_RETURN )
\r
1012 fgWarning( "%s", joy->pJoystick.fname );
\r
1013 joy->error = GL_TRUE;
\r
1018 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1019 *buttons = ( joy->pJoystick.js.b1 ? 1 : 0 ) | ( joy->pJoystick.js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
1021 *buttons = joy->pJoystick.js.buttons;
\r
1026 axes[ 0 ] = (float) joy->pJoystick.js.x;
\r
1027 axes[ 1 ] = (float) joy->pJoystick.js.y;
\r
1033 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
1035 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1043 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1049 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1050 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1051 joy->pJoystick.os->cache_axes[ i ] = 0.0f;
\r
1053 joy->pJoystick.os->cache_buttons = 0;
\r
1055 joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK);
\r
1057 #ifdef HAVE_ERRNO_H
\r
1058 if( joy->pJoystick.os->fd < 0 && errno == EACCES )
\r
1059 fgWarning ( "%s exists but is not readable by you", joy->pJoystick.os->fname );
\r
1062 joy->error =( joy->pJoystick.os->fd < 0 );
\r
1067 joy->num_axes = 0;
\r
1068 joy->num_buttons = 0;
\r
1069 if( joy->pJoystick.os->is_analog )
\r
1072 char joyfname[ 1024 ];
\r
1073 int noargs, in_no_axes;
\r
1075 float axes [ _JS_MAX_AXES ];
\r
1076 int buttons[ _JS_MAX_AXES ];
\r
1078 joy->num_axes = 2;
\r
1079 joy->num_buttons = 32;
\r
1081 fghJoystickRawRead( joy, buttons, axes );
\r
1082 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1086 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1088 joyfile = fopen( joyfname, "r" );
\r
1089 joy->error =( joyfile == NULL );
\r
1093 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1094 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1095 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1096 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1097 fclose( joyfile );
\r
1101 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1103 joy->dead_band[ i ] = 0.0f;
\r
1104 joy->saturate [ i ] = 1.0f;
\r
1107 return; /* End of analog code */
\r
1110 # ifdef HAVE_USB_JS
\r
1111 if( ! fghJoystickInitializeHID( joy->pJoystick.os, &joy->num_axes,
\r
1112 &joy->num_buttons ) )
\r
1114 close( joy->pJoystick.os->fd );
\r
1115 joy->error = GL_TRUE;
\r
1119 cp = strrchr( joy->pJoystick.os->fname, '/' );
\r
1122 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1124 strcpy( joy->name, &cp[1] );
\r
1127 if( joy->num_axes > _JS_MAX_AXES )
\r
1128 joy->num_axes = _JS_MAX_AXES;
\r
1130 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1132 /* We really should get this from the HID, but that data seems
\r
1133 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1136 if( joy->pJoystick.os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1138 joy->max [ i ] = 1.0f;
\r
1139 joy->center[ i ] = 0.0f;
\r
1140 joy->min [ i ] = -1.0f;
\r
1144 joy->max [ i ] = 255.0f;
\r
1145 joy->center[ i ] = 127.0f;
\r
1146 joy->min [ i ] = 0.0f;
\r
1149 joy->dead_band[ i ] = 0.0f;
\r
1150 joy->saturate[ i ] = 1.0f;
\r
1155 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1156 /* Default for older Linux systems. */
\r
1157 joy->num_axes = 2;
\r
1158 joy->num_buttons = 32;
\r
1161 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1162 joy->pJoystick.tmp_axes[ i ] = 0.0f;
\r
1164 joy->pJoystick.tmp_buttons = 0;
\r
1167 joy->pJoystick.fd = open( joy->pJoystick.fname, O_RDONLY );
\r
1169 joy->error =( joy->pJoystick.fd < 0 );
\r
1174 /* Set the correct number of axes for the linux driver */
\r
1176 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1177 * to the upper byte of an uninitialized word doesn't work.
\r
1180 ioctl( joy->pJoystick.fd, JSIOCGAXES, &u );
\r
1181 joy->num_axes = u;
\r
1182 ioctl( joy->pJoystick.fd, JSIOCGBUTTONS, &u );
\r
1183 joy->num_buttons = u;
\r
1184 ioctl( joy->pJoystick.fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1185 fcntl( joy->pJoystick.fd, F_SETFL, O_NONBLOCK );
\r
1189 * The Linux driver seems to return 512 for all axes
\r
1190 * when no stick is present - but there is a chance
\r
1191 * that could happen by accident - so it's gotta happen
\r
1192 * on both axes for at least 100 attempts.
\r
1194 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1201 fghJoystickRawRead( joy, NULL, joy->center );
\r
1203 } while( !joy->error &&
\r
1205 joy->center[ 0 ] == 512.0f &&
\r
1206 joy->center[ 1 ] == 512.0f );
\r
1208 if ( counter >= 100 )
\r
1209 joy->error = GL_TRUE;
\r
1212 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1215 joy->max [ i ] = 32767.0f;
\r
1216 joy->center[ i ] = 0.0f;
\r
1217 joy->min [ i ] = -32767.0f;
\r
1219 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1220 joy->min[ i ] = 0.0f;
\r
1222 joy->dead_band[ i ] = 0.0f;
\r
1223 joy->saturate [ i ] = 1.0f;
\r
1229 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
1231 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1232 fgJoystick[ ident ]->id = ident;
\r
1233 fgJoystick[ ident ]->error = GL_FALSE;
\r
1235 fgJoystick[ ident ]->pJoystick.os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1236 memset( fgJoystick[ ident ]->pJoystick.os, 0, sizeof( struct os_specific_s ) );
\r
1237 if( ident < USB_IDENT_OFFSET )
\r
1238 fgJoystick[ ident ]->pJoystick.os->is_analog = 1;
\r
1239 if( fgJoystick[ ident ]->pJoystick.os->is_analog )
\r
1240 snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", AJSDEV, ident );
\r
1242 snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", UHIDDEV,
\r
1243 ident - USB_IDENT_OFFSET );
\r
1244 #elif defined( __linux__ )
\r
1245 fgJoystick[ ident ]->id = ident;
\r
1246 fgJoystick[ ident ]->error = GL_FALSE;
\r
1248 snprintf( fgJoystick[ident]->pJoystick.fname, sizeof(fgJoystick[ident]->pJoystick.fname), "/dev/input/js%d", ident );
\r
1250 if( access( fgJoystick[ ident ]->pJoystick.fname, F_OK ) != 0 )
\r
1251 snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident );
\r
1256 void fgPlatformJoystickClose ( int ident )
\r
1258 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1259 if( fgJoystick[ident]->pJoystick.os )
\r
1261 if( ! fgJoystick[ ident ]->error )
\r
1262 close( fgJoystick[ ident ]->pJoystick.os->fd );
\r
1263 #ifdef HAVE_USB_JS
\r
1264 if( fgJoystick[ ident ]->pJoystick.os->hids )
\r
1265 free (fgJoystick[ ident ]->pJoystick.os->hids);
\r
1266 if( fgJoystick[ ident ]->pJoystick.os->hid_data_buf )
\r
1267 free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf );
\r
1269 free( fgJoystick[ident]->pJoystick.os );
\r
1273 if( ! fgJoystick[ident]->error )
\r
1274 close( fgJoystick[ ident ]->pJoystick.fd );
\r
1283 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1286 * Default values (for no joystick -- each conditional will reset the
\r
1289 joy->error = TRUE;
\r
1290 joy->num_axes = joy->num_buttons = 0;
\r
1291 joy->name[ 0 ] = '\0';
\r
1293 fgPlatformJoystickOpen ( joy );
\r
1298 * This function replaces the constructor method in the JS library.
\r
1300 static void fghJoystickInit( int ident )
\r
1302 if( ident >= MAX_NUM_JOYSTICKS )
\r
1303 fgError( "Too large a joystick number: %d", ident );
\r
1305 if( fgJoystick[ ident ] )
\r
1306 fgError( "illegal attempt to initialize joystick device again" );
\r
1308 fgJoystick[ ident ] =
\r
1309 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1311 /* Set defaults */
\r
1312 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1313 fgJoystick[ ident ]->error = GL_TRUE;
\r
1315 fgPlatformJoystickInit( fgJoystick, ident );
\r
1317 fghJoystickOpen( fgJoystick[ ident ] );
\r
1321 * Try initializing all the joysticks (well, both of them)
\r
1323 void fgInitialiseJoysticks ( void )
\r
1325 if( !fgState.JoysticksInitialised )
\r
1328 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1329 fghJoystickInit( ident );
\r
1331 fgState.JoysticksInitialised = GL_TRUE;
\r
1336 void fgJoystickClose( void )
\r
1339 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1341 if( fgJoystick[ ident ] )
\r
1343 fgPlatformJoystickClose ( ident );
\r
1345 free( fgJoystick[ ident ] );
\r
1346 fgJoystick[ ident ] = NULL;
\r
1347 /* show joystick has been deinitialized */
\r
1353 * Polls the joystick and executes the joystick callback hooked to the
\r
1354 * window specified in the function's parameter:
\r
1356 void fgJoystickPollWindow( SFG_Window* window )
\r
1358 float axes[ _JS_MAX_AXES ];
\r
1362 freeglut_return_if_fail( window );
\r
1363 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1365 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1367 if( fgJoystick[ident] )
\r
1369 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1371 if( !fgJoystick[ident]->error )
\r
1372 INVOKE_WCB( *window, Joystick,
\r
1374 (int) ( axes[ 0 ] * 1000.0f ),
\r
1375 (int) ( axes[ 1 ] * 1000.0f ),
\r
1376 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1383 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1385 int fgJoystickDetect( void )
\r
1389 fgInitialiseJoysticks ();
\r
1391 if ( !fgState.JoysticksInitialised )
\r
1394 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1395 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1402 * Joystick information functions
\r
1404 int glutJoystickGetNumAxes( int ident )
\r
1406 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1407 return fgJoystick[ ident ]->num_axes;
\r
1409 int glutJoystickGetNumButtons( int ident )
\r
1411 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1412 return fgJoystick[ ident ]->num_buttons;
\r
1414 int glutJoystickNotWorking( int ident )
\r
1416 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1417 return fgJoystick[ ident ]->error;
\r
1420 float glutJoystickGetDeadBand( int ident, int axis )
\r
1422 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1423 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1425 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1427 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1428 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1431 float glutJoystickGetSaturation( int ident, int axis )
\r
1433 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1434 return fgJoystick[ ident ]->saturate[ axis ];
\r
1436 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1438 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1439 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1442 void glutJoystickSetMinRange( int ident, float *axes )
\r
1444 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1445 memcpy( fgJoystick[ ident ]->min, axes,
\r
1446 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1448 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1450 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1451 memcpy( fgJoystick[ ident ]->max, axes,
\r
1452 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1454 void glutJoystickSetCenter( int ident, float *axes )
\r
1456 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1457 memcpy( fgJoystick[ ident ]->center, axes,
\r
1458 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1461 void glutJoystickGetMinRange( int ident, float *axes )
\r
1463 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1464 memcpy( axes, fgJoystick[ ident ]->min,
\r
1465 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1467 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1469 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1470 memcpy( axes, fgJoystick[ ident ]->max,
\r
1471 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1473 void glutJoystickGetCenter( int ident, float *axes )
\r
1475 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1476 memcpy( axes, fgJoystick[ ident ]->center,
\r
1477 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1480 /*** END OF FILE ***/
\r