Added Thierry's change to include sys/param.h. This lets us pick out version
[freeglut] / src / freeglut_joystick.c
1 /*
2  * freeglut_joystick.c
3  *
4  * Joystick handling code
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Steve Baker, <sjbaker1@airmail.net>
8  *
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:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
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.
25  */
26
27 /*
28  * PWO: this is not exactly what Steve Baker has done for PLIB, as I had to convert
29  *      it from C++ to C. And I've also reformatted it a bit (that's my little
30  *      personal deviation :]) I don't really know if it is still portable...
31  *      Steve: could you please add some comments to the code? :)
32  *
33  * FreeBSD port - courtesy of Stephen Montgomery-Smith <stephen@math.missouri.edu>
34  */
35
36 #if defined(__FreeBSD__) || defined(__NetBSD__)
37 #include <sys/param.h>
38 #endif
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #define G_LOG_DOMAIN "freeglut-joystick"
45
46 #include "../include/GL/freeglut.h"
47 #include "freeglut_internal.h"
48
49 /*
50  * PWO: I don't like it at all. It's a mess. Could it be cleared?
51  */
52 #ifdef WIN32
53 #   include <windows.h>
54 #   if defined( __CYGWIN32__ ) || defined( __CYGWIN__ )
55 #       define NEAR /* */
56 #       define FAR  /* */
57 #   endif
58 #   include <mmsystem.h>
59 #   include <string.h>
60 #else
61 #   include <unistd.h>
62 #   include <fcntl.h>
63 #   if defined(__FreeBSD__) || defined(__NetBSD__)
64 #   if __FreeBSD_version >= 500000
65 #       include <sys/joystick.h>
66 #   else
67 #       include <machine/joystick.h>
68 #   endif
69 #       define JS_DATA_TYPE joystick
70 #       define JS_RETURN (sizeof(struct JS_DATA_TYPE))
71 #   elif defined(__linux__)
72 #       include <sys/ioctl.h>
73 #       include <linux/joystick.h>
74 #       include <errno.h>
75
76         /*
77          * Check the joystick driver version
78          */
79 #       ifdef JS_VERSION
80 #           if JS_VERSION >= 0x010000
81 #               define JS_NEW
82 #           endif
83 #       endif
84 #   else
85 #       ifndef JS_DATA_TYPE
86
87             /*
88              * Not Windoze and no joystick driver...
89              *
90              * Well - we'll put these values in and that should
91              * allow the code to at least compile. The JS open
92              * routine should error out and shut off all the code
93              * downstream anyway
94              */
95             struct JS_DATA_TYPE
96             {
97                 int buttons;
98                 int x;
99                 int y;
100             };
101
102 #           define JS_RETURN (sizeof(struct JS_DATA_TYPE))
103 #       endif
104 #   endif
105 #endif
106
107 #ifdef WIN32
108 #   define _JS_MAX_AXES 6
109 #else
110 #   ifdef __FreeBSD__
111 #       define _JS_MAX_AXES 2
112 #   else
113 #       define _JS_MAX_AXES 6
114 #   endif
115 #endif
116
117 typedef struct tagSFG_Joystick SFG_Joystick;
118 struct tagSFG_Joystick
119 {
120 #ifdef __FreeBSD__
121     int         id;
122 #endif
123
124 #ifdef WIN32
125     JOYINFOEX   js;
126     UINT        js_id;
127 #else
128 #   ifdef JS_NEW
129         struct js_event js;
130         int         tmp_buttons;
131         float       tmp_axes[ _JS_MAX_AXES ];
132 #   else
133         struct JS_DATA_TYPE js;
134 #   endif
135
136     char fname[ 128 ];
137     int  fd;
138 #endif
139
140     GLboolean error;
141     int       num_axes;
142     int       num_buttons;
143
144     float dead_band[ _JS_MAX_AXES ];
145     float saturate [ _JS_MAX_AXES ];
146     float center   [ _JS_MAX_AXES ];
147     float max      [ _JS_MAX_AXES ];
148     float min      [ _JS_MAX_AXES ];
149 };
150
151 /*
152  * The static joystick structure pointer
153  */
154 static SFG_Joystick* fgJoystick = NULL;
155
156 /*
157  * Read the raw joystick data
158  */
159 static void fghJoystickRawRead ( SFG_Joystick* joy, int* buttons, float* axes )
160 {
161 #ifdef WIN32
162     MMRESULT status;
163 #else
164     int status;
165 #endif
166
167     int i;
168
169     if( joy->error )
170     {
171         if( buttons )
172             *buttons = 0 ;
173
174         if( axes )
175             for( i=0; i<joy->num_axes; i++ )
176                 axes[ i ] = 1500.0f;
177
178         return;
179     }
180
181 #ifdef WIN32
182     status = joyGetPosEx( joy->js_id, &joy->js );
183
184     if( status != JOYERR_NOERROR )
185     {
186         joy->error = TRUE;
187         return;
188     }
189
190     if( buttons )
191         *buttons = joy->js.dwButtons;
192
193     if( axes )
194     {
195         /*
196          * WARNING - Fall through case clauses!!
197          */
198         switch( joy->num_axes )
199         {
200             case 6: axes[5] = (float) joy->js.dwVpos;
201             case 5: axes[4] = (float) joy->js.dwUpos;
202             case 4: axes[3] = (float) joy->js.dwRpos;
203             case 3: axes[2] = (float) joy->js.dwZpos;
204             case 2: axes[1] = (float) joy->js.dwYpos;
205             case 1: axes[0] = (float) joy->js.dwXpos;
206         }
207     }
208 #else
209 #   ifdef JS_NEW
210
211     while( 1 )
212     {
213         status = read( joy->fd, &joy->js, sizeof(struct js_event) );
214
215         if( status != sizeof(struct js_event) )
216         {
217                 if( errno == EAGAIN )
218                 {
219                     /*
220                      * Use the old values
221                      */
222                 if( buttons ) *buttons = joy->tmp_buttons;
223                     if( axes    ) memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
224                 return;
225                 }
226
227                 fgWarning( "%s", joy->fname );
228                 joy->error = TRUE;
229                 return;
230         }
231
232         switch( joy->js.type & ~JS_EVENT_INIT )
233         {
234             case JS_EVENT_BUTTON:
235                 if ( joy->js.value == 0 ) /* clear the flag */
236                     joy->tmp_buttons &= ~(1 << joy->js.number);
237             else
238                     joy->tmp_buttons |= (1 << joy->js.number);
239                 break;
240
241             case JS_EVENT_AXIS:
242                 joy->tmp_axes[ joy->js.number ] = (float) joy->js.value;
243
244                 if( axes )
245                     memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
246                 break;
247         }
248
249         if( buttons )
250                 *buttons = joy->tmp_buttons;
251     }
252 #   else
253
254     status = read( joy->fd, &joy->js, JS_RETURN );
255
256     if( status != JS_RETURN )
257     {
258         fgWarning( "%s", joy->fname );
259         joy->error = TRUE;
260         return;
261     }
262
263     if( buttons )
264 #       if defined(__FreeBSD__) || defined(__NetBSD__)
265         *buttons = (joy->js.b1 ? 1 : 0) | (joy->js.b2 ? 2 : 0);
266 #       else
267         *buttons = joy->js.buttons;
268 #       endif
269
270     if( axes )
271     {
272         axes[ 0 ] = (float) joy->js.x;
273         axes[ 1 ] = (float) joy->js.y;
274     }
275 #   endif
276 #endif
277 }
278
279 /*
280  * Correct the joystick axis data
281  */
282 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
283 {
284     if( value < joy->center[ axis ] )
285     {
286         float xx = (value - joy->center[ axis ]) / (joy->center[ axis ] - joy->min[ axis ]);
287
288         if( xx < -joy->saturate[ axis ] )
289                 return( -1.0f );
290
291         if( xx > -joy->dead_band [ axis ] )
292                 return(  0.0f );
293
294         xx = (xx + joy->dead_band[ axis ]) / (joy->saturate[ axis ] - joy->dead_band[ axis ]);
295
296         return( ( xx < -1.0f ) ? -1.0f : xx );
297     }
298     else
299     {
300         float xx = (value - joy->center [ axis ]) / (joy->max[ axis ] - joy->center[ axis ]);
301
302         if( xx > joy->saturate[ axis ] )
303             return 1.0f ;
304
305         if( xx < joy->dead_band[ axis ] )
306                 return 0.0f ;
307
308         xx = (xx - joy->dead_band[ axis ]) / (joy->saturate[ axis ] - joy->dead_band[ axis ]);
309
310         return( ( xx > 1.0f ) ? 1.0f : xx );
311     }
312 }
313
314 /*
315  * Read the corrected joystick data
316  */
317 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
318 {
319     float raw_axes[ _JS_MAX_AXES ];
320     int  i;
321
322     if( joy->error )
323     {
324         if( buttons )
325             *buttons = 0;
326
327         if( axes )
328             for ( i=0; i<joy->num_axes ; i++ )
329                 axes[ i ] = 0.0f ;
330     }
331
332     fghJoystickRawRead( joy, buttons, raw_axes );
333
334     if( axes )
335         for( i=0 ; i<joy->num_axes ; i++ )
336             axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
337 }
338
339 /*
340  * Happy happy happy joy joy joy (happy new year toudi :D)
341  */
342 static void fghJoystickOpen( SFG_Joystick* joy )
343 {
344 #ifdef WIN32
345     JOYCAPS jsCaps;
346     int     i;
347
348     joy->js.dwFlags = JOY_RETURNALL;
349     joy->js.dwSize  = sizeof( joy->js );
350
351     memset( &jsCaps, 0, sizeof(jsCaps) );
352
353     joy->error    = (joyGetDevCaps( joy->js_id, &jsCaps, sizeof(jsCaps) ) != JOYERR_NOERROR);
354     joy->num_axes = (jsCaps.wNumAxes < _JS_MAX_AXES ) ? jsCaps.wNumAxes : _JS_MAX_AXES;
355
356     /*
357      * WARNING - Fall through case clauses!!
358      */
359     switch( joy->num_axes )
360     {
361     case 6 : joy->min[ 5 ] = (float) jsCaps.wVmin; joy->max[ 5 ] = (float) jsCaps.wVmax;
362     case 5 : joy->min[ 4 ] = (float) jsCaps.wUmin; joy->max[ 4 ] = (float) jsCaps.wUmax;
363     case 4 : joy->min[ 3 ] = (float) jsCaps.wRmin; joy->max[ 3 ] = (float) jsCaps.wRmax;
364     case 3 : joy->min[ 2 ] = (float) jsCaps.wZmin; joy->max[ 2 ] = (float) jsCaps.wZmax;
365     case 2 : joy->min[ 1 ] = (float) jsCaps.wYmin; joy->max[ 1 ] = (float) jsCaps.wYmax;
366     case 1 : joy->min[ 0 ] = (float) jsCaps.wXmin; joy->max[ 0 ] = (float) jsCaps.wXmax; break;
367
368     /*
369      * I guess we have no axes at all
370      */
371     default: joy->error = TRUE; break;
372     }
373
374     /*
375      * Guess all the rest judging on the axes extremals
376      */
377     for( i=0 ; i<joy->num_axes ; i++ )
378     {
379         joy->center   [ i ] = (joy->max[i] + joy->min[i]) * 0.5f;
380         joy->dead_band[ i ] = 0.0f;
381         joy->saturate [ i ] = 1.0f;
382     }
383
384 #else
385 #   ifdef __FreeBSD__
386     int   buttons[ _JS_MAX_AXES ];
387     float axes[ _JS_MAX_AXES ];
388     int   noargs, in_no_axes;
389     char  joyfname[ 1024 ];
390     FILE* joyfile;
391 #   else
392 #       ifndef JS_NEW
393     int counter;
394 #       endif
395 #   endif
396     int i;
397
398     /*
399      * Default for older Linux systems.
400      */
401     joy->num_axes    =  2;
402     joy->num_buttons = 32;
403
404 #   ifdef JS_NEW
405     for( i=0 ; i<_JS_MAX_AXES ; i++ )
406         joy->tmp_axes[ i ] = 0.0f ;
407
408     joy->tmp_buttons = 0 ;
409 #   endif
410
411     joy->fd = open( joy->fname, O_RDONLY );
412
413     joy->error = (joy->fd < 0);
414
415     if( joy->error )
416         return;
417
418 #   ifdef __FreeBSD__
419     fghJoystickRawRead(joy, buttons, axes );
420     joy->error = axes[ 0 ] < -1000000000.0f;
421     if( joy->error )
422       return ;
423
424     sprintf( joyfname, "%s/.joy%drc", getenv( "HOME" ), joy->id );
425
426     joyfile = fopen( joyfname, "r" );
427     joy->error = (joyfile == NULL);
428     if( joy->error )
429       return;
430
431     noargs = fscanf(
432         joyfile, "%d%f%f%f%f%f%f",
433         &in_no_axes,
434         &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
435         &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ]
436     );
437
438     joy->error = (noargs != 7) || (in_no_axes != _JS_MAX_AXES);
439     fclose( joyfile );
440     if( joy->error )
441       return;
442
443     for( i=0 ; i<_JS_MAX_AXES ; i++ )
444     {
445         joy->dead_band[ i ] = 0.0f;
446         joy->saturate [ i ] = 1.0f;
447     }
448 #   else
449
450     /*
451      * Set the correct number of axes for the linux driver
452      */
453 #       ifdef JS_NEW
454     ioctl( joy->fd, JSIOCGAXES   , &joy->num_axes    );
455     ioctl( joy->fd, JSIOCGBUTTONS, &joy->num_buttons );
456     fcntl( joy->fd, F_SETFL, O_NONBLOCK );
457
458 #       endif
459
460     /*
461      * The Linux driver seems to return 512 for all axes
462      * when no stick is present - but there is a chance
463      * that could happen by accident - so it's gotta happen
464      * on both axes for at least 100 attempts.
465      *
466      * PWO: shouldn't be that done somehow wiser on the kernel level?
467      */
468 #       ifndef JS_NEW
469     counter = 0 ;
470
471     do
472     { 
473         fghJoystickRawRead( joy, NULL, joy->center );
474         counter++;
475     } while( !joy->error && counter < 100 && joy->center[ 0 ] == 512.0f && joy->center[ 1 ] == 512.0f );
476    
477     if( counter >= 100 )
478         joy->error = TRUE;
479 #       endif
480
481     for( i=0 ; i<_JS_MAX_AXES ; i++ )
482     {
483 #       ifdef JS_NEW
484         joy->max   [ i ] =  32767.0f;
485         joy->center[ i ] =      0.0f;
486         joy->min   [ i ] = -32767.0f;
487 #       else
488         joy->max[ i ] = joy->center[ i ] * 2.0f;
489         joy->min[ i ] = 0.0f;
490 #       endif
491         joy->dead_band[ i ] = 0.0f ;
492         joy->saturate [ i ] = 1.0f ;
493     }
494 #   endif
495 #endif
496 }
497
498 /*
499  *
500  */
501 void fgJoystickInit( int ident )
502 {
503     /*
504      * Make sure we don't get reinitialized
505      */
506     if( fgJoystick != NULL )
507         fgError( "illegal attemp to initialize joystick device" );
508
509     /*
510      * Have the global joystick structure created
511      */
512     fgJoystick = (SFG_Joystick *)calloc( sizeof(SFG_Joystick), 1 );
513
514 #ifdef WIN32
515     switch( ident )
516     {
517     case 0:  fgJoystick->js_id    = JOYSTICKID1; fghJoystickOpen( fgJoystick ); break;
518     case 1:  fgJoystick->js_id    = JOYSTICKID2; fghJoystickOpen( fgJoystick ); break;
519     default: fgJoystick->num_axes = 0; fgJoystick->error = TRUE;                break;
520     }
521 #else
522
523 #   ifdef __FreeBSD__
524     fgJoystick->id = ident;
525     sprintf( fgJoystick->fname, "/dev/joy%d", ident );
526 #   else
527     sprintf( fgJoystick->fname, "/dev/js%d", ident );
528 #   endif
529
530     /*
531      * Let's try opening the joystick device now:
532      */
533     fghJoystickOpen( fgJoystick );
534 #endif
535 }
536
537 /*
538  *
539  */
540 void fgJoystickClose( void )
541 {
542     if( fgJoystick == NULL )
543         fgError( "illegal attempt to deinitialize joystick device" );
544
545 #ifndef WIN32
546     if( fgJoystick->error != TRUE )
547         close( fgJoystick->fd );
548 #endif
549
550     free ( fgJoystick ) ;
551     fgJoystick = NULL ;  /* show joystick has been deinitialized */
552 }
553
554 /*
555  * Polls the joystick and executes the joystick callback hooked to the
556  * window specified in the function's parameter:
557  */
558 void fgJoystickPollWindow( SFG_Window* window )
559 {
560     float axes[ _JS_MAX_AXES ];
561     int buttons;
562
563     /*
564      * Make sure the joystick device is initialized, the window seems valid
565      * and that there is a joystick callback hooked to it:
566      */
567     freeglut_return_if_fail( fgJoystick != NULL && window != NULL );
568     freeglut_return_if_fail( window->Callbacks.Joystick != NULL );
569
570     /*
571      * Poll the joystick now:
572      */
573     fghJoystickRead( fgJoystick, &buttons, axes );
574
575     /*
576      * Execute the freeglut joystick callback now
577      */
578     fgSetWindow (window);
579     window->Callbacks.Joystick(
580         buttons,
581         (int) (axes[ 0 ] * 1000.0f),
582         (int) (axes[ 1 ] * 1000.0f),
583         (int) (axes[ 2 ] * 1000.0f)
584     );
585 }
586
587 /*
588  * PWO: These jsJoystick class methods have not been implemented.
589  *      We might consider adding such functions to freeglut-2.0.
590  */
591 #if 0
592   int  getNumAxes () { return num_axes ; }
593   int  notWorking () { return error ;    }
594
595   float getDeadBand ( int axis )             { return dead_band [ axis ] ; }
596   void  setDeadBand ( int axis, float db )   { dead_band [ axis ] = db   ; }
597
598   float getSaturation ( int axis )           { return saturate [ axis ]  ; }
599   void  setSaturation ( int axis, float st ) { saturate [ axis ] = st    ; }
600
601   void setMinRange ( float *axes ) { memcpy ( min   , axes, num_axes * sizeof(float) ) ; }
602   void setMaxRange ( float *axes ) { memcpy ( max   , axes, num_axes * sizeof(float) ) ; }
603   void setCenter   ( float *axes ) { memcpy ( center, axes, num_axes * sizeof(float) ) ; }
604
605   void getMinRange ( float *axes ) { memcpy ( axes, min   , num_axes * sizeof(float) ) ; }
606   void getMaxRange ( float *axes ) { memcpy ( axes, max   , num_axes * sizeof(float) ) ; }
607   void getCenter   ( float *axes ) { memcpy ( axes, center, num_axes * sizeof(float) ) ; }
608 #endif
609
610 /*** END OF FILE ***/
611
612
613
614