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