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