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>
44 * Functions associated with the "jsJoystick" class in PLIB
46 #if TARGET_HOST_MAC_OSX
47 #define K_NUM_DEVICES 32
49 io_object_t ioDevices[K_NUM_DEVICES];
51 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
52 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
54 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
55 /* callback for CFArrayApply */
56 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
58 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
59 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
60 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
64 /* External function declarations (mostly platform-specific) */
65 extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
66 extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
67 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
68 extern void fgPlatformJoystickClose ( int ident );
71 * The static joystick structure pointer
73 #define MAX_NUM_JOYSTICKS 2
74 SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
77 * Read the raw joystick data
79 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
88 for( i = 0; i < joy->num_axes; i++ )
94 fgPlatformJoystickRawRead ( joy, buttons, axes );
98 * Correct the joystick axis data
100 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
102 if( value < joy->center[ axis ] )
104 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
107 if( xx < -joy->saturate[ axis ] )
110 if( xx > -joy->dead_band [ axis ] )
113 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
114 joy->dead_band[ axis ] );
116 return ( xx < -1.0f ) ? -1.0f : xx;
120 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
121 joy->center[ axis ] );
123 if( xx > joy->saturate[ axis ] )
126 if( xx < joy->dead_band[ axis ] )
129 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
130 joy->dead_band[ axis ] );
132 return ( xx > 1.0f ) ? 1.0f : xx;
137 * Read the corrected joystick data
139 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
141 float raw_axes[ _JS_MAX_AXES ];
150 for ( i=0; i<joy->num_axes; i++ )
154 fghJoystickRawRead( joy, buttons, raw_axes );
157 for( i=0; i<joy->num_axes; i++ )
158 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
162 * Happy happy happy joy joy joy (happy new year toudi :D)
166 #if TARGET_HOST_MAC_OSX
167 /** open the IOKit connection, enumerate all the HID devices, add their
168 interface references to the static array. We then use the array index
169 as the device number when we come to open() the joystick. */
170 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
172 CFMutableDictionaryRef hidMatch = NULL;
173 IOReturn rv = kIOReturnSuccess;
175 io_iterator_t hidIterator;
178 /* build a dictionary matching HID devices */
179 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
181 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
182 if (rv != kIOReturnSuccess || !hidIterator) {
183 fgWarning( "no joystick (HID) devices found" );
188 while ((ioDev = IOIteratorNext(hidIterator))) {
189 /* filter out keyboard and mouse devices */
190 CFDictionaryRef properties = getCFProperties(ioDev);
193 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
194 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
195 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
196 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
198 /* keep only joystick devices */
199 if ( ( page == kHIDPage_GenericDesktop ) && (
200 (usage == kHIDUsage_GD_Joystick)
201 || (usage == kHIDUsage_GD_GamePad)
202 || (usage == kHIDUsage_GD_MultiAxisController)
203 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
204 /* add it to the array */
205 ioDevices[numDevices++] = ioDev;
208 IOObjectRelease(hidIterator);
211 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
214 CFMutableDictionaryRef cfProperties;
217 /* comment copied from darwin/SDL_sysjoystick.c */
218 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
219 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
222 io_registry_entry_t parent1, parent2;
224 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
225 if (rv != kIOReturnSuccess) {
226 fgWarning ( "error getting device entry parent");
230 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
231 if (rv != kIOReturnSuccess) {
232 fgWarning ( "error getting device entry parent 2");
237 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
238 &cfProperties, kCFAllocatorDefault, kNilOptions);
239 if (rv != kIOReturnSuccess || !cfProperties) {
240 fgWarning ( "error getting device properties");
247 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
249 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
250 fgError ( "%s", "element enumerator passed non-dictionary value");
254 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
257 /** element enumerator function : pass NULL for top-level*/
258 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
260 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
261 "Joystick element type mismatch",
262 "fghJoystickEnumerateElements" );
264 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
265 CFArrayApplyFunction((CFArrayRef) element, range,
266 &fghJoystickElementEnumerator, joy );
269 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
271 long cookie, lmin, lmax;
272 int index = joy->num_axes++;
274 CFNumberGetValue ((CFNumberRef)
275 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
276 kCFNumberLongType, &cookie);
278 joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;
280 CFNumberGetValue ((CFNumberRef)
281 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
282 kCFNumberLongType, &lmin);
284 CFNumberGetValue ((CFNumberRef)
285 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
286 kCFNumberLongType, &lmax);
288 joy->min[index] = lmin;
289 joy->max[index] = lmax;
290 joy->dead_band[index] = 0.0;
291 joy->saturate[index] = 1.0;
292 joy->center[index] = (lmax + lmin) * 0.5;
295 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
298 CFNumberGetValue ((CFNumberRef)
299 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
300 kCFNumberLongType, &cookie);
302 joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
303 /* anything else for buttons? */
306 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
308 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
309 /* do we map hats to axes or buttons? */
314 * Platform-Specific Code
317 #if TARGET_HOST_MACINTOSH
318 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
326 for ( i = 0; i < joy->num_buttons; i++ )
329 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);
332 *buttons |= state << i;
338 for ( i = 0; i < joy->num_axes; i++ )
341 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );
344 axes [i] = (float) state;
350 void fgPlatformJoystickOpen( SFG_Joystick* joy )
355 /* XXX FIXME: get joystick name in Mac */
361 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
363 joy->error = GL_TRUE;
365 /* initialize the needs structure */
366 ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =
368 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
369 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
370 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
371 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
372 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
373 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
374 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
375 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
376 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
378 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
379 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
380 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
381 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
382 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
383 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
384 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
385 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
386 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
387 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
388 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
389 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
390 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
391 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
392 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
393 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
394 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
395 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
396 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
397 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
398 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
399 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
400 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
401 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
402 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
403 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
404 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
405 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
406 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
407 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
408 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
409 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
412 memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
415 /* next two calls allow keyboard and mouse to emulate other input
416 * devices (gamepads, joysticks, etc)
419 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
423 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
427 err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,
428 joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
432 err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
433 'freeglut', nil, 0, 128, 0 );
436 joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;
437 joy->num_axes = ISP_NUM_AXIS;
439 for( i = 0; i < joy->num_axes; i++ )
441 joy->dead_band[ i ] = 0;
442 joy->saturate [ i ] = 1;
443 joy->center [ i ] = kISpAxisMiddle;
444 joy->max [ i ] = kISpAxisMaximum;
445 joy->min [ i ] = kISpAxisMinimum;
448 joy->error = GL_FALSE;
451 joy->num_buttons = joy->num_axes = 0;
455 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
457 fgJoystick[ ident ]->id = ident;
458 snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */
459 fgJoystick[ ident ]->error = GL_FALSE;
463 void fgPlatformJoystickClose ( int ident )
471 #if TARGET_HOST_MAC_OSX
472 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
476 if ( buttons != NULL )
480 for ( i = 0; i < joy->num_buttons; i++ )
482 IOHIDEventStruct hidEvent;
483 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );
484 if ( hidEvent.value )
491 for ( i = 0; i < joy->num_axes; i++ )
493 IOHIDEventStruct hidEvent;
494 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );
495 axes[i] = hidEvent.value;
501 void fgPlatformJoystickOpen( SFG_Joystick* joy )
505 IOCFPlugInInterface **plugin;
507 HRESULT pluginResult;
509 CFDictionaryRef props;
510 CFTypeRef topLevelElement;
512 if( joy->id >= numDevices )
514 fgWarning( "device index out of range in fgJoystickOpen()" );
518 /* create device interface */
519 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
520 kIOHIDDeviceUserClientTypeID,
521 kIOCFPlugInInterfaceID,
524 if( rv != kIOReturnSuccess )
526 fgWarning( "error creating plugin for io device" );
530 pluginResult = ( *plugin )->QueryInterface(
532 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
533 &( LPVOID )joy->pJoystick.hidDev
536 if( pluginResult != S_OK )
537 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
539 ( *plugin )->Release( plugin ); /* don't leak a ref */
540 if( joy->pJoystick.hidDev == NULL )
543 /* store the interface in this instance */
544 rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );
545 if( rv != kIOReturnSuccess )
547 fgWarning( "error opening device interface");
551 props = getCFProperties( ioDevices[ joy->id ] );
553 /* recursively enumerate all the bits */
554 CFTypeRef topLevelElement =
555 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
556 enumerateElements( topLevelElement );
562 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
564 fgJoystick[ ident ]->id = ident;
565 fgJoystick[ ident ]->error = GL_FALSE;
566 fgJoystick[ ident ]->num_axes = 0;
567 fgJoystick[ ident ]->num_buttons = 0;
571 /* do first-time init (since we can't over-ride jsInit, hmm */
574 mach_port_t masterPort;
575 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
576 if( rv != kIOReturnSuccess )
578 fgWarning( "error getting master Mach port" );
581 fghJoystickFindDevices( masterPort );
584 if ( ident >= numDevices )
586 fgJoystick[ ident ]->error = GL_TRUE;
590 /* get the name now too */
591 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
592 CFTypeRef ref = CFDictionaryGetValue( properties,
593 CFSTR( kIOHIDProductKey ) );
595 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
598 !CFStringGetCString( ( CFStringRef )ref, name, 128,
599 CFStringGetSystemEncoding( ) ) )
601 fgWarning( "error getting device name" );
607 void fgPlatformJoystickClose ( int ident )
609 ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->
610 close( fgJoystick[ ident ]->pJoystick.hidDev );
617 static void fghJoystickOpen( SFG_Joystick* joy )
620 * Default values (for no joystick -- each conditional will reset the
624 joy->num_axes = joy->num_buttons = 0;
625 joy->name[ 0 ] = '\0';
627 fgPlatformJoystickOpen ( joy );
632 * This function replaces the constructor method in the JS library.
634 static void fghJoystickInit( int ident )
636 if( ident >= MAX_NUM_JOYSTICKS )
637 fgError( "Too large a joystick number: %d", ident );
639 if( fgJoystick[ ident ] )
640 fgError( "illegal attempt to initialize joystick device again" );
642 fgJoystick[ ident ] =
643 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
646 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
647 fgJoystick[ ident ]->error = GL_TRUE;
649 fgPlatformJoystickInit( fgJoystick, ident );
651 fghJoystickOpen( fgJoystick[ ident ] );
655 * Try initializing all the joysticks (well, both of them)
657 void fgInitialiseJoysticks ( void )
659 if( !fgState.JoysticksInitialised )
662 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
663 fghJoystickInit( ident );
665 fgState.JoysticksInitialised = GL_TRUE;
670 void fgJoystickClose( void )
673 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
675 if( fgJoystick[ ident ] )
677 fgPlatformJoystickClose ( ident );
679 free( fgJoystick[ ident ] );
680 fgJoystick[ ident ] = NULL;
681 /* show joystick has been deinitialized */
687 * Polls the joystick and executes the joystick callback hooked to the
688 * window specified in the function's parameter:
690 void fgJoystickPollWindow( SFG_Window* window )
692 float axes[ _JS_MAX_AXES ];
696 freeglut_return_if_fail( window );
697 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
699 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
701 if( fgJoystick[ident] )
703 fghJoystickRead( fgJoystick[ident], &buttons, axes );
705 if( !fgJoystick[ident]->error )
706 INVOKE_WCB( *window, Joystick,
708 (int) ( axes[ 0 ] * 1000.0f ),
709 (int) ( axes[ 1 ] * 1000.0f ),
710 (int) ( axes[ 2 ] * 1000.0f ) )
717 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
719 int fgJoystickDetect( void )
723 fgInitialiseJoysticks ();
725 if ( !fgState.JoysticksInitialised )
728 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
729 if( fgJoystick[ident] && !fgJoystick[ident]->error )
736 * Joystick information, setup and execution functions
740 * Forces the joystick callback to be executed
742 void FGAPIENTRY glutForceJoystickFunc( void )
744 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutForceJoystickFunc" );
745 #if !defined(_WIN32_WCE)
746 freeglut_return_if_fail( fgStructure.CurrentWindow != NULL );
747 freeglut_return_if_fail( FETCH_WCB( *( fgStructure.CurrentWindow ), Joystick ) );
748 fgJoystickPollWindow( fgStructure.CurrentWindow );
749 #endif /* !defined(_WIN32_WCE) */
751 int glutJoystickGetNumAxes( int ident )
753 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
754 return fgJoystick[ ident ]->num_axes;
756 int glutJoystickGetNumButtons( int ident )
758 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
759 return fgJoystick[ ident ]->num_buttons;
761 int glutJoystickNotWorking( int ident )
763 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
764 return fgJoystick[ ident ]->error;
767 float glutJoystickGetDeadBand( int ident, int axis )
769 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
770 return fgJoystick[ ident ]->dead_band [ axis ];
772 void glutJoystickSetDeadBand( int ident, int axis, float db )
774 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
775 fgJoystick[ ident ]->dead_band[ axis ] = db;
778 float glutJoystickGetSaturation( int ident, int axis )
780 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
781 return fgJoystick[ ident ]->saturate[ axis ];
783 void glutJoystickSetSaturation( int ident, int axis, float st )
785 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
786 fgJoystick[ ident ]->saturate [ axis ] = st;
789 void glutJoystickSetMinRange( int ident, float *axes )
791 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
792 memcpy( fgJoystick[ ident ]->min, axes,
793 fgJoystick[ ident ]->num_axes * sizeof( float ) );
795 void glutJoystickSetMaxRange( int ident, float *axes )
797 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
798 memcpy( fgJoystick[ ident ]->max, axes,
799 fgJoystick[ ident ]->num_axes * sizeof( float ) );
801 void glutJoystickSetCenter( int ident, float *axes )
803 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
804 memcpy( fgJoystick[ ident ]->center, axes,
805 fgJoystick[ ident ]->num_axes * sizeof( float ) );
808 void glutJoystickGetMinRange( int ident, float *axes )
810 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
811 memcpy( axes, fgJoystick[ ident ]->min,
812 fgJoystick[ ident ]->num_axes * sizeof( float ) );
814 void glutJoystickGetMaxRange( int ident, float *axes )
816 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
817 memcpy( axes, fgJoystick[ ident ]->max,
818 fgJoystick[ ident ]->num_axes * sizeof( float ) );
820 void glutJoystickGetCenter( int ident, float *axes )
822 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
823 memcpy( axes, fgJoystick[ ident ]->center,
824 fgJoystick[ ident ]->num_axes * sizeof( float ) );
827 /*** END OF FILE ***/