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