Replace #ifdef WIN32 with #ifdef TARGET_HOST_WIN32, as per FreeGLUT convention
[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 TARGET_HOST_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 TARGET_HOST_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 TARGET_HOST_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 TARGET_HOST_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 TARGET_HOST_WIN32
184     status = joyGetPosEx( joy->js_id, &joy->js );
185
186     if( status != JOYERR_NOERROR )
187     {
188         joy->error = GL_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 = GL_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 = GL_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 TARGET_HOST_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 = GL_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 = GL_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 )
537         fgError( "illegal attemp to initialize joystick device" );
538
539     fgJoystick = ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
540
541 #ifdef TARGET_HOST_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 = GL_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 )
579         fgError( "illegal attempt to deinitialize joystick device" );
580
581 #ifndef TARGET_HOST_WIN32
582     if( ! fgJoystick->error )
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 );
600     freeglut_return_if_fail( window );
601     freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
602
603     fghJoystickRead( fgJoystick, &buttons, axes );
604
605     INVOKE_WCB( *window, 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      * fgSetWindow (window);
614      * window->Callbacks.Joystick(
615      *   buttons,
616      *   (int) (axes[ 0 ] * 1000.0f),
617      *   (int) (axes[ 1 ] * 1000.0f),
618      *   (int) (axes[ 2 ] * 1000.0f)
619      * );
620      */
621 }
622
623 /*
624  * PWO: These jsJoystick class methods have not been implemented.
625  *      We might consider adding such functions to freeglut-2.0.
626  */
627 #if 0
628 int  getNumAxes ()
629     { return num_axes; }
630 int  notWorking ()
631     { return error; }
632
633 float getDeadBand ( int axis )
634     { return dead_band [ axis ]; }
635 void  setDeadBand ( int axis, float db )
636     { dead_band [ axis ] = db; }
637
638 float getSaturation ( int axis )
639     { return saturate [ axis ]; }
640 void  setSaturation ( int axis, float st )
641     { saturate [ axis ] = st; }
642
643 void setMinRange ( float *axes )
644     { memcpy ( min   , axes, num_axes * sizeof(float) ); }
645 void setMaxRange ( float *axes )
646     { memcpy ( max   , axes, num_axes * sizeof(float) ); }
647 void setCenter   ( float *axes )
648     { memcpy ( center, axes, num_axes * sizeof(float) ); }
649
650 void getMinRange ( float *axes )
651     { memcpy ( axes, min   , num_axes * sizeof(float) ); }
652 void getMaxRange ( float *axes )
653     { memcpy ( axes, max   , num_axes * sizeof(float) ); }
654 void getCenter   ( float *axes )
655     { memcpy ( axes, center, num_axes * sizeof(float) ); }
656 #endif
657
658 /*** END OF FILE ***/