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 #include "../include/GL/freeglut.h"
46 #include "freeglut_internal.h"
49 * PWO: I don't like it at all. It's a mess. Could it be cleared?
53 # if defined( __CYGWIN32__ ) || defined( __CYGWIN__ )
57 # include <mmsystem.h>
62 # if defined(__FreeBSD__) || defined(__NetBSD__)
63 # if __FreeBSD_version >= 500000
64 # include <sys/joystick.h>
66 # include <machine/joystick.h>
68 # define JS_DATA_TYPE joystick
69 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
70 # elif defined(__linux__)
71 # include <sys/ioctl.h>
72 # include <linux/joystick.h>
76 * Check the joystick driver version
79 # if JS_VERSION >= 0x010000
87 * Not Windoze and no (known) joystick driver...
89 * Well - we'll put these values in and that should
90 * allow the code to at least compile. The JS open
91 * routine should error out and shut off all the code
101 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
107 # define _JS_MAX_AXES 6
110 # define _JS_MAX_AXES 2
112 # define _JS_MAX_AXES 6
116 typedef struct tagSFG_Joystick SFG_Joystick;
117 struct tagSFG_Joystick
120 * XXX All BSDs might share this?
133 float tmp_axes[ _JS_MAX_AXES ];
135 struct JS_DATA_TYPE js;
146 float dead_band[ _JS_MAX_AXES ];
147 float saturate [ _JS_MAX_AXES ];
148 float center [ _JS_MAX_AXES ];
149 float max [ _JS_MAX_AXES ];
150 float min [ _JS_MAX_AXES ];
154 * The static joystick structure pointer
156 static SFG_Joystick* fgJoystick = NULL;
159 * Read the raw joystick data
161 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
177 for( i=0; i<joy->num_axes; i++ )
184 status = joyGetPosEx( joy->js_id, &joy->js );
186 if( status != JOYERR_NOERROR )
188 joy->error = GL_TRUE;
193 *buttons = joy->js.dwButtons;
198 * WARNING - Fall through case clauses!!
200 switch( joy->num_axes )
202 case 6: axes[5] = (float) joy->js.dwVpos;
203 case 5: axes[4] = (float) joy->js.dwUpos;
204 case 4: axes[3] = (float) joy->js.dwRpos;
205 case 3: axes[2] = (float) joy->js.dwZpos;
206 case 2: axes[1] = (float) joy->js.dwYpos;
207 case 1: axes[0] = (float) joy->js.dwXpos;
215 status = read( joy->fd, &joy->js, sizeof(struct js_event) );
217 if( status != sizeof( struct js_event ) )
219 if( errno == EAGAIN )
225 *buttons = joy->tmp_buttons;
227 memcpy( axes, joy->tmp_axes,
228 sizeof( float ) * joy->num_axes );
232 fgWarning( "%s", joy->fname );
233 joy->error = GL_TRUE;
237 switch( joy->js.type & ~JS_EVENT_INIT )
239 case JS_EVENT_BUTTON:
240 if( joy->js.value == 0 ) /* clear the flag */
241 joy->tmp_buttons &= ~( 1 << joy->js.number );
243 joy->tmp_buttons |= ( 1 << joy->js.number );
247 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
250 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
255 *buttons = joy->tmp_buttons;
259 status = read( joy->fd, &joy->js, JS_RETURN );
261 if( status != JS_RETURN )
263 fgWarning( "%s", joy->fname );
264 joy->error = GL_TRUE;
269 # if defined( __FreeBSD__ ) || defined( __NetBSD__ )
270 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 );
272 *buttons = joy->js.buttons;
277 axes[ 0 ] = (float) joy->js.x;
278 axes[ 1 ] = (float) joy->js.y;
285 * Correct the joystick axis data
287 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
289 if( value < joy->center[ axis ] )
291 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
294 if( xx < -joy->saturate[ axis ] )
297 if( xx > -joy->dead_band [ axis ] )
300 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
301 joy->dead_band[ axis ] );
303 return ( xx < -1.0f ) ? -1.0f : xx;
307 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
308 joy->center[ axis ] );
310 if( xx > joy->saturate[ axis ] )
313 if( xx < joy->dead_band[ axis ] )
316 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
317 joy->dead_band[ axis ] );
319 return ( xx > 1.0f ) ? 1.0f : xx;
324 * Read the corrected joystick data
326 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
328 float raw_axes[ _JS_MAX_AXES ];
337 for ( i=0; i<joy->num_axes ; i++ )
341 fghJoystickRawRead( joy, buttons, raw_axes );
344 for( i=0 ; i<joy->num_axes ; i++ )
345 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
349 * Happy happy happy joy joy joy (happy new year toudi :D)
351 static void fghJoystickOpen( SFG_Joystick* joy )
357 joy->js.dwFlags = JOY_RETURNALL;
358 joy->js.dwSize = sizeof( joy->js );
360 memset( &jsCaps, 0, sizeof( jsCaps ) );
363 ( joyGetDevCaps( joy->js_id, &jsCaps, sizeof( jsCaps ) ) !=
366 ( jsCaps.wNumAxes < _JS_MAX_AXES ) ? jsCaps.wNumAxes : _JS_MAX_AXES;
369 * WARNING - Fall through case clauses!!
371 switch( joy->num_axes )
374 joy->min[ 5 ] = (float) jsCaps.wVmin;
375 joy->max[ 5 ] = (float) jsCaps.wVmax;
377 joy->min[ 4 ] = (float) jsCaps.wUmin;
378 joy->max[ 4 ] = (float) jsCaps.wUmax;
380 joy->min[ 3 ] = (float) jsCaps.wRmin;
381 joy->max[ 3 ] = (float) jsCaps.wRmax;
383 joy->min[ 2 ] = (float) jsCaps.wZmin;
384 joy->max[ 2 ] = (float) jsCaps.wZmax;
386 joy->min[ 1 ] = (float) jsCaps.wYmin;
387 joy->max[ 1 ] = (float) jsCaps.wYmax;
389 joy->min[ 0 ] = (float) jsCaps.wXmin;
390 joy->max[ 0 ] = (float) jsCaps.wXmax;
394 * I guess we have no axes at all
397 joy->error = GL_TRUE;
402 * Guess all the rest judging on the axes extremals
404 for( i=0 ; i<joy->num_axes ; i++ )
406 joy->center [ i ] = (joy->max[i] + joy->min[i]) * 0.5f;
407 joy->dead_band[ i ] = 0.0f;
408 joy->saturate [ i ] = 1.0f;
413 int buttons[ _JS_MAX_AXES ];
414 float axes[ _JS_MAX_AXES ];
415 int noargs, in_no_axes;
416 char joyfname[ 1024 ];
426 * Default for older Linux systems.
429 joy->num_buttons = 32;
432 for( i=0 ; i<_JS_MAX_AXES ; i++ )
433 joy->tmp_axes[ i ] = 0.0f ;
435 joy->tmp_buttons = 0 ;
438 joy->fd = open( joy->fname, O_RDONLY );
440 joy->error = (joy->fd < 0);
445 * XXX All BSDs should share this?
448 fghJoystickRawRead(joy, buttons, axes );
449 joy->error = axes[ 0 ] < -1000000000.0f;
453 sprintf( joyfname, "%s/.joy%drc", getenv( "HOME" ), joy->id );
455 joyfile = fopen( joyfname, "r" );
456 joy->error =( joyfile == NULL );
461 joyfile, "%d%f%f%f%f%f%f",
463 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
464 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ]
467 joy->error =( noargs != 7 ) || ( in_no_axes != _JS_MAX_AXES );
472 for( i = 0; i < _JS_MAX_AXES; i++ )
474 joy->dead_band[ i ] = 0.0f;
475 joy->saturate [ i ] = 1.0f;
480 * Set the correct number of axes for the linux driver
484 ioctl( joy->fd, JSIOCGAXES , &joy->num_axes );
485 ioctl( joy->fd, JSIOCGBUTTONS, &joy->num_buttons );
486 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
491 * The Linux driver seems to return 512 for all axes
492 * when no stick is present - but there is a chance
493 * that could happen by accident - so it's gotta happen
494 * on both axes for at least 100 attempts.
496 * PWO: shouldn't be that done somehow wiser on the kernel level?
503 fghJoystickRawRead( joy, NULL, joy->center );
505 } while( !joy->error &&
507 joy->center[ 0 ] == 512.0f &&
508 joy->center[ 1 ] == 512.0f );
511 joy->error = GL_TRUE;
514 for( i = 0; i < _JS_MAX_AXES; i++ )
517 joy->max [ i ] = 32767.0f;
518 joy->center[ i ] = 0.0f;
519 joy->min [ i ] = -32767.0f;
521 joy->max[ i ] = joy->center[ i ] * 2.0f;
522 joy->min[ i ] = 0.0f;
524 joy->dead_band[ i ] = 0.0f ;
525 joy->saturate [ i ] = 1.0f ;
534 void fgJoystickInit( int ident )
537 fgError( "illegal attemp to initialize joystick device" );
539 fgJoystick = ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
545 fgJoystick->js_id = JOYSTICKID1;
546 fghJoystickOpen( fgJoystick );
549 fgJoystick->js_id = JOYSTICKID2;
550 fghJoystickOpen( fgJoystick );
553 fgJoystick->num_axes = 0;
554 fgJoystick->error = GL_TRUE;
560 * XXX All BSDs should share this code?
563 fgJoystick->id = ident;
564 sprintf( fgJoystick->fname, "/dev/joy%d", ident );
566 sprintf( fgJoystick->fname, "/dev/js%d", ident );
569 fghJoystickOpen( fgJoystick );
576 void fgJoystickClose( void )
579 fgError( "illegal attempt to deinitialize joystick device" );
582 if( ! fgJoystick->error )
583 close( fgJoystick->fd );
587 fgJoystick = NULL; /* show joystick has been deinitialized */
591 * Polls the joystick and executes the joystick callback hooked to the
592 * window specified in the function's parameter:
594 void fgJoystickPollWindow( SFG_Window* window )
596 float axes[ _JS_MAX_AXES ];
599 freeglut_return_if_fail( fgJoystick );
600 freeglut_return_if_fail( window );
601 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
603 fghJoystickRead( fgJoystick, &buttons, axes );
605 INVOKE_WCB( *window, Joystick,
607 (int) (axes[ 0 ] * 1000.0f ),
608 (int) (axes[ 1 ] * 1000.0f ),
609 (int) (axes[ 2 ] * 1000.0f ) )
613 * fgSetWindow (window);
614 * window->Callbacks.Joystick(
616 * (int) (axes[ 0 ] * 1000.0f),
617 * (int) (axes[ 1 ] * 1000.0f),
618 * (int) (axes[ 2 ] * 1000.0f)
624 * PWO: These jsJoystick class methods have not been implemented.
625 * We might consider adding such functions to freeglut-2.0.
633 float getDeadBand ( int axis )
634 { return dead_band [ axis ]; }
635 void setDeadBand ( int axis, float db )
636 { dead_band [ axis ] = db; }
638 float getSaturation ( int axis )
639 { return saturate [ axis ]; }
640 void setSaturation ( int axis, float st )
641 { saturate [ axis ] = st; }
643 void setMinRange ( float *axes )
644 { memcpy ( min , axes, num_axes * sizeof(float) ); }
645 void setMaxRange ( float *axes )
646 { memcpy ( max , axes, num_axes * sizeof(float) ); }
647 void setCenter ( float *axes )
648 { memcpy ( center, axes, num_axes * sizeof(float) ); }
650 void getMinRange ( float *axes )
651 { memcpy ( axes, min , num_axes * sizeof(float) ); }
652 void getMaxRange ( float *axes )
653 { memcpy ( axes, max , num_axes * sizeof(float) ); }
654 void getCenter ( float *axes )
655 { memcpy ( axes, center, num_axes * sizeof(float) ); }
658 /*** END OF FILE ***/