4 * Joystick handling code
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Steve Baker, <sjbaker1@airmail.net>
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
30 * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
31 * Many thanks for Steve Baker for permission to pull from that library.
34 #include <GL/freeglut.h>
35 #include "fg_internal.h"
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
43 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
45 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
48 # if defined(__NetBSD__)
54 # include <dev/usb/usb.h>
55 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
59 # include <libusbhid.h>
61 # include <legacy/dev/usb/usb.h>
63 # include <dev/usb/usbhid.h>
65 /* Compatibility with older usb.h revisions */
66 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
67 # define USB_MAX_DEVNAMES MAXDEVNAMES
71 struct os_specific_s {
75 /* The following structure members are specific to analog joysticks */
78 /* The following structure members are specific to USB joysticks */
79 struct hid_item *hids;
83 int axes_usage [ _JS_MAX_AXES ];
85 /* We keep button and axes state ourselves, as they might not be updated
86 * on every read of a USB device
89 float cache_axes [ _JS_MAX_AXES ];
92 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
93 # define USB_IDENT_OFFSET 2
95 # define USBDEV "/dev/usb"
96 # define UHIDDEV "/dev/uhid"
97 # define AJSDEV "/dev/joy"
103 * Functions associated with the "jsJoystick" class in PLIB
105 #if TARGET_HOST_MAC_OSX
106 #define K_NUM_DEVICES 32
108 io_object_t ioDevices[K_NUM_DEVICES];
110 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
111 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
113 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
114 /* callback for CFArrayApply */
115 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
117 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
118 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
119 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
123 /* External function declarations (mostly platform-specific) */
124 extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
125 extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
126 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
127 extern void fgPlatformJoystickClose ( int ident );
130 * The static joystick structure pointer
132 #define MAX_NUM_JOYSTICKS 2
133 SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
136 * Read the raw joystick data
138 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
147 for( i = 0; i < joy->num_axes; i++ )
153 fgPlatformJoystickRawRead ( joy, buttons, axes );
157 * Correct the joystick axis data
159 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
161 if( value < joy->center[ axis ] )
163 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
166 if( xx < -joy->saturate[ axis ] )
169 if( xx > -joy->dead_band [ axis ] )
172 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
173 joy->dead_band[ axis ] );
175 return ( xx < -1.0f ) ? -1.0f : xx;
179 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
180 joy->center[ axis ] );
182 if( xx > joy->saturate[ axis ] )
185 if( xx < joy->dead_band[ axis ] )
188 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
189 joy->dead_band[ axis ] );
191 return ( xx > 1.0f ) ? 1.0f : xx;
196 * Read the corrected joystick data
198 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
200 float raw_axes[ _JS_MAX_AXES ];
209 for ( i=0; i<joy->num_axes; i++ )
213 fghJoystickRawRead( joy, buttons, raw_axes );
216 for( i=0; i<joy->num_axes; i++ )
217 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
221 * Happy happy happy joy joy joy (happy new year toudi :D)
225 #if TARGET_HOST_MAC_OSX
226 /** open the IOKit connection, enumerate all the HID devices, add their
227 interface references to the static array. We then use the array index
228 as the device number when we come to open() the joystick. */
229 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
231 CFMutableDictionaryRef hidMatch = NULL;
232 IOReturn rv = kIOReturnSuccess;
234 io_iterator_t hidIterator;
237 /* build a dictionary matching HID devices */
238 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
240 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
241 if (rv != kIOReturnSuccess || !hidIterator) {
242 fgWarning( "no joystick (HID) devices found" );
247 while ((ioDev = IOIteratorNext(hidIterator))) {
248 /* filter out keyboard and mouse devices */
249 CFDictionaryRef properties = getCFProperties(ioDev);
252 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
253 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
254 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
255 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
257 /* keep only joystick devices */
258 if ( ( page == kHIDPage_GenericDesktop ) && (
259 (usage == kHIDUsage_GD_Joystick)
260 || (usage == kHIDUsage_GD_GamePad)
261 || (usage == kHIDUsage_GD_MultiAxisController)
262 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
263 /* add it to the array */
264 ioDevices[numDevices++] = ioDev;
267 IOObjectRelease(hidIterator);
270 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
273 CFMutableDictionaryRef cfProperties;
276 /* comment copied from darwin/SDL_sysjoystick.c */
277 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
278 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
281 io_registry_entry_t parent1, parent2;
283 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
284 if (rv != kIOReturnSuccess) {
285 fgWarning ( "error getting device entry parent");
289 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
290 if (rv != kIOReturnSuccess) {
291 fgWarning ( "error getting device entry parent 2");
296 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
297 &cfProperties, kCFAllocatorDefault, kNilOptions);
298 if (rv != kIOReturnSuccess || !cfProperties) {
299 fgWarning ( "error getting device properties");
306 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
308 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
309 fgError ( "%s", "element enumerator passed non-dictionary value");
313 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
316 /** element enumerator function : pass NULL for top-level*/
317 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
319 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
320 "Joystick element type mismatch",
321 "fghJoystickEnumerateElements" );
323 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
324 CFArrayApplyFunction((CFArrayRef) element, range,
325 &fghJoystickElementEnumerator, joy );
328 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
330 long cookie, lmin, lmax;
331 int index = joy->num_axes++;
333 CFNumberGetValue ((CFNumberRef)
334 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
335 kCFNumberLongType, &cookie);
337 joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;
339 CFNumberGetValue ((CFNumberRef)
340 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
341 kCFNumberLongType, &lmin);
343 CFNumberGetValue ((CFNumberRef)
344 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
345 kCFNumberLongType, &lmax);
347 joy->min[index] = lmin;
348 joy->max[index] = lmax;
349 joy->dead_band[index] = 0.0;
350 joy->saturate[index] = 1.0;
351 joy->center[index] = (lmax + lmin) * 0.5;
354 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
357 CFNumberGetValue ((CFNumberRef)
358 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
359 kCFNumberLongType, &cookie);
361 joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
362 /* anything else for buttons? */
365 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
367 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
368 /* do we map hats to axes or buttons? */
373 * Platform-Specific Code
376 #if TARGET_HOST_MACINTOSH
377 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
385 for ( i = 0; i < joy->num_buttons; i++ )
388 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);
391 *buttons |= state << i;
397 for ( i = 0; i < joy->num_axes; i++ )
400 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );
403 axes [i] = (float) state;
409 void fgPlatformJoystickOpen( SFG_Joystick* joy )
414 /* XXX FIXME: get joystick name in Mac */
420 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
422 joy->error = GL_TRUE;
424 /* initialize the needs structure */
425 ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =
427 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
428 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
429 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
430 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
431 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
432 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
433 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
434 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
435 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
437 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
438 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
439 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
440 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
441 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
442 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
443 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
444 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
445 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
446 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
447 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
448 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
449 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
450 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
451 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
452 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
453 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
454 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
455 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
456 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
457 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
458 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
459 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
460 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
461 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
462 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
463 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
464 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
465 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
466 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
467 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
468 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
471 memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
474 /* next two calls allow keyboard and mouse to emulate other input
475 * devices (gamepads, joysticks, etc)
478 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
482 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
486 err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,
487 joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
491 err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
492 'freeglut', nil, 0, 128, 0 );
495 joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;
496 joy->num_axes = ISP_NUM_AXIS;
498 for( i = 0; i < joy->num_axes; i++ )
500 joy->dead_band[ i ] = 0;
501 joy->saturate [ i ] = 1;
502 joy->center [ i ] = kISpAxisMiddle;
503 joy->max [ i ] = kISpAxisMaximum;
504 joy->min [ i ] = kISpAxisMinimum;
507 joy->error = GL_FALSE;
510 joy->num_buttons = joy->num_axes = 0;
514 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
516 fgJoystick[ ident ]->id = ident;
517 snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */
518 fgJoystick[ ident ]->error = GL_FALSE;
522 void fgPlatformJoystickClose ( int ident )
530 #if TARGET_HOST_MAC_OSX
531 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
535 if ( buttons != NULL )
539 for ( i = 0; i < joy->num_buttons; i++ )
541 IOHIDEventStruct hidEvent;
542 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );
543 if ( hidEvent.value )
550 for ( i = 0; i < joy->num_axes; i++ )
552 IOHIDEventStruct hidEvent;
553 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );
554 axes[i] = hidEvent.value;
560 void fgPlatformJoystickOpen( SFG_Joystick* joy )
564 IOCFPlugInInterface **plugin;
566 HRESULT pluginResult;
568 CFDictionaryRef props;
569 CFTypeRef topLevelElement;
571 if( joy->id >= numDevices )
573 fgWarning( "device index out of range in fgJoystickOpen()" );
577 /* create device interface */
578 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
579 kIOHIDDeviceUserClientTypeID,
580 kIOCFPlugInInterfaceID,
583 if( rv != kIOReturnSuccess )
585 fgWarning( "error creating plugin for io device" );
589 pluginResult = ( *plugin )->QueryInterface(
591 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
592 &( LPVOID )joy->pJoystick.hidDev
595 if( pluginResult != S_OK )
596 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
598 ( *plugin )->Release( plugin ); /* don't leak a ref */
599 if( joy->pJoystick.hidDev == NULL )
602 /* store the interface in this instance */
603 rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );
604 if( rv != kIOReturnSuccess )
606 fgWarning( "error opening device interface");
610 props = getCFProperties( ioDevices[ joy->id ] );
612 /* recursively enumerate all the bits */
613 CFTypeRef topLevelElement =
614 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
615 enumerateElements( topLevelElement );
621 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
623 fgJoystick[ ident ]->id = ident;
624 fgJoystick[ ident ]->error = GL_FALSE;
625 fgJoystick[ ident ]->num_axes = 0;
626 fgJoystick[ ident ]->num_buttons = 0;
630 /* do first-time init (since we can't over-ride jsInit, hmm */
633 mach_port_t masterPort;
634 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
635 if( rv != kIOReturnSuccess )
637 fgWarning( "error getting master Mach port" );
640 fghJoystickFindDevices( masterPort );
643 if ( ident >= numDevices )
645 fgJoystick[ ident ]->error = GL_TRUE;
649 /* get the name now too */
650 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
651 CFTypeRef ref = CFDictionaryGetValue( properties,
652 CFSTR( kIOHIDProductKey ) );
654 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
657 !CFStringGetCString( ( CFStringRef )ref, name, 128,
658 CFStringGetSystemEncoding( ) ) )
660 fgWarning( "error getting device name" );
666 void fgPlatformJoystickClose ( int ident )
668 ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->
669 close( fgJoystick[ ident ]->pJoystick.hidDev );
676 static void fghJoystickOpen( SFG_Joystick* joy )
679 * Default values (for no joystick -- each conditional will reset the
683 joy->num_axes = joy->num_buttons = 0;
684 joy->name[ 0 ] = '\0';
686 fgPlatformJoystickOpen ( joy );
691 * This function replaces the constructor method in the JS library.
693 static void fghJoystickInit( int ident )
695 if( ident >= MAX_NUM_JOYSTICKS )
696 fgError( "Too large a joystick number: %d", ident );
698 if( fgJoystick[ ident ] )
699 fgError( "illegal attempt to initialize joystick device again" );
701 fgJoystick[ ident ] =
702 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
705 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
706 fgJoystick[ ident ]->error = GL_TRUE;
708 fgPlatformJoystickInit( fgJoystick, ident );
710 fghJoystickOpen( fgJoystick[ ident ] );
714 * Try initializing all the joysticks (well, both of them)
716 void fgInitialiseJoysticks ( void )
718 if( !fgState.JoysticksInitialised )
721 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
722 fghJoystickInit( ident );
724 fgState.JoysticksInitialised = GL_TRUE;
729 void fgJoystickClose( void )
732 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
734 if( fgJoystick[ ident ] )
736 fgPlatformJoystickClose ( ident );
738 free( fgJoystick[ ident ] );
739 fgJoystick[ ident ] = NULL;
740 /* show joystick has been deinitialized */
746 * Polls the joystick and executes the joystick callback hooked to the
747 * window specified in the function's parameter:
749 void fgJoystickPollWindow( SFG_Window* window )
751 float axes[ _JS_MAX_AXES ];
755 freeglut_return_if_fail( window );
756 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
758 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
760 if( fgJoystick[ident] )
762 fghJoystickRead( fgJoystick[ident], &buttons, axes );
764 if( !fgJoystick[ident]->error )
765 INVOKE_WCB( *window, Joystick,
767 (int) ( axes[ 0 ] * 1000.0f ),
768 (int) ( axes[ 1 ] * 1000.0f ),
769 (int) ( axes[ 2 ] * 1000.0f ) )
776 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
778 int fgJoystickDetect( void )
782 fgInitialiseJoysticks ();
784 if ( !fgState.JoysticksInitialised )
787 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
788 if( fgJoystick[ident] && !fgJoystick[ident]->error )
795 * Joystick information, setup and execution functions
799 * Forces the joystick callback to be executed
801 void FGAPIENTRY glutForceJoystickFunc( void )
803 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutForceJoystickFunc" );
804 #if !defined(_WIN32_WCE)
805 freeglut_return_if_fail( fgStructure.CurrentWindow != NULL );
806 freeglut_return_if_fail( FETCH_WCB( *( fgStructure.CurrentWindow ), Joystick ) );
807 fgJoystickPollWindow( fgStructure.CurrentWindow );
808 #endif /* !defined(_WIN32_WCE) */
810 int glutJoystickGetNumAxes( int ident )
812 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
813 return fgJoystick[ ident ]->num_axes;
815 int glutJoystickGetNumButtons( int ident )
817 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
818 return fgJoystick[ ident ]->num_buttons;
820 int glutJoystickNotWorking( int ident )
822 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
823 return fgJoystick[ ident ]->error;
826 float glutJoystickGetDeadBand( int ident, int axis )
828 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
829 return fgJoystick[ ident ]->dead_band [ axis ];
831 void glutJoystickSetDeadBand( int ident, int axis, float db )
833 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
834 fgJoystick[ ident ]->dead_band[ axis ] = db;
837 float glutJoystickGetSaturation( int ident, int axis )
839 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
840 return fgJoystick[ ident ]->saturate[ axis ];
842 void glutJoystickSetSaturation( int ident, int axis, float st )
844 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
845 fgJoystick[ ident ]->saturate [ axis ] = st;
848 void glutJoystickSetMinRange( int ident, float *axes )
850 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
851 memcpy( fgJoystick[ ident ]->min, axes,
852 fgJoystick[ ident ]->num_axes * sizeof( float ) );
854 void glutJoystickSetMaxRange( int ident, float *axes )
856 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
857 memcpy( fgJoystick[ ident ]->max, axes,
858 fgJoystick[ ident ]->num_axes * sizeof( float ) );
860 void glutJoystickSetCenter( int ident, float *axes )
862 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
863 memcpy( fgJoystick[ ident ]->center, axes,
864 fgJoystick[ ident ]->num_axes * sizeof( float ) );
867 void glutJoystickGetMinRange( int ident, float *axes )
869 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
870 memcpy( axes, fgJoystick[ ident ]->min,
871 fgJoystick[ ident ]->num_axes * sizeof( float ) );
873 void glutJoystickGetMaxRange( int ident, float *axes )
875 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
876 memcpy( axes, fgJoystick[ ident ]->max,
877 fgJoystick[ ident ]->num_axes * sizeof( float ) );
879 void glutJoystickGetCenter( int ident, float *axes )
881 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
882 memcpy( axes, fgJoystick[ ident ]->center,
883 fgJoystick[ ident ]->num_axes * sizeof( float ) );
886 /*** END OF FILE ***/