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 * PWO: This is not exactly what Steve Baker has done for PLIB, as I had to
29 * convert it from C++ to C. And I've also reformatted it a bit (that's
30 * my little personal deviation :]) I don't really know if it is still
32 * Steve: could you please add some comments to the code? :)
34 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
37 #if defined(__FreeBSD__) || defined(__NetBSD__)
38 #include <sys/param.h>
45 #define G_LOG_DOMAIN "freeglut-joystick"
47 #include "../include/GL/freeglut.h"
48 #include "freeglut_internal.h"
51 * PWO: I don't like it at all. It's a mess. Could it be cleared?
55 # if defined( __CYGWIN32__ ) || defined( __CYGWIN__ )
59 # include <mmsystem.h>
64 # if defined(__FreeBSD__) || defined(__NetBSD__)
65 # if __FreeBSD_version >= 500000
66 # include <sys/joystick.h>
68 # include <machine/joystick.h>
70 # define JS_DATA_TYPE joystick
71 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
72 # elif defined(__linux__)
73 # include <sys/ioctl.h>
74 # include <linux/joystick.h>
78 * Check the joystick driver version
81 # if JS_VERSION >= 0x010000
89 * Not Windoze and no (known) joystick driver...
91 * Well - we'll put these values in and that should
92 * allow the code to at least compile. The JS open
93 * routine should error out and shut off all the code
103 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
109 # define _JS_MAX_AXES 6
112 # define _JS_MAX_AXES 2
114 # define _JS_MAX_AXES 6
118 typedef struct tagSFG_Joystick SFG_Joystick;
119 struct tagSFG_Joystick
122 * XXX All BSDs might share this?
135 float tmp_axes[ _JS_MAX_AXES ];
137 struct JS_DATA_TYPE js;
148 float dead_band[ _JS_MAX_AXES ];
149 float saturate [ _JS_MAX_AXES ];
150 float center [ _JS_MAX_AXES ];
151 float max [ _JS_MAX_AXES ];
152 float min [ _JS_MAX_AXES ];
156 * The static joystick structure pointer
158 static SFG_Joystick* fgJoystick = NULL;
161 * Read the raw joystick data
163 static void fghJoystickRawRead ( SFG_Joystick* joy, int* buttons, float* axes )
179 for( i=0; i<joy->num_axes; i++ )
186 status = joyGetPosEx( joy->js_id, &joy->js );
188 if( status != JOYERR_NOERROR )
195 *buttons = joy->js.dwButtons;
200 * WARNING - Fall through case clauses!!
202 switch( joy->num_axes )
204 case 6: axes[5] = (float) joy->js.dwVpos;
205 case 5: axes[4] = (float) joy->js.dwUpos;
206 case 4: axes[3] = (float) joy->js.dwRpos;
207 case 3: axes[2] = (float) joy->js.dwZpos;
208 case 2: axes[1] = (float) joy->js.dwYpos;
209 case 1: axes[0] = (float) joy->js.dwXpos;
217 status = read( joy->fd, &joy->js, sizeof(struct js_event) );
219 if( status != sizeof(struct js_event) )
221 if( errno == EAGAIN )
227 *buttons = joy->tmp_buttons;
229 memcpy( axes, joy->tmp_axes,
230 sizeof(float) * joy->num_axes );
234 fgWarning( "%s", joy->fname );
239 switch( joy->js.type & ~JS_EVENT_INIT )
241 case JS_EVENT_BUTTON:
242 if ( joy->js.value == 0 ) /* clear the flag */
243 joy->tmp_buttons &= ~(1 << joy->js.number);
245 joy->tmp_buttons |= (1 << joy->js.number);
249 joy->tmp_axes[ joy->js.number ] = (float) joy->js.value;
252 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
257 *buttons = joy->tmp_buttons;
261 status = read( joy->fd, &joy->js, JS_RETURN );
263 if( status != JS_RETURN )
265 fgWarning( "%s", joy->fname );
271 # if defined(__FreeBSD__) || defined(__NetBSD__)
272 *buttons = (joy->js.b1 ? 1 : 0) | (joy->js.b2 ? 2 : 0);
274 *buttons = joy->js.buttons;
279 axes[ 0 ] = (float) joy->js.x;
280 axes[ 1 ] = (float) joy->js.y;
287 * Correct the joystick axis data
289 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
291 if( value < joy->center[ axis ] )
293 float xx = (value - joy->center[ axis ]) / (joy->center[ axis ] -
296 if( xx < -joy->saturate[ axis ] )
299 if( xx > -joy->dead_band [ axis ] )
302 xx = (xx + joy->dead_band[ axis ]) / (joy->saturate[ axis ] -
303 joy->dead_band[ axis ]);
305 return ( xx < -1.0f ) ? -1.0f : xx;
309 float xx = (value - joy->center [ axis ]) / (joy->max[ axis ] -
310 joy->center[ axis ]);
312 if( xx > joy->saturate[ axis ] )
315 if( xx < joy->dead_band[ axis ] )
318 xx = (xx - joy->dead_band[ axis ]) / (joy->saturate[ axis ] -
319 joy->dead_band[ axis ]);
321 return ( xx > 1.0f ) ? 1.0f : xx;
326 * Read the corrected joystick data
328 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
330 float raw_axes[ _JS_MAX_AXES ];
339 for ( i=0; i<joy->num_axes ; i++ )
343 fghJoystickRawRead( joy, buttons, raw_axes );
346 for( i=0 ; i<joy->num_axes ; i++ )
347 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
351 * Happy happy happy joy joy joy (happy new year toudi :D)
353 static void fghJoystickOpen( SFG_Joystick* joy )
359 joy->js.dwFlags = JOY_RETURNALL;
360 joy->js.dwSize = sizeof( joy->js );
362 memset( &jsCaps, 0, sizeof(jsCaps) );
365 (joyGetDevCaps( joy->js_id, &jsCaps, sizeof(jsCaps) ) !=
368 (jsCaps.wNumAxes < _JS_MAX_AXES ) ? jsCaps.wNumAxes : _JS_MAX_AXES;
371 * WARNING - Fall through case clauses!!
373 switch( joy->num_axes )
376 joy->min[ 5 ] = (float) jsCaps.wVmin;
377 joy->max[ 5 ] = (float) jsCaps.wVmax;
379 joy->min[ 4 ] = (float) jsCaps.wUmin;
380 joy->max[ 4 ] = (float) jsCaps.wUmax;
382 joy->min[ 3 ] = (float) jsCaps.wRmin;
383 joy->max[ 3 ] = (float) jsCaps.wRmax;
385 joy->min[ 2 ] = (float) jsCaps.wZmin;
386 joy->max[ 2 ] = (float) jsCaps.wZmax;
388 joy->min[ 1 ] = (float) jsCaps.wYmin;
389 joy->max[ 1 ] = (float) jsCaps.wYmax;
391 joy->min[ 0 ] = (float) jsCaps.wXmin;
392 joy->max[ 0 ] = (float) jsCaps.wXmax;
396 * I guess we have no axes at all
404 * Guess all the rest judging on the axes extremals
406 for( i=0 ; i<joy->num_axes ; i++ )
408 joy->center [ i ] = (joy->max[i] + joy->min[i]) * 0.5f;
409 joy->dead_band[ i ] = 0.0f;
410 joy->saturate [ i ] = 1.0f;
415 int buttons[ _JS_MAX_AXES ];
416 float axes[ _JS_MAX_AXES ];
417 int noargs, in_no_axes;
418 char joyfname[ 1024 ];
428 * Default for older Linux systems.
431 joy->num_buttons = 32;
434 for( i=0 ; i<_JS_MAX_AXES ; i++ )
435 joy->tmp_axes[ i ] = 0.0f ;
437 joy->tmp_buttons = 0 ;
440 joy->fd = open( joy->fname, O_RDONLY );
442 joy->error = (joy->fd < 0);
447 * XXX All BSDs should share this?
450 fghJoystickRawRead(joy, buttons, axes );
451 joy->error = axes[ 0 ] < -1000000000.0f;
455 sprintf( joyfname, "%s/.joy%drc", getenv( "HOME" ), joy->id );
457 joyfile = fopen( joyfname, "r" );
458 joy->error = (joyfile == NULL);
463 joyfile, "%d%f%f%f%f%f%f",
465 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
466 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ]
469 joy->error = (noargs != 7) || (in_no_axes != _JS_MAX_AXES);
474 for( i=0 ; i<_JS_MAX_AXES ; i++ )
476 joy->dead_band[ i ] = 0.0f;
477 joy->saturate [ i ] = 1.0f;
482 * Set the correct number of axes for the linux driver
486 ioctl( joy->fd, JSIOCGAXES , &joy->num_axes );
487 ioctl( joy->fd, JSIOCGBUTTONS, &joy->num_buttons );
488 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
493 * The Linux driver seems to return 512 for all axes
494 * when no stick is present - but there is a chance
495 * that could happen by accident - so it's gotta happen
496 * on both axes for at least 100 attempts.
498 * PWO: shouldn't be that done somehow wiser on the kernel level?
505 fghJoystickRawRead( joy, NULL, joy->center );
507 } while( !joy->error &&
509 joy->center[ 0 ] == 512.0f &&
510 joy->center[ 1 ] == 512.0f );
516 for( i=0 ; i<_JS_MAX_AXES ; i++ )
519 joy->max [ i ] = 32767.0f;
520 joy->center[ i ] = 0.0f;
521 joy->min [ i ] = -32767.0f;
523 joy->max[ i ] = joy->center[ i ] * 2.0f;
524 joy->min[ i ] = 0.0f;
526 joy->dead_band[ i ] = 0.0f ;
527 joy->saturate [ i ] = 1.0f ;
536 void fgJoystickInit( int ident )
538 if( fgJoystick != NULL )
539 fgError( "illegal attemp to initialize joystick device" );
541 fgJoystick = (SFG_Joystick *)calloc( sizeof(SFG_Joystick), 1 );
547 fgJoystick->js_id = JOYSTICKID1;
548 fghJoystickOpen( fgJoystick );
551 fgJoystick->js_id = JOYSTICKID2;
552 fghJoystickOpen( fgJoystick );
555 fgJoystick->num_axes = 0;
556 fgJoystick->error = TRUE;
562 * XXX All BSDs should share this code?
565 fgJoystick->id = ident;
566 sprintf( fgJoystick->fname, "/dev/joy%d", ident );
568 sprintf( fgJoystick->fname, "/dev/js%d", ident );
571 fghJoystickOpen( fgJoystick );
578 void fgJoystickClose( void )
580 if( fgJoystick == NULL )
581 fgError( "illegal attempt to deinitialize joystick device" );
584 if( fgJoystick->error != TRUE )
585 close( fgJoystick->fd );
588 free ( fgJoystick ) ;
589 fgJoystick = NULL ; /* show joystick has been deinitialized */
593 * Polls the joystick and executes the joystick callback hooked to the
594 * window specified in the function's parameter:
596 void fgJoystickPollWindow( SFG_Window* window )
598 float axes[ _JS_MAX_AXES ];
601 freeglut_return_if_fail( fgJoystick != NULL && window != NULL );
602 freeglut_return_if_fail( window->Callbacks.Joystick != NULL );
604 fghJoystickRead( fgJoystick, &buttons, axes );
606 fgSetWindow (window);
607 window->Callbacks.Joystick(
609 (int) (axes[ 0 ] * 1000.0f),
610 (int) (axes[ 1 ] * 1000.0f),
611 (int) (axes[ 2 ] * 1000.0f)
616 * PWO: These jsJoystick class methods have not been implemented.
617 * We might consider adding such functions to freeglut-2.0.
625 float getDeadBand ( int axis )
626 { return dead_band [ axis ]; }
627 void setDeadBand ( int axis, float db )
628 { dead_band [ axis ] = db; }
630 float getSaturation ( int axis )
631 { return saturate [ axis ]; }
632 void setSaturation ( int axis, float st )
633 { saturate [ axis ] = st; }
635 void setMinRange ( float *axes )
636 { memcpy ( min , axes, num_axes * sizeof(float) ); }
637 void setMaxRange ( float *axes )
638 { memcpy ( max , axes, num_axes * sizeof(float) ); }
639 void setCenter ( float *axes )
640 { memcpy ( center, axes, num_axes * sizeof(float) ); }
642 void getMinRange ( float *axes )
643 { memcpy ( axes, min , num_axes * sizeof(float) ); }
644 void getMaxRange ( float *axes )
645 { memcpy ( axes, max , num_axes * sizeof(float) ); }
646 void getCenter ( float *axes )
647 { memcpy ( axes, center, num_axes * sizeof(float) ); }
650 /*** END OF FILE ***/