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