resetting manifest requested domain to floor
[platform/upstream/freeglut.git] / 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  * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
29  *
30  * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
31  *  Many thanks for Steve Baker for permission to pull from that library.
32  */
33
34 #include <GL/freeglut.h>
35 #include "freeglut_internal.h"
36 #ifdef HAVE_SYS_PARAM_H
37 #    include <sys/param.h>
38 #endif
39
40 /*
41  * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
42  * interspersed
43  */
44
45 /* XXX It might be better to poll the operating system for the numbers of buttons and
46  * XXX axes and then dynamically allocate the arrays.
47  */
48 #define _JS_MAX_BUTTONS 32
49
50 #if TARGET_HOST_MACINTOSH
51 #    define _JS_MAX_AXES  9
52 #    include <InputSprocket.h>
53 #endif
54
55 #if TARGET_HOST_MAC_OSX
56 #    define _JS_MAX_AXES 16
57 #    include <mach/mach.h>
58 #    include <IOKit/IOkitLib.h>
59 #    include <IOKit/hid/IOHIDLib.h>
60 #endif
61
62 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
63 #    define _JS_MAX_AXES  8
64 #    include <windows.h>
65 #    include <mmsystem.h>
66 #    include <regstr.h>
67
68 #endif
69
70 #if TARGET_HOST_POSIX_X11
71 #    define _JS_MAX_AXES 16
72 #    ifdef HAVE_SYS_IOCTL_H
73 #        include <sys/ioctl.h>
74 #    endif
75 #    ifdef HAVE_FCNTL_H
76 #        include <fcntl.h>
77 #    endif
78 #    ifdef HAVE_ERRNO_H
79 #        include <errno.h>
80 #        include <string.h>
81 #    endif
82 #    if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
83 /* XXX The below hack is done until freeglut's autoconf is updated. */
84 #        define HAVE_USB_JS    1
85
86 #        if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
87 #            include <sys/joystick.h>
88 #        else
89 /*
90  * XXX NetBSD/amd64 systems may find that they have to steal the
91  * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
92  * XXX I cannot comment whether that works for the interface, but
93  * XXX it lets you compile...(^&  I do not think that we can do away
94  * XXX with this header.
95  */
96 #            include <machine/joystick.h>         /* For analog joysticks */
97 #        endif
98 #        define JS_DATA_TYPE joystick
99 #        define JS_RETURN (sizeof(struct JS_DATA_TYPE))
100 #    endif
101
102 #    if defined(__linux__)
103 #        include <linux/joystick.h>
104
105 /* check the joystick driver version */
106 #        if defined(JS_VERSION) && JS_VERSION >= 0x010000
107 #            define JS_NEW
108 #        endif
109 #    else  /* Not BSD or Linux */
110 #        ifndef JS_RETURN
111
112   /*
113    * We'll put these values in and that should
114    * allow the code to at least compile when there is
115    * no support. The JS open routine should error out
116    * and shut off all the code downstream anyway and if
117    * the application doesn't use a joystick we'll be fine.
118    */
119
120   struct JS_DATA_TYPE
121   {
122     int buttons;
123     int x;
124     int y;
125   };
126
127 #            define JS_RETURN (sizeof(struct JS_DATA_TYPE))
128 #        endif
129 #    endif
130 #endif
131
132 #define JS_TRUE  1
133 #define JS_FALSE 0
134
135 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
136
137 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
138
139 #    ifdef HAVE_USB_JS
140 #        if defined(__NetBSD__)
141 /* XXX The below hack is done until freeglut's autoconf is updated. */
142 #            define HAVE_USBHID_H 1
143 #            ifdef HAVE_USBHID_H
144 #                include <usbhid.h>
145 #            else
146 #                include <usb.h>
147 #            endif
148 #        elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
149 #            ifdef HAVE_USBHID_H
150 #                include <usbhid.h>
151 #            else
152 #                include <libusbhid.h>
153 #            endif
154 #        endif
155 #        include <legacy/dev/usb/usb.h>
156 #        include <dev/usb/usbhid.h>
157
158 /* Compatibility with older usb.h revisions */
159 #        if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
160 #            define USB_MAX_DEVNAMES MAXDEVNAMES
161 #        endif
162 #    endif
163
164 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
165 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
166 struct os_specific_s {
167   char             fname [128 ];
168   int              fd;
169   int              is_analog;
170   /* The following structure members are specific to analog joysticks */
171   struct joystick  ajs;
172 #    ifdef HAVE_USB_JS
173   /* The following structure members are specific to USB joysticks */
174   struct hid_item *hids;
175   int              hid_dlen;
176   int              hid_offset;
177   char            *hid_data_buf;
178   int              axes_usage [ _JS_MAX_AXES ];
179 #    endif
180   /* We keep button and axes state ourselves, as they might not be updated
181    * on every read of a USB device
182    */
183   int              cache_buttons;
184   float            cache_axes [ _JS_MAX_AXES ];
185 };
186
187 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
188 #    define USB_IDENT_OFFSET    2
189
190 #    define USBDEV "/dev/usb"
191 #    define UHIDDEV "/dev/uhid"
192 #    define AJSDEV "/dev/joy"
193
194 #    ifdef HAVE_USB_JS
195 /*
196  * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
197  * the full name of a USB device. If /dev/usbN isn't readable, we punt and
198  * return the uhidN device name. We warn the user of this situation once.
199  */
200 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
201 {
202   struct usb_device_info di;
203   int i, a;
204   char *cp;
205
206   for (a = 1; a < USB_MAX_DEVICES; a++) {
207     di.udi_addr = a;
208     if (ioctl(f, USB_DEVICEINFO, &di) != 0)
209       return NULL;
210     for (i = 0; i < USB_MAX_DEVNAMES; i++)
211       if (di.udi_devnames[i][0] &&
212           strcmp(di.udi_devnames[i], dev) == 0) {
213         cp =  calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
214         strcpy(cp, di.udi_vendor);
215         strcat(cp, " ");
216         strcat(cp, di.udi_product);
217         strncpy(out, cp, outlen - 1);
218         out[outlen - 1] = 0;
219         free( cp );
220         return out;
221       }
222   }
223   return NULL;
224 }
225
226 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
227 {
228   int i, f;
229   char buf[50];
230   char *cp;
231   static int protection_warned = 0;
232
233   for (i = 0; i < 16; i++) {
234     snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
235     f = open(buf, O_RDONLY);
236     if (f >= 0) {
237       cp = fghJoystickWalkUSBdev(f, name, out, outlen);
238       close(f);
239       if (cp)
240         return 1;
241     }
242 #ifdef HAVE_ERRNO_H
243     else if (errno == EACCES) {
244       if (!protection_warned) {
245         fgWarning ( "Can't open %s for read!", buf );
246         protection_warned = 1;
247       }
248     }
249 #endif
250   }
251   return 0;
252 }
253
254 static int fghJoystickInitializeHID(struct os_specific_s *os,
255        int *num_axes, int *num_buttons)
256 {
257     int size, is_joystick;
258 #   ifdef HAVE_USBHID_H
259         int report_id = 0;
260 #   endif
261     struct hid_data *d;
262     struct hid_item h;
263     report_desc_t rd;
264
265     if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
266     {
267 #ifdef HAVE_ERRNO_H
268         fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
269 #else
270         fgWarning ( "error: %s", os->fname );
271 #endif
272         return FALSE;
273     }
274
275     os->hids = NULL;
276
277 #   ifdef HAVE_USBHID_H
278         if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
279         {
280             /*** XXX {report_id} may not be the right variable? ***/
281 #ifdef HAVE_ERRNO_H
282             fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
283 #else
284             fgWarning ( "error: %s%d", UHIDDEV, report_id );
285 #endif
286             return FALSE;
287         }
288
289         size = hid_report_size( rd, hid_input, report_id );
290 #   else
291         size = hid_report_size( rd, 0, hid_input );
292 #   endif
293     os->hid_data_buf = calloc( 1, size );
294     os->hid_dlen = size;
295
296     is_joystick = 0;
297 #   ifdef HAVE_USBHID_H
298         d = hid_start_parse( rd, 1 << hid_input, report_id );
299 #   else
300         d = hid_start_parse( rd, 1 << hid_input );
301 #   endif
302         while( hid_get_item( d, &h ) )
303         {
304             int usage, page, interesting_hid;
305
306             page = HID_PAGE( h.usage );
307             usage = HID_USAGE( h.usage );
308
309             /* This test is somewhat too simplistic, but this is how MicroSoft
310              * does, so I guess it works for all joysticks/game pads. */
311             is_joystick = is_joystick ||
312                 ( h.kind == hid_collection &&
313                   page == HUP_GENERIC_DESKTOP &&
314                   ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
315
316             if( h.kind != hid_input )
317                 continue;
318
319             if( !is_joystick )
320                 continue;
321
322             interesting_hid = TRUE;
323             if( page == HUP_GENERIC_DESKTOP )
324             {
325                 switch( usage )
326                 {
327                 case HUG_X:
328                 case HUG_RX:
329                 case HUG_Y:
330                 case HUG_RY:
331                 case HUG_Z:
332                 case HUG_RZ:
333                 case HUG_SLIDER:
334                     if( *num_axes < _JS_MAX_AXES )
335                     {
336                         os->axes_usage[ *num_axes ] = usage;
337                         ( *num_axes )++;
338                     }
339                     break;
340                 case HUG_HAT_SWITCH:
341                     /* Allocate two axes for a hat */
342                     if( *num_axes + 1 < _JS_MAX_AXES )
343                     {
344                         os->axes_usage[ *num_axes ] = usage;
345                         (*num_axes)++;
346                         os->axes_usage[ *num_axes ] = usage;
347                         (*num_axes)++;
348                     }
349                     break;
350                 default:
351                     interesting_hid = FALSE;
352                     break;
353                 }
354             }
355             else if( page == HUP_BUTTON )
356             {
357                 interesting_hid = ( usage > 0 ) &&
358                     ( usage <= _JS_MAX_BUTTONS );
359
360                 if( interesting_hid && usage - 1 > *num_buttons )
361                     *num_buttons = usage - 1;
362             }
363
364             if( interesting_hid )
365             {
366                 h.next = os->hids;
367                 os->hids = calloc( 1, sizeof ( struct hid_item ) );
368                 *os->hids = h;
369             }
370         }
371         hid_end_parse( d );
372
373         return os->hids != NULL;
374 }
375 #    endif
376 #endif
377
378 /*
379  * Definition of "SFG_Joystick" structure -- based on JS's "jsJoystick" object class.
380  * See "js.h" lines 80-178.
381  */
382 typedef struct tagSFG_Joystick SFG_Joystick;
383 struct tagSFG_Joystick
384 {
385 #if TARGET_HOST_MACINTOSH
386 #define  ISP_NUM_AXIS    9
387 #define  ISP_NUM_NEEDS  41
388     ISpElementReference isp_elem  [ ISP_NUM_NEEDS ];
389     ISpNeed             isp_needs [ ISP_NUM_NEEDS ];
390 #endif
391
392 #if TARGET_HOST_MAC_OSX
393     IOHIDDeviceInterface ** hidDev;
394     IOHIDElementCookie buttonCookies[41];
395     IOHIDElementCookie axisCookies[_JS_MAX_AXES];
396     long minReport[_JS_MAX_AXES],
397          maxReport[_JS_MAX_AXES];
398 #endif
399
400 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
401     JOYCAPS     jsCaps;
402     JOYINFOEX   js;
403     UINT        js_id;
404 #endif
405
406
407 #if TARGET_HOST_POSIX_X11
408 #   if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
409        struct os_specific_s *os;
410 #   endif
411
412 #   ifdef JS_NEW
413        struct js_event     js;
414        int          tmp_buttons;
415        float        tmp_axes [ _JS_MAX_AXES ];
416 #   else
417        struct JS_DATA_TYPE js;
418 #   endif
419
420     char         fname [ 128 ];
421     int          fd;
422 #endif
423
424     int          id;
425     GLboolean    error;
426     char         name [ 128 ];
427     int          num_axes;
428     int          num_buttons;
429
430     float dead_band[ _JS_MAX_AXES ];
431     float saturate [ _JS_MAX_AXES ];
432     float center   [ _JS_MAX_AXES ];
433     float max      [ _JS_MAX_AXES ];
434     float min      [ _JS_MAX_AXES ];
435 };
436
437 /*
438  * Functions associated with the "jsJoystick" class in PLIB
439  */
440 #if TARGET_HOST_MAC_OSX
441 #define K_NUM_DEVICES   32
442 int numDevices;
443 io_object_t ioDevices[K_NUM_DEVICES];
444
445 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
446 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
447
448 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
449 /* callback for CFArrayApply */
450 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
451
452 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
453 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
454 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
455 #endif
456
457
458 /*
459  * The static joystick structure pointer
460  */
461 #define MAX_NUM_JOYSTICKS  2
462 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
463
464
465 /*
466  * Read the raw joystick data
467  */
468 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
469 {
470 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
471     MMRESULT status;
472 #else
473     int status;
474 #endif
475
476 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
477     int len;
478 #endif
479
480     int i;
481
482     /* Defaults */
483     if( buttons )
484         *buttons = 0;
485
486     if( axes )
487         for( i = 0; i < joy->num_axes; i++ )
488             axes[ i ] = 1500.0f;
489
490     if( joy->error )
491         return;
492
493 #if TARGET_HOST_MACINTOSH
494     if ( buttons )
495     {
496         *buttons = 0;
497
498         for ( i = 0; i < joy->num_buttons; i++ )
499         {
500             UInt32 state;
501             int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
502             ISP_CHECK_ERR(err)
503
504             *buttons |= state << i;
505         }
506     }
507
508     if ( axes )
509     {
510         for ( i = 0; i < joy->num_axes; i++ )
511         {
512             UInt32 state;
513             int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
514             ISP_CHECK_ERR(err)
515
516             axes [i] = (float) state;
517         }
518     }
519 #endif
520
521 #if TARGET_HOST_MAC_OSX
522     if ( buttons != NULL )
523     {
524         *buttons = 0;
525
526         for ( i = 0; i < joy->num_buttons; i++ )
527         {
528             IOHIDEventStruct hidEvent;
529             (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
530             if ( hidEvent.value )
531                 *buttons |= 1 << i;
532         }
533     }
534
535     if ( axes != NULL )
536     {
537         for ( i = 0; i < joy->num_axes; i++ )
538         {
539             IOHIDEventStruct hidEvent;
540             (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
541             axes[i] = hidEvent.value;
542         }
543     }
544 #endif
545
546 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
547     status = joyGetPosEx( joy->js_id, &joy->js );
548
549     if ( status != JOYERR_NOERROR )
550     {
551         joy->error = GL_TRUE;
552         return;
553     }
554
555     if ( buttons )
556         *buttons = joy->js.dwButtons;
557
558     if ( axes )
559     {
560         /*
561          * WARNING - Fall through case clauses!!
562          */
563         switch ( joy->num_axes )
564         {
565         case 8:
566             /* Generate two POV axes from the POV hat angle.
567              * Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
568              *   hundredths of a degree, or 0xFFFF when idle.
569              */
570             if ( ( joy->js.dwPOV & 0xFFFF ) == 0xFFFF )
571             {
572               axes [ 6 ] = 0.0;
573               axes [ 7 ] = 0.0;
574             }
575             else
576             {
577               /* This is the contentious bit: how to convert angle to X/Y.
578                *    wk: I know of no define for PI that we could use here:
579                *    SG_PI would pull in sg, M_PI is undefined for MSVC
580                * But the accuracy of the value of PI is very unimportant at
581                * this point.
582                */
583               float s = (float) sin ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
584               float c = (float) cos ( ( joy->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180.0f ) );
585
586               /* Convert to coordinates on a square so that North-East
587                * is (1,1) not (.7,.7), etc.
588                * s and c cannot both be zero so we won't divide by zero.
589                */
590               if ( fabs ( s ) < fabs ( c ) )
591               {
592                 axes [ 6 ] = ( c < 0.0 ) ? -s/c  : s/c ;
593                 axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f;
594               }
595               else
596               {
597                 axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f;
598                 axes [ 7 ] = ( s < 0.0 ) ? -c/s  : c/s ;
599               }
600             }
601
602         case 6: axes[5] = (float) joy->js.dwVpos;
603         case 5: axes[4] = (float) joy->js.dwUpos;
604         case 4: axes[3] = (float) joy->js.dwRpos;
605         case 3: axes[2] = (float) joy->js.dwZpos;
606         case 2: axes[1] = (float) joy->js.dwYpos;
607         case 1: axes[0] = (float) joy->js.dwXpos;
608         }
609     }
610 #endif
611
612 #if TARGET_HOST_POSIX_X11
613 #    if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
614     if ( joy->os->is_analog )
615     {
616         int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
617         if ( status != sizeof(joy->os->ajs) ) {
618             perror ( joy->os->fname );
619             joy->error = GL_TRUE;
620             return;
621         }
622         if ( buttons != NULL )
623             *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
624
625         if ( axes != NULL )
626         {
627             axes[0] = (float) joy->os->ajs.x;
628             axes[1] = (float) joy->os->ajs.y;
629         }
630
631         return;
632     }
633
634 #        ifdef HAVE_USB_JS
635     while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
636     {
637         struct hid_item *h;
638
639         for  ( h = joy->os->hids; h; h = h->next )
640         {
641             int d = hid_get_data ( joy->os->hid_data_buf, h );
642
643             int page = HID_PAGE ( h->usage );
644             int usage = HID_USAGE ( h->usage );
645
646             if ( page == HUP_GENERIC_DESKTOP )
647             {
648                 int i;
649                 for ( i = 0; i < joy->num_axes; i++ )
650                     if (joy->os->axes_usage[i] == usage)
651                     {
652                         if (usage == HUG_HAT_SWITCH)
653                         {
654                             if (d < 0 || d > 8)
655                                 d = 0;  /* safety */
656                             joy->os->cache_axes[i] = (float)hatmap_x[d];
657                             joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
658                         }
659                         else
660                         {
661                             joy->os->cache_axes[i] = (float)d;
662                         }
663                         break;
664                     }
665             }
666             else if (page == HUP_BUTTON)
667             {
668                if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
669                {
670                    if (d)
671                        joy->os->cache_buttons |=  (1 << ( usage - 1 ));
672                    else
673                        joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
674                }
675             }
676         }
677     }
678 #ifdef HAVE_ERRNO_H
679     if ( len < 0 && errno != EAGAIN )
680 #else
681     if ( len < 0 )
682 #endif
683     {
684         perror( joy->os->fname );
685         joy->error = 1;
686     }
687     if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
688     if ( axes    != NULL )
689         memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
690 #        endif
691 #    endif
692
693 #    ifdef JS_NEW
694
695     while ( 1 )
696     {
697         status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
698
699         if ( status != sizeof( struct js_event ) )
700         {
701 #ifdef HAVE_ERRNO_H
702             if ( errno == EAGAIN )
703             {
704                 /* Use the old values */
705                 if ( buttons )
706                     *buttons = joy->tmp_buttons;
707                 if ( axes )
708                     memcpy( axes, joy->tmp_axes,
709                             sizeof( float ) * joy->num_axes );
710                 return;
711             }
712 #endif
713
714             fgWarning ( "%s", joy->fname );
715             joy->error = GL_TRUE;
716             return;
717         }
718
719         switch ( joy->js.type & ~JS_EVENT_INIT )
720         {
721         case JS_EVENT_BUTTON:
722             if( joy->js.value == 0 ) /* clear the flag */
723                 joy->tmp_buttons &= ~( 1 << joy->js.number );
724             else
725                 joy->tmp_buttons |= ( 1 << joy->js.number );
726             break;
727
728         case JS_EVENT_AXIS:
729             if ( joy->js.number < joy->num_axes )
730             {
731                 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
732
733                 if( axes )
734                     memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
735             }
736             break;
737
738         default:
739             fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
740
741             /* use the old values */
742
743             if ( buttons != NULL ) *buttons = joy->tmp_buttons;
744             if ( axes    != NULL )
745                 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
746
747             return;
748         }
749
750         if( buttons )
751             *buttons = joy->tmp_buttons;
752     }
753 #    else
754
755     status = read( joy->fd, &joy->js, JS_RETURN );
756
757     if ( status != JS_RETURN )
758     {
759         fgWarning( "%s", joy->fname );
760         joy->error = GL_TRUE;
761         return;
762     }
763
764     if ( buttons )
765 #        if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
766         *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 );  /* XXX Should not be here -- BSD is handled earlier */
767 #        else
768         *buttons = joy->js.buttons;
769 #        endif
770
771     if ( axes )
772     {
773         axes[ 0 ] = (float) joy->js.x;
774         axes[ 1 ] = (float) joy->js.y;
775     }
776 #    endif
777 #endif
778 }
779
780 /*
781  * Correct the joystick axis data
782  */
783 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
784 {
785     if( value < joy->center[ axis ] )
786     {
787         float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
788                                                        joy->min[ axis ] );
789
790         if( xx < -joy->saturate[ axis ] )
791             return -1.0f;
792
793         if( xx > -joy->dead_band [ axis ] )
794             return 0.0f;
795
796         xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
797                                                  joy->dead_band[ axis ] );
798
799         return ( xx < -1.0f ) ? -1.0f : xx;
800     }
801     else
802     {
803         float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
804                                                         joy->center[ axis ] );
805
806         if( xx > joy->saturate[ axis ] )
807             return 1.0f;
808
809         if( xx < joy->dead_band[ axis ] )
810             return 0.0f;
811
812         xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
813                                                  joy->dead_band[ axis ] );
814
815         return ( xx > 1.0f ) ? 1.0f : xx;
816     }
817 }
818
819 /*
820  * Read the corrected joystick data
821  */
822 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
823 {
824     float raw_axes[ _JS_MAX_AXES ];
825     int  i;
826
827     if( joy->error )
828     {
829         if( buttons )
830             *buttons = 0;
831
832         if( axes )
833             for ( i=0; i<joy->num_axes; i++ )
834                 axes[ i ] = 0.0f;
835     }
836
837     fghJoystickRawRead( joy, buttons, raw_axes );
838
839     if( axes )
840         for( i=0; i<joy->num_axes; i++ )
841             axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
842 }
843
844 /*
845  * Happy happy happy joy joy joy (happy new year toudi :D)
846  */
847
848
849 #if TARGET_HOST_MAC_OSX
850 /** open the IOKit connection, enumerate all the HID devices, add their
851 interface references to the static array. We then use the array index
852 as the device number when we come to open() the joystick. */
853 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
854 {
855     CFMutableDictionaryRef hidMatch = NULL;
856     IOReturn rv = kIOReturnSuccess;
857
858     io_iterator_t hidIterator;
859     io_object_t ioDev;
860
861     /* build a dictionary matching HID devices */
862     hidMatch = IOServiceMatching(kIOHIDDeviceKey);
863
864     rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
865     if (rv != kIOReturnSuccess || !hidIterator) {
866       fgWarning( "no joystick (HID) devices found" );
867       return;
868     }
869
870     /* iterate */
871     while ((ioDev = IOIteratorNext(hidIterator))) {
872         /* filter out keyboard and mouse devices */
873         CFDictionaryRef properties = getCFProperties(ioDev);
874         long usage, page;
875
876         CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
877         CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
878         CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
879         CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
880
881         /* keep only joystick devices */
882         if ( ( page == kHIDPage_GenericDesktop ) && (
883                             (usage == kHIDUsage_GD_Joystick)
884                          || (usage == kHIDUsage_GD_GamePad)
885                          || (usage == kHIDUsage_GD_MultiAxisController)
886                          || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
887             /* add it to the array */
888             ioDevices[numDevices++] = ioDev;
889     }
890
891     IOObjectRelease(hidIterator);
892 }
893
894 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
895 {
896     IOReturn rv;
897     CFMutableDictionaryRef cfProperties;
898
899 #if 0
900     /* comment copied from darwin/SDL_sysjoystick.c */
901     /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
902      * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
903      */
904
905     io_registry_entry_t parent1, parent2;
906
907     rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
908     if (rv != kIOReturnSuccess) {
909         fgWarning ( "error getting device entry parent");
910         return NULL;
911     }
912
913     rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
914     if (rv != kIOReturnSuccess) {
915         fgWarning ( "error getting device entry parent 2");
916         return NULL;
917     }
918 #endif
919
920     rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
921         &cfProperties, kCFAllocatorDefault, kNilOptions);
922     if (rv != kIOReturnSuccess || !cfProperties) {
923         fgWarning ( "error getting device properties");
924         return NULL;
925     }
926
927     return cfProperties;
928 }
929
930 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
931 {
932       if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
933             fgError ( "%s", "element enumerator passed non-dictionary value");
934             return;
935     }
936
937       static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
938 }
939
940 /** element enumerator function : pass NULL for top-level*/
941 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
942 {
943       FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
944                                     "Joystick element type mismatch",
945                                     "fghJoystickEnumerateElements" );
946
947       CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
948       CFArrayApplyFunction((CFArrayRef) element, range,
949             &fghJoystickElementEnumerator, joy );
950 }
951
952 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
953 {
954     long cookie, lmin, lmax;
955     int index = joy->num_axes++;
956
957     CFNumberGetValue ((CFNumberRef)
958         CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
959         kCFNumberLongType, &cookie);
960
961     axisCookies[index] = (IOHIDElementCookie) cookie;
962
963     CFNumberGetValue ((CFNumberRef)
964         CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
965         kCFNumberLongType, &lmin);
966
967     CFNumberGetValue ((CFNumberRef)
968         CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
969         kCFNumberLongType, &lmax);
970
971     joy->min[index] = lmin;
972     joy->max[index] = lmax;
973     joy->dead_band[index] = 0.0;
974     joy->saturate[index] = 1.0;
975     joy->center[index] = (lmax + lmin) * 0.5;
976 }
977
978 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
979 {
980     long cookie;
981     CFNumberGetValue ((CFNumberRef)
982             CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
983             kCFNumberLongType, &cookie);
984
985     joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
986     /* anything else for buttons? */
987 }
988
989 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
990 {
991     /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
992     /* do we map hats to axes or buttons? */
993 }
994 #endif
995
996 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
997 /* Inspired by
998    http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
999  */
1000 #    if FREEGLUT_LIB_PRAGMAS
1001 #        pragma comment (lib, "advapi32.lib")
1002 #    endif
1003
1004 static int fghJoystickGetOEMProductName ( SFG_Joystick* joy, char *buf, int buf_sz )
1005 {
1006     char buffer [ 256 ];
1007
1008     char OEMKey [ 256 ];
1009
1010     HKEY  hKey;
1011     DWORD dwcb;
1012     LONG  lr;
1013
1014     if ( joy->error )
1015         return 0;
1016
1017     /* Open .. MediaResources\CurrentJoystickSettings */
1018     _snprintf ( buffer, sizeof(buffer), "%s\\%s\\%s",
1019                 REGSTR_PATH_JOYCONFIG, joy->jsCaps.szRegKey,
1020                 REGSTR_KEY_JOYCURR );
1021
1022     lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
1023
1024     if ( lr != ERROR_SUCCESS ) return 0;
1025
1026     /* Get OEM Key name */
1027     dwcb = sizeof(OEMKey);
1028
1029     /* JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. */
1030     _snprintf ( buffer, sizeof(buffer), "Joystick%d%s", joy->js_id + 1, REGSTR_VAL_JOYOEMNAME );
1031
1032     lr = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEMKey, &dwcb);
1033     RegCloseKey ( hKey );
1034
1035     if ( lr != ERROR_SUCCESS ) return 0;
1036
1037     /* Open OEM Key from ...MediaProperties */
1038     _snprintf ( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey );
1039
1040     lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey );
1041
1042     if ( lr != ERROR_SUCCESS ) return 0;
1043
1044     /* Get OEM Name */
1045     dwcb = buf_sz;
1046
1047     lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf,
1048                              &dwcb );
1049     RegCloseKey ( hKey );
1050
1051     if ( lr != ERROR_SUCCESS ) return 0;
1052
1053     return 1;
1054 }
1055 #endif
1056
1057
1058 static void fghJoystickOpen( SFG_Joystick* joy )
1059 {
1060     int i = 0;
1061 #if TARGET_HOST_MACINTOSH
1062     OSStatus err;
1063 #endif
1064 #if TARGET_HOST_MAC_OSX
1065         IOReturn rv;
1066         SInt32 score;
1067         IOCFPlugInInterface **plugin;
1068
1069         HRESULT pluginResult;
1070
1071         CFDictionaryRef props;
1072     CFTypeRef topLevelElement;
1073 #endif
1074 #if TARGET_HOST_POSIX_X11
1075 #    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
1076        char *cp;
1077 #    endif
1078 #    ifdef JS_NEW
1079        unsigned char u;
1080 #    else
1081 #      if defined( __linux__ ) || TARGET_HOST_SOLARIS
1082          int counter = 0;
1083 #      endif
1084 #    endif
1085 #endif
1086
1087     /* Silence gcc, the correct #ifdefs would be too fragile... */
1088     (void)i;
1089
1090     /*
1091      * Default values (for no joystick -- each conditional will reset the
1092      * error flag)
1093      */
1094     joy->error = TRUE;
1095     joy->num_axes = joy->num_buttons = 0;
1096     joy->name[ 0 ] = '\0';
1097
1098 #if TARGET_HOST_MACINTOSH
1099     /* XXX FIXME: get joystick name in Mac */
1100
1101     err = ISpStartup( );
1102
1103     if( err == noErr )
1104     {
1105 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
1106
1107         joy->error = GL_TRUE;
1108
1109         /* initialize the needs structure */
1110         ISpNeed temp_isp_needs[ isp_num_needs ] =
1111         {
1112           { "\pX-Axis",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1113           { "\pY-Axis",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1114           { "\pZ-Axis",    128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1115           { "\pR-Axis",    128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1116           { "\pAxis   4",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1117           { "\pAxis   5",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1118           { "\pAxis   6",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1119           { "\pAxis   7",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1120           { "\pAxis   8",  128, 0, 0, kISpElementKind_Axis,   kISpElementLabel_None, 0, 0, 0, 0 },
1121
1122           { "\pButton 0",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1123           { "\pButton 1",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1124           { "\pButton 2",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1125           { "\pButton 3",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1126           { "\pButton 4",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1127           { "\pButton 5",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1128           { "\pButton 6",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1129           { "\pButton 7",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1130           { "\pButton 8",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1131           { "\pButton 9",  128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1132           { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1133           { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1134           { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1135           { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1136           { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1137           { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1138           { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1139           { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1140           { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1141           { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1142           { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1143           { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1144           { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1145           { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1146           { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1147           { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1148           { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1149           { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1150           { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1151           { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1152           { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1153           { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
1154         };
1155
1156         memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
1157
1158
1159         /* next two calls allow keyboard and mouse to emulate other input
1160          * devices (gamepads, joysticks, etc)
1161          */
1162         /*
1163           err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
1164           ISP_CHECK_ERR(err)
1165
1166
1167           err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
1168           ISP_CHECK_ERR(err)
1169         */
1170
1171         err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
1172                                               joy->isp_needs, joy->isp_elem,
1173                                               0 );
1174         ISP_CHECK_ERR( err )
1175
1176         err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
1177                        'freeglut', nil, 0, 128, 0 );
1178         ISP_CHECK_ERR( err )
1179
1180         joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
1181         joy->num_axes    = joy->isp_num_axis;
1182
1183         for( i = 0; i < joy->num_axes; i++ )
1184         {
1185             joy->dead_band[ i ] = 0;
1186             joy->saturate [ i ] = 1;
1187             joy->center   [ i ] = kISpAxisMiddle;
1188             joy->max      [ i ] = kISpAxisMaximum;
1189             joy->min      [ i ] = kISpAxisMinimum;
1190         }
1191
1192         joy->error = GL_FALSE;
1193     }
1194     else
1195         joy->num_buttons = joy->num_axes = 0;
1196 #endif
1197
1198 #if TARGET_HOST_MAC_OSX
1199     if( joy->id >= numDevices )
1200     {
1201         fgWarning( "device index out of range in fgJoystickOpen()" );
1202         return;
1203     }
1204
1205     /* create device interface */
1206     rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
1207                                             kIOHIDDeviceUserClientTypeID,
1208                                             kIOCFPlugInInterfaceID,
1209                                             &plugin, &score );
1210
1211     if( rv != kIOReturnSuccess )
1212     {
1213         fgWarning( "error creating plugin for io device" );
1214         return;
1215     }
1216
1217     pluginResult = ( *plugin )->QueryInterface(
1218         plugin,
1219         CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
1220         &( LPVOID )joy->hidDev
1221     );
1222
1223     if( pluginResult != S_OK )
1224         fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
1225
1226     ( *plugin )->Release( plugin ); /* don't leak a ref */
1227     if( joy->hidDev == NULL )
1228         return;
1229
1230     /* store the interface in this instance */
1231     rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
1232     if( rv != kIOReturnSuccess )
1233     {
1234         fgWarning( "error opening device interface");
1235         return;
1236     }
1237
1238     props = getCFProperties( ioDevices[ joy->id ] );
1239
1240     /* recursively enumerate all the bits */
1241     CFTypeRef topLevelElement =
1242         CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
1243     enumerateElements( topLevelElement );
1244
1245     CFRelease( props );
1246 #endif
1247
1248 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
1249     joy->js.dwFlags = JOY_RETURNALL;
1250     joy->js.dwSize  = sizeof( joy->js );
1251
1252     memset( &joy->jsCaps, 0, sizeof( joy->jsCaps ) );
1253
1254     joy->error =
1255         ( joyGetDevCaps( joy->js_id, &joy->jsCaps, sizeof( joy->jsCaps ) ) !=
1256           JOYERR_NOERROR );
1257
1258     if( joy->jsCaps.wNumAxes == 0 )
1259     {
1260         joy->num_axes = 0;
1261         joy->error = GL_TRUE;
1262     }
1263     else
1264     {
1265         /* Device name from jsCaps is often "Microsoft PC-joystick driver",
1266          * at least for USB.  Try to get the real name from the registry.
1267          */
1268         if ( ! fghJoystickGetOEMProductName( joy, joy->name,
1269                                              sizeof( joy->name ) ) )
1270         {
1271             fgWarning( "JS: Failed to read joystick name from registry" );
1272             strncpy( joy->name, joy->jsCaps.szPname, sizeof( joy->name ) );
1273         }
1274
1275         /* Windows joystick drivers may provide any combination of
1276          * X,Y,Z,R,U,V,POV - not necessarily the first n of these.
1277          */
1278         if( joy->jsCaps.wCaps & JOYCAPS_HASPOV )
1279         {
1280             joy->num_axes = _JS_MAX_AXES;
1281             joy->min[ 7 ] = -1.0; joy->max[ 7 ] = 1.0;  /* POV Y */
1282             joy->min[ 6 ] = -1.0; joy->max[ 6 ] = 1.0;  /* POV X */
1283         }
1284         else
1285             joy->num_axes = 6;
1286
1287         joy->min[ 5 ] = ( float )joy->jsCaps.wVmin;
1288         joy->max[ 5 ] = ( float )joy->jsCaps.wVmax;
1289         joy->min[ 4 ] = ( float )joy->jsCaps.wUmin;
1290         joy->max[ 4 ] = ( float )joy->jsCaps.wUmax;
1291         joy->min[ 3 ] = ( float )joy->jsCaps.wRmin;
1292         joy->max[ 3 ] = ( float )joy->jsCaps.wRmax;
1293         joy->min[ 2 ] = ( float )joy->jsCaps.wZmin;
1294         joy->max[ 2 ] = ( float )joy->jsCaps.wZmax;
1295         joy->min[ 1 ] = ( float )joy->jsCaps.wYmin;
1296         joy->max[ 1 ] = ( float )joy->jsCaps.wYmax;
1297         joy->min[ 0 ] = ( float )joy->jsCaps.wXmin;
1298         joy->max[ 0 ] = ( float )joy->jsCaps.wXmax;
1299     }
1300
1301     /* Guess all the rest judging on the axes extremals */
1302     for( i = 0; i < joy->num_axes; i++ )
1303     {
1304         joy->center   [ i ] = ( joy->max[ i ] + joy->min[ i ] ) * 0.5f;
1305         joy->dead_band[ i ] = 0.0f;
1306         joy->saturate [ i ] = 1.0f;
1307     }
1308 #endif
1309
1310 #if TARGET_HOST_POSIX_X11
1311 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
1312     for( i = 0; i < _JS_MAX_AXES; i++ )
1313         joy->os->cache_axes[ i ] = 0.0f;
1314
1315     joy->os->cache_buttons = 0;
1316
1317     joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
1318
1319 #ifdef HAVE_ERRNO_H
1320     if( joy->os->fd < 0 && errno == EACCES )
1321         fgWarning ( "%s exists but is not readable by you", joy->os->fname );
1322 #endif
1323
1324     joy->error =( joy->os->fd < 0 );
1325
1326     if( joy->error )
1327         return;
1328
1329     joy->num_axes = 0;
1330     joy->num_buttons = 0;
1331     if( joy->os->is_analog )
1332     {
1333         FILE *joyfile;
1334         char joyfname[ 1024 ];
1335         int noargs, in_no_axes;
1336
1337         float axes [ _JS_MAX_AXES ];
1338         int buttons[ _JS_MAX_AXES ];
1339
1340         joy->num_axes    =  2;
1341         joy->num_buttons = 32;
1342
1343         fghJoystickRawRead( joy, buttons, axes );
1344         joy->error = axes[ 0 ] < -1000000000.0f;
1345         if( joy->error )
1346             return;
1347
1348         snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
1349
1350         joyfile = fopen( joyfname, "r" );
1351         joy->error =( joyfile == NULL );
1352         if( joy->error )
1353             return;
1354
1355         noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
1356                          &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
1357                          &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
1358         joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
1359         fclose( joyfile );
1360         if( joy->error )
1361             return;
1362
1363         for( i = 0; i < _JS_MAX_AXES; i++ )
1364         {
1365             joy->dead_band[ i ] = 0.0f;
1366             joy->saturate [ i ] = 1.0f;
1367         }
1368
1369         return;    /* End of analog code */
1370     }
1371
1372 #    ifdef HAVE_USB_JS
1373     if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
1374                                     &joy->num_buttons ) )
1375     {
1376         close( joy->os->fd );
1377         joy->error = GL_TRUE;
1378         return;
1379     }
1380
1381     cp = strrchr( joy->os->fname, '/' );
1382     if( cp )
1383     {
1384         if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
1385             0 )
1386             strcpy( joy->name, &cp[1] );
1387     }
1388
1389     if( joy->num_axes > _JS_MAX_AXES )
1390         joy->num_axes = _JS_MAX_AXES;
1391
1392     for( i = 0; i < _JS_MAX_AXES; i++ )
1393     {
1394         /* We really should get this from the HID, but that data seems
1395          * to be quite unreliable for analog-to-USB converters. Punt for
1396          * now.
1397          */
1398         if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
1399         {
1400             joy->max   [ i ] = 1.0f;
1401             joy->center[ i ] = 0.0f;
1402             joy->min   [ i ] = -1.0f;
1403         }
1404         else
1405         {
1406             joy->max   [ i ] = 255.0f;
1407             joy->center[ i ] = 127.0f;
1408             joy->min   [ i ] = 0.0f;
1409         }
1410
1411         joy->dead_band[ i ] = 0.0f;
1412         joy->saturate[ i ] = 1.0f;
1413     }
1414 #    endif
1415 #endif
1416
1417 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
1418     /* Default for older Linux systems. */
1419     joy->num_axes    =  2;
1420     joy->num_buttons = 32;
1421
1422 #    ifdef JS_NEW
1423     for( i = 0; i < _JS_MAX_AXES; i++ )
1424         joy->tmp_axes[ i ] = 0.0f;
1425
1426     joy->tmp_buttons = 0;
1427 #    endif
1428
1429     joy->fd = open( joy->fname, O_RDONLY );
1430
1431     joy->error =( joy->fd < 0 );
1432
1433     if( joy->error )
1434         return;
1435
1436     /* Set the correct number of axes for the linux driver */
1437 #    ifdef JS_NEW
1438     /* Melchior Franz's fixes for big-endian Linuxes since writing
1439      *  to the upper byte of an uninitialized word doesn't work.
1440      *  9 April 2003
1441      */
1442     ioctl( joy->fd, JSIOCGAXES, &u );
1443     joy->num_axes = u;
1444     ioctl( joy->fd, JSIOCGBUTTONS, &u );
1445     joy->num_buttons = u;
1446     ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
1447     fcntl( joy->fd, F_SETFL, O_NONBLOCK );
1448 #    endif
1449
1450     /*
1451      * The Linux driver seems to return 512 for all axes
1452      * when no stick is present - but there is a chance
1453      * that could happen by accident - so it's gotta happen
1454      * on both axes for at least 100 attempts.
1455      *
1456      * PWO: shouldn't be that done somehow wiser on the kernel level?
1457      */
1458 #    ifndef JS_NEW
1459     counter = 0;
1460
1461     do
1462     {
1463         fghJoystickRawRead( joy, NULL, joy->center );
1464         counter++;
1465     } while( !joy->error &&
1466              counter < 100 &&
1467              joy->center[ 0 ] == 512.0f &&
1468              joy->center[ 1 ] == 512.0f );
1469
1470     if ( counter >= 100 )
1471         joy->error = GL_TRUE;
1472 #    endif
1473
1474     for( i = 0; i < _JS_MAX_AXES; i++ )
1475     {
1476 #    ifdef JS_NEW
1477         joy->max   [ i ] =  32767.0f;
1478         joy->center[ i ] =      0.0f;
1479         joy->min   [ i ] = -32767.0f;
1480 #    else
1481         joy->max[ i ] = joy->center[ i ] * 2.0f;
1482         joy->min[ i ] = 0.0f;
1483 #    endif
1484         joy->dead_band[ i ] = 0.0f;
1485         joy->saturate [ i ] = 1.0f;
1486     }
1487 #endif
1488 #endif
1489 }
1490
1491 /*
1492  * This function replaces the constructor method in the JS library.
1493  */
1494 static void fghJoystickInit( int ident )
1495 {
1496     if( ident >= MAX_NUM_JOYSTICKS )
1497       fgError( "Too large a joystick number: %d", ident );
1498
1499     if( fgJoystick[ ident ] )
1500         fgError( "illegal attempt to initialize joystick device again" );
1501
1502     fgJoystick[ ident ] =
1503         ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
1504
1505     /* Set defaults */
1506     fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
1507     fgJoystick[ ident ]->error = GL_TRUE;
1508
1509 #if TARGET_HOST_MACINTOSH
1510     fgJoystick[ ident ]->id = ident;
1511     snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
1512     fgJoystick[ ident ]->error = GL_FALSE;
1513 #endif
1514
1515 #if TARGET_HOST_MAC_OSX
1516     fgJoystick[ ident ]->id = ident;
1517     fgJoystick[ ident ]->error = GL_FALSE;
1518     fgJoystick[ ident ]->num_axes = 0;
1519     fgJoystick[ ident ]->num_buttons = 0;
1520
1521     if( numDevices < 0 )
1522     {
1523         /* do first-time init (since we can't over-ride jsInit, hmm */
1524         numDevices = 0;
1525
1526         mach_port_t masterPort;
1527         IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
1528         if( rv != kIOReturnSuccess )
1529         {
1530             fgWarning( "error getting master Mach port" );
1531             return;
1532         }
1533         fghJoystickFindDevices( masterPort );
1534     }
1535
1536     if ( ident >= numDevices )
1537     {
1538         fgJoystick[ ident ]->error = GL_TRUE;
1539         return;
1540     }
1541
1542     /* get the name now too */
1543     CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
1544     CFTypeRef ref = CFDictionaryGetValue( properties,
1545                                           CFSTR( kIOHIDProductKey ) );
1546     if (!ref)
1547         ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
1548
1549     if( !ref ||
1550         !CFStringGetCString( ( CFStringRef )ref, name, 128,
1551                              CFStringGetSystemEncoding( ) ) )
1552     {
1553         fgWarning( "error getting device name" );
1554         name[ 0 ] = '\0';
1555     }
1556 #endif
1557
1558 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
1559     switch( ident )
1560     {
1561     case 0:
1562         fgJoystick[ ident ]->js_id = JOYSTICKID1;
1563         fgJoystick[ ident ]->error = GL_FALSE;
1564         break;
1565     case 1:
1566         fgJoystick[ ident ]->js_id = JOYSTICKID2;
1567         fgJoystick[ ident ]->error = GL_FALSE;
1568         break;
1569     default:
1570         fgJoystick[ ident ]->num_axes = 0;
1571         fgJoystick[ ident ]->error = GL_TRUE;
1572         return;
1573     }
1574 #endif
1575
1576 #if TARGET_HOST_POSIX_X11
1577 #    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
1578     fgJoystick[ ident ]->id = ident;
1579     fgJoystick[ ident ]->error = GL_FALSE;
1580
1581     fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
1582     memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
1583     if( ident < USB_IDENT_OFFSET )
1584         fgJoystick[ ident ]->os->is_analog = 1;
1585     if( fgJoystick[ ident ]->os->is_analog )
1586         snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
1587     else
1588         snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
1589                  ident - USB_IDENT_OFFSET );
1590 #    elif defined( __linux__ )
1591     fgJoystick[ ident ]->id = ident;
1592     fgJoystick[ ident ]->error = GL_FALSE;
1593
1594     snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
1595
1596     if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
1597         snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
1598 #    endif
1599 #endif
1600
1601     fghJoystickOpen( fgJoystick[ ident  ] );
1602 }
1603
1604 /*
1605  * Try initializing all the joysticks (well, both of them)
1606  */
1607 void fgInitialiseJoysticks ( void )
1608 {
1609     if( !fgState.JoysticksInitialised )
1610     {
1611         int ident ;
1612         for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
1613             fghJoystickInit( ident );
1614
1615         fgState.JoysticksInitialised = GL_TRUE;
1616     }
1617 }
1618
1619 /*
1620  *
1621  */
1622 void fgJoystickClose( void )
1623 {
1624     int ident ;
1625     for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
1626     {
1627         if( fgJoystick[ ident ] )
1628         {
1629
1630 #if TARGET_HOST_MACINTOSH
1631             ISpSuspend( );
1632             ISpStop( );
1633             ISpShutdown( );
1634 #endif
1635
1636 #if TARGET_HOST_MAC_OSX
1637             ( *( fgJoystick[ ident ]->hidDev ) )->
1638                 close( fgJoystick[ ident ]->hidDev );
1639 #endif
1640
1641 #if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE)
1642             /* Do nothing special */
1643 #endif
1644
1645 #if TARGET_HOST_POSIX_X11
1646 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
1647             if( fgJoystick[ident]->os )
1648             {
1649                 if( ! fgJoystick[ ident ]->error )
1650                     close( fgJoystick[ ident ]->os->fd );
1651 #ifdef HAVE_USB_JS
1652                 if( fgJoystick[ ident ]->os->hids )
1653                     free (fgJoystick[ ident ]->os->hids);
1654                 if( fgJoystick[ ident ]->os->hid_data_buf )
1655                     free( fgJoystick[ ident ]->os->hid_data_buf );
1656 #endif
1657                 free( fgJoystick[ident]->os );
1658             }
1659 #endif
1660
1661             if( ! fgJoystick[ident]->error )
1662                 close( fgJoystick[ ident ]->fd );
1663 #endif
1664
1665             free( fgJoystick[ ident ] );
1666             fgJoystick[ ident ] = NULL;
1667             /* show joystick has been deinitialized */
1668         }
1669     }
1670 }
1671
1672 /*
1673  * Polls the joystick and executes the joystick callback hooked to the
1674  * window specified in the function's parameter:
1675  */
1676 void fgJoystickPollWindow( SFG_Window* window )
1677 {
1678     float axes[ _JS_MAX_AXES ];
1679     int buttons;
1680     int ident;
1681
1682     freeglut_return_if_fail( window );
1683     freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
1684
1685     for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
1686     {
1687         if( fgJoystick[ident] )
1688         {
1689             fghJoystickRead( fgJoystick[ident], &buttons, axes );
1690
1691             if( !fgJoystick[ident]->error )
1692                 INVOKE_WCB( *window, Joystick,
1693                             ( buttons,
1694                               (int) ( axes[ 0 ] * 1000.0f ),
1695                               (int) ( axes[ 1 ] * 1000.0f ),
1696                               (int) ( axes[ 2 ] * 1000.0f ) )
1697                 );
1698         }
1699     }
1700 }
1701
1702 /*
1703  * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
1704  */
1705 int fgJoystickDetect( void )
1706 {
1707     int ident;
1708
1709     fgInitialiseJoysticks ();
1710
1711     if ( !fgState.JoysticksInitialised )
1712         return 0;
1713
1714     for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
1715         if( fgJoystick[ident] && !fgJoystick[ident]->error )
1716             return 1;
1717
1718     return 0;
1719 }
1720
1721 /*
1722  * Joystick information functions
1723  */
1724 int  glutJoystickGetNumAxes( int ident )
1725 {
1726     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
1727     return fgJoystick[ ident ]->num_axes;
1728 }
1729 int  glutJoystickGetNumButtons( int ident )
1730 {
1731     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
1732     return fgJoystick[ ident ]->num_buttons;
1733 }
1734 int  glutJoystickNotWorking( int ident )
1735 {
1736     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
1737     return fgJoystick[ ident ]->error;
1738 }
1739
1740 float glutJoystickGetDeadBand( int ident, int axis )
1741 {
1742     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
1743     return fgJoystick[ ident ]->dead_band [ axis ];
1744 }
1745 void  glutJoystickSetDeadBand( int ident, int axis, float db )
1746 {
1747     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
1748     fgJoystick[ ident ]->dead_band[ axis ] = db;
1749 }
1750
1751 float glutJoystickGetSaturation( int ident, int axis )
1752 {
1753     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
1754     return fgJoystick[ ident ]->saturate[ axis ];
1755 }
1756 void  glutJoystickSetSaturation( int ident, int axis, float st )
1757 {
1758     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
1759     fgJoystick[ ident ]->saturate [ axis ] = st;
1760 }
1761
1762 void glutJoystickSetMinRange( int ident, float *axes )
1763 {
1764     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
1765     memcpy( fgJoystick[ ident ]->min, axes,
1766             fgJoystick[ ident ]->num_axes * sizeof( float ) );
1767 }
1768 void glutJoystickSetMaxRange( int ident, float *axes )
1769 {
1770     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
1771     memcpy( fgJoystick[ ident ]->max, axes,
1772             fgJoystick[ ident ]->num_axes * sizeof( float ) );
1773 }
1774 void glutJoystickSetCenter( int ident, float *axes )
1775 {
1776     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
1777     memcpy( fgJoystick[ ident ]->center, axes,
1778             fgJoystick[ ident ]->num_axes * sizeof( float ) );
1779 }
1780
1781 void glutJoystickGetMinRange( int ident, float *axes )
1782 {
1783     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
1784     memcpy( axes, fgJoystick[ ident ]->min,
1785             fgJoystick[ ident ]->num_axes * sizeof( float ) );
1786 }
1787 void glutJoystickGetMaxRange( int ident, float *axes )
1788 {
1789     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
1790     memcpy( axes, fgJoystick[ ident ]->max,
1791             fgJoystick[ ident ]->num_axes * sizeof( float ) );
1792 }
1793 void glutJoystickGetCenter( int ident, float *axes )
1794 {
1795     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
1796     memcpy( axes, fgJoystick[ ident ]->center,
1797             fgJoystick[ ident ]->num_axes * sizeof( float ) );
1798 }
1799
1800 /*** END OF FILE ***/