Finished off most of the issues with freeglut_structure.c, from a stylistic
[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 /*
122  * XXX All BSDs might share this?
123  */
124 #ifdef __FreeBSD__
125     int         id;
126 #endif
127
128 #ifdef WIN32
129     JOYINFOEX   js;
130     UINT        js_id;
131 #else
132 #   ifdef JS_NEW
133         struct js_event js;
134         int         tmp_buttons;
135         float       tmp_axes[ _JS_MAX_AXES ];
136 #   else
137         struct JS_DATA_TYPE js;
138 #   endif
139
140     char fname[ 128 ];
141     int  fd;
142 #endif
143
144     GLboolean error;
145     int       num_axes;
146     int       num_buttons;
147
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 ];
153 };
154
155 /*
156  * The static joystick structure pointer
157  */
158 static SFG_Joystick* fgJoystick = NULL;
159
160 /*
161  * Read the raw joystick data
162  */
163 static void fghJoystickRawRead ( SFG_Joystick* joy, int* buttons, float* axes )
164 {
165 #ifdef WIN32
166     MMRESULT status;
167 #else
168     int status;
169 #endif
170
171     int i;
172
173     if( joy->error )
174     {
175         if( buttons )
176             *buttons = 0 ;
177
178         if( axes )
179             for( i=0; i<joy->num_axes; i++ )
180                 axes[ i ] = 1500.0f;
181
182         return;
183     }
184
185 #ifdef WIN32
186     status = joyGetPosEx( joy->js_id, &joy->js );
187
188     if( status != JOYERR_NOERROR )
189     {
190         joy->error = TRUE;
191         return;
192     }
193
194     if( buttons )
195         *buttons = joy->js.dwButtons;
196
197     if( axes )
198     {
199         /*
200          * WARNING - Fall through case clauses!!
201          */
202         switch( joy->num_axes )
203         {
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;
210         }
211     }
212 #else
213 #   ifdef JS_NEW
214
215     while( 1 )
216     {
217         status = read( joy->fd, &joy->js, sizeof(struct js_event) );
218
219         if( status != sizeof(struct js_event) )
220         {
221             if( errno == EAGAIN )
222             {
223                 /*
224                  * Use the old values
225                  */
226                 if( buttons )
227                     *buttons = joy->tmp_buttons;
228                 if( axes )
229                     memcpy( axes, joy->tmp_axes,
230                             sizeof(float) * joy->num_axes );
231                 return;
232             }
233
234             fgWarning( "%s", joy->fname );
235             joy->error = TRUE;
236             return;
237         }
238
239         switch( joy->js.type & ~JS_EVENT_INIT )
240         {
241         case JS_EVENT_BUTTON:
242             if ( joy->js.value == 0 ) /* clear the flag */
243                 joy->tmp_buttons &= ~(1 << joy->js.number);
244             else
245                 joy->tmp_buttons |= (1 << joy->js.number);
246             break;
247
248         case JS_EVENT_AXIS:
249             joy->tmp_axes[ joy->js.number ] = (float) joy->js.value;
250             
251             if( axes )
252                 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
253             break;
254         }
255
256         if( buttons )
257             *buttons = joy->tmp_buttons;
258     }
259 #   else
260
261     status = read( joy->fd, &joy->js, JS_RETURN );
262
263     if( status != JS_RETURN )
264     {
265         fgWarning( "%s", joy->fname );
266         joy->error = TRUE;
267         return;
268     }
269
270     if( buttons )
271 #       if defined(__FreeBSD__) || defined(__NetBSD__)
272         *buttons = (joy->js.b1 ? 1 : 0) | (joy->js.b2 ? 2 : 0);
273 #       else
274         *buttons = joy->js.buttons;
275 #       endif
276
277     if( axes )
278     {
279         axes[ 0 ] = (float) joy->js.x;
280         axes[ 1 ] = (float) joy->js.y;
281     }
282 #   endif
283 #endif
284 }
285
286 /*
287  * Correct the joystick axis data
288  */
289 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
290 {
291     if( value < joy->center[ axis ] )
292     {
293         float xx = (value - joy->center[ axis ]) / (joy->center[ axis ] -
294                                                     joy->min[ axis ]);
295
296         if( xx < -joy->saturate[ axis ] )
297             return -1.0f;
298
299         if( xx > -joy->dead_band [ axis ] )
300             return 0.0f;
301
302         xx = (xx + joy->dead_band[ axis ]) / (joy->saturate[ axis ] -
303                                               joy->dead_band[ axis ]);
304
305         return ( xx < -1.0f ) ? -1.0f : xx;
306     }
307     else
308     {
309         float xx = (value - joy->center [ axis ]) / (joy->max[ axis ] -
310                                                      joy->center[ axis ]);
311
312         if( xx > joy->saturate[ axis ] )
313             return 1.0f ;
314
315         if( xx < joy->dead_band[ axis ] )
316             return 0.0f ;
317
318         xx = (xx - joy->dead_band[ axis ]) / (joy->saturate[ axis ] -
319                                               joy->dead_band[ axis ]);
320
321         return ( xx > 1.0f ) ? 1.0f : xx;
322     }
323 }
324
325 /*
326  * Read the corrected joystick data
327  */
328 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
329 {
330     float raw_axes[ _JS_MAX_AXES ];
331     int  i;
332
333     if( joy->error )
334     {
335         if( buttons )
336             *buttons = 0;
337
338         if( axes )
339             for ( i=0; i<joy->num_axes ; i++ )
340                 axes[ i ] = 0.0f ;
341     }
342
343     fghJoystickRawRead( joy, buttons, raw_axes );
344
345     if( axes )
346         for( i=0 ; i<joy->num_axes ; i++ )
347             axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
348 }
349
350 /*
351  * Happy happy happy joy joy joy (happy new year toudi :D)
352  */
353 static void fghJoystickOpen( SFG_Joystick* joy )
354 {
355 #ifdef WIN32
356     JOYCAPS jsCaps;
357     int     i;
358
359     joy->js.dwFlags = JOY_RETURNALL;
360     joy->js.dwSize  = sizeof( joy->js );
361
362     memset( &jsCaps, 0, sizeof(jsCaps) );
363
364     joy->error =
365         (joyGetDevCaps( joy->js_id, &jsCaps, sizeof(jsCaps) ) !=
366          JOYERR_NOERROR);
367     joy->num_axes =
368         (jsCaps.wNumAxes < _JS_MAX_AXES ) ? jsCaps.wNumAxes : _JS_MAX_AXES;
369
370     /*
371      * WARNING - Fall through case clauses!!
372      */
373     switch( joy->num_axes )
374     {
375     case 6:
376         joy->min[ 5 ] = (float) jsCaps.wVmin;
377         joy->max[ 5 ] = (float) jsCaps.wVmax;
378     case 5:
379         joy->min[ 4 ] = (float) jsCaps.wUmin;
380         joy->max[ 4 ] = (float) jsCaps.wUmax;
381     case 4:
382         joy->min[ 3 ] = (float) jsCaps.wRmin;
383         joy->max[ 3 ] = (float) jsCaps.wRmax;
384     case 3:
385         joy->min[ 2 ] = (float) jsCaps.wZmin;
386         joy->max[ 2 ] = (float) jsCaps.wZmax;
387     case 2:
388         joy->min[ 1 ] = (float) jsCaps.wYmin;
389         joy->max[ 1 ] = (float) jsCaps.wYmax;
390     case 1:
391         joy->min[ 0 ] = (float) jsCaps.wXmin;
392         joy->max[ 0 ] = (float) jsCaps.wXmax;
393         break;
394
395     /*
396      * I guess we have no axes at all
397      */
398     default:
399         joy->error = TRUE;
400         break;
401     }
402
403     /*
404      * Guess all the rest judging on the axes extremals
405      */
406     for( i=0 ; i<joy->num_axes ; i++ )
407     {
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;
411     }
412
413 #else
414 #   ifdef __FreeBSD__
415     int   buttons[ _JS_MAX_AXES ];
416     float axes[ _JS_MAX_AXES ];
417     int   noargs, in_no_axes;
418     char  joyfname[ 1024 ];
419     FILE* joyfile;
420 #   else
421 #       ifndef JS_NEW
422     int counter;
423 #       endif
424 #   endif
425     int i;
426
427     /*
428      * Default for older Linux systems.
429      */
430     joy->num_axes    =  2;
431     joy->num_buttons = 32;
432
433 #   ifdef JS_NEW
434     for( i=0 ; i<_JS_MAX_AXES ; i++ )
435         joy->tmp_axes[ i ] = 0.0f ;
436
437     joy->tmp_buttons = 0 ;
438 #   endif
439
440     joy->fd = open( joy->fname, O_RDONLY );
441
442     joy->error = (joy->fd < 0);
443
444     if( joy->error )
445         return;
446 /*
447  * XXX All BSDs should share this?
448  */
449 #   ifdef __FreeBSD__
450     fghJoystickRawRead(joy, buttons, axes );
451     joy->error = axes[ 0 ] < -1000000000.0f;
452     if( joy->error )
453         return ;
454
455     sprintf( joyfname, "%s/.joy%drc", getenv( "HOME" ), joy->id );
456
457     joyfile = fopen( joyfname, "r" );
458     joy->error = (joyfile == NULL);
459     if( joy->error )
460       return;
461
462     noargs = fscanf(
463         joyfile, "%d%f%f%f%f%f%f",
464         &in_no_axes,
465         &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
466         &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ]
467     );
468
469     joy->error = (noargs != 7) || (in_no_axes != _JS_MAX_AXES);
470     fclose( joyfile );
471     if( joy->error )
472         return;
473
474     for( i=0 ; i<_JS_MAX_AXES ; i++ )
475     {
476         joy->dead_band[ i ] = 0.0f;
477         joy->saturate [ i ] = 1.0f;
478     }
479 #   else
480
481     /*
482      * Set the correct number of axes for the linux driver
483      */
484 #       ifdef JS_NEW
485
486     ioctl( joy->fd, JSIOCGAXES   , &joy->num_axes    );
487     ioctl( joy->fd, JSIOCGBUTTONS, &joy->num_buttons );
488     fcntl( joy->fd, F_SETFL, O_NONBLOCK );
489
490 #       endif
491
492     /*
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.
497      *
498      * PWO: shouldn't be that done somehow wiser on the kernel level?
499      */
500 #       ifndef JS_NEW
501     counter = 0 ;
502
503     do
504     { 
505         fghJoystickRawRead( joy, NULL, joy->center );
506         counter++;
507     } while( !joy->error &&
508              counter < 100 &&
509              joy->center[ 0 ] == 512.0f &&
510              joy->center[ 1 ] == 512.0f );
511    
512     if( counter >= 100 )
513         joy->error = TRUE;
514 #       endif
515
516     for( i=0 ; i<_JS_MAX_AXES ; i++ )
517     {
518 #       ifdef JS_NEW
519         joy->max   [ i ] =  32767.0f;
520         joy->center[ i ] =      0.0f;
521         joy->min   [ i ] = -32767.0f;
522 #       else
523         joy->max[ i ] = joy->center[ i ] * 2.0f;
524         joy->min[ i ] = 0.0f;
525 #       endif
526         joy->dead_band[ i ] = 0.0f ;
527         joy->saturate [ i ] = 1.0f ;
528     }
529 #   endif
530 #endif
531 }
532
533 /*
534  *
535  */
536 void fgJoystickInit( int ident )
537 {
538     if( fgJoystick != NULL )
539         fgError( "illegal attemp to initialize joystick device" );
540
541     fgJoystick = (SFG_Joystick *)calloc( sizeof(SFG_Joystick), 1 );
542
543 #ifdef WIN32
544     switch( ident )
545     {
546     case 0:
547         fgJoystick->js_id = JOYSTICKID1;
548         fghJoystickOpen( fgJoystick );
549         break;
550     case 1:
551         fgJoystick->js_id = JOYSTICKID2;
552         fghJoystickOpen( fgJoystick );
553         break;
554     default:
555         fgJoystick->num_axes = 0;
556         fgJoystick->error = TRUE;
557         break;
558     }
559 #else
560
561 /*
562  * XXX All BSDs should share this code?
563  */
564 #   ifdef __FreeBSD__
565     fgJoystick->id = ident;
566     sprintf( fgJoystick->fname, "/dev/joy%d", ident );
567 #   else
568     sprintf( fgJoystick->fname, "/dev/js%d", ident );
569 #   endif
570
571     fghJoystickOpen( fgJoystick );
572 #endif
573 }
574
575 /*
576  *
577  */
578 void fgJoystickClose( void )
579 {
580     if( fgJoystick == NULL )
581         fgError( "illegal attempt to deinitialize joystick device" );
582
583 #ifndef WIN32
584     if( fgJoystick->error != TRUE )
585         close( fgJoystick->fd );
586 #endif
587
588     free ( fgJoystick ) ;
589     fgJoystick = NULL ;  /* show joystick has been deinitialized */
590 }
591
592 /*
593  * Polls the joystick and executes the joystick callback hooked to the
594  * window specified in the function's parameter:
595  */
596 void fgJoystickPollWindow( SFG_Window* window )
597 {
598     float axes[ _JS_MAX_AXES ];
599     int buttons;
600
601     freeglut_return_if_fail( fgJoystick != NULL && window != NULL );
602     freeglut_return_if_fail( window->Callbacks.Joystick != NULL );
603
604     fghJoystickRead( fgJoystick, &buttons, axes );
605
606     fgSetWindow (window);
607     window->Callbacks.Joystick(
608         buttons,
609         (int) (axes[ 0 ] * 1000.0f),
610         (int) (axes[ 1 ] * 1000.0f),
611         (int) (axes[ 2 ] * 1000.0f)
612     );
613 }
614
615 /*
616  * PWO: These jsJoystick class methods have not been implemented.
617  *      We might consider adding such functions to freeglut-2.0.
618  */
619 #if 0
620 int  getNumAxes ()
621     { return num_axes; }
622 int  notWorking ()
623     { return error; }
624
625 float getDeadBand ( int axis )
626     { return dead_band [ axis ]; }
627 void  setDeadBand ( int axis, float db )
628     { dead_band [ axis ] = db; }
629
630 float getSaturation ( int axis )
631     { return saturate [ axis ]; }
632 void  setSaturation ( int axis, float st )
633     { saturate [ axis ] = st; }
634
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) ); }
641
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) ); }
648 #endif
649
650 /*** END OF FILE ***/