Removing an extraneous "#if TARGET_HOST"
[freeglut] / src / x11 / freeglut_joystick_x11.c
1 /*\r
2  * freeglut_joystick_x11.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  * Copied for Platform code by Evan Felix <karcaw at gmail.com>\r
9  * Creation date: Thur Feb 2 2012\r
10  *\r
11  * Permission is hereby granted, free of charge, to any person obtaining a\r
12  * copy of this software and associated documentation files (the "Software"),\r
13  * to deal in the Software without restriction, including without limitation\r
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
15  * and/or sell copies of the Software, and to permit persons to whom the\r
16  * Software is furnished to do so, subject to the following conditions:\r
17  *\r
18  * The above copyright notice and this permission notice shall be included\r
19  * in all copies or substantial portions of the Software.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
24  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
25  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27  */\r
28 \r
29 /*\r
30  * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>\r
31  *\r
32  * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.\r
33  *  Many thanks for Steve Baker for permission to pull from that library.\r
34  */\r
35 \r
36 #include <GL/freeglut.h>\r
37 #include "../Common/freeglut_internal.h"\r
38 #ifdef HAVE_SYS_PARAM_H\r
39 #    include <sys/param.h>\r
40 #endif\r
41 \r
42 \r
43 /*this should be defined in a header file */\r
44 #define MAX_NUM_JOYSTICKS  2   \r
45 extern SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];\r
46 \r
47 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
48 {\r
49     int status;\r
50 \r
51     int i;\r
52 \r
53 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
54     int len;\r
55 \r
56     if ( joy->pJoystick.os->is_analog )\r
57     {\r
58         int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) );\r
59         if ( status != sizeof(joy->pJoystick.os->ajs) ) {\r
60             perror ( joy->pJoystick.os->fname );\r
61             joy->error = GL_TRUE;\r
62             return;\r
63         }\r
64         if ( buttons != NULL )\r
65             *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );\r
66 \r
67         if ( axes != NULL )\r
68         {\r
69             axes[0] = (float) joy->pJoystick.os->ajs.x;\r
70             axes[1] = (float) joy->pJoystick.os->ajs.y;\r
71         }\r
72 \r
73         return;\r
74     }\r
75 \r
76 #  ifdef HAVE_USB_JS\r
77     while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen )\r
78     {\r
79         struct hid_item *h;\r
80 \r
81         for  ( h = joy->pJoystick.os->hids; h; h = h->next )\r
82         {\r
83             int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );\r
84 \r
85             int page = HID_PAGE ( h->usage );\r
86             int usage = HID_USAGE ( h->usage );\r
87 \r
88             if ( page == HUP_GENERIC_DESKTOP )\r
89             {\r
90                 int i;\r
91                 for ( i = 0; i < joy->num_axes; i++ )\r
92                     if (joy->pJoystick.os->axes_usage[i] == usage)\r
93                     {\r
94                         if (usage == HUG_HAT_SWITCH)\r
95                         {\r
96                             if (d < 0 || d > 8)\r
97                                 d = 0;  /* safety */\r
98                             joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d];\r
99                             joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d];\r
100                         }\r
101                         else\r
102                         {\r
103                             joy->pJoystick.os->cache_axes[i] = (float)d;\r
104                         }\r
105                         break;\r
106                     }\r
107             }\r
108             else if (page == HUP_BUTTON)\r
109             {\r
110                if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)\r
111                {\r
112                    if (d)\r
113                        joy->pJoystick.os->cache_buttons |=  (1 << ( usage - 1 ));\r
114                    else\r
115                        joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));\r
116                }\r
117             }\r
118         }\r
119     }\r
120 #    ifdef HAVE_ERRNO_H\r
121     if ( len < 0 && errno != EAGAIN )\r
122 #    else\r
123     if ( len < 0 )\r
124 #    endif\r
125     {\r
126         perror( joy->pJoystick.os->fname );\r
127         joy->error = 1;\r
128     }\r
129     if ( buttons != NULL ) *buttons = joy->pJoystick.os->cache_buttons;\r
130     if ( axes    != NULL )\r
131         memcpy ( axes, joy->pJoystick.os->cache_axes, sizeof(float) * joy->num_axes );\r
132 #  endif\r
133 #endif\r
134 \r
135 #ifdef JS_NEW\r
136 \r
137     while ( 1 )\r
138     {\r
139         status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) );\r
140 \r
141         if ( status != sizeof( struct js_event ) )\r
142         {\r
143 #  ifdef HAVE_ERRNO_H\r
144             if ( errno == EAGAIN )\r
145             {\r
146                 /* Use the old values */\r
147                 if ( buttons )\r
148                     *buttons = joy->pJoystick.tmp_buttons;\r
149                 if ( axes )\r
150                     memcpy( axes, joy->pJoystick.tmp_axes,\r
151                             sizeof( float ) * joy->num_axes );\r
152                 return;\r
153             }\r
154 #  endif\r
155 \r
156             fgWarning ( "%s", joy->pJoystick.fname );\r
157             joy->error = GL_TRUE;\r
158             return;\r
159         }\r
160 \r
161         switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT )\r
162         {\r
163         case JS_EVENT_BUTTON:\r
164             if( joy->pJoystick.js.value == 0 ) /* clear the flag */\r
165                 joy->pJoystick.tmp_buttons &= ~( 1 << joy->pJoystick.js.number );\r
166             else\r
167                 joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number );\r
168             break;\r
169 \r
170         case JS_EVENT_AXIS:\r
171             if ( joy->pJoystick.js.number < joy->num_axes )\r
172             {\r
173                 joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value;\r
174 \r
175                 if( axes )\r
176                     memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );\r
177             }\r
178             break;\r
179 \r
180         default:\r
181             fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );\r
182 \r
183             /* use the old values */\r
184 \r
185             if ( buttons != NULL ) *buttons = joy->pJoystick.tmp_buttons;\r
186             if ( axes    != NULL )\r
187                 memcpy ( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );\r
188 \r
189             return;\r
190         }\r
191 \r
192         if( buttons )\r
193             *buttons = joy->pJoystick.tmp_buttons;\r
194     }\r
195 #else\r
196 \r
197     status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN );\r
198 \r
199     if ( status != JS_RETURN )\r
200     {\r
201         fgWarning( "%s", joy->pJoystick.fname );\r
202         joy->error = GL_TRUE;\r
203         return;\r
204     }\r
205 \r
206     if ( buttons )\r
207 #    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
208         *buttons = ( joy->pJoystick.js.b1 ? 1 : 0 ) | ( joy->pJoystick.js.b2 ? 2 : 0 );  /* XXX Should not be here -- BSD is handled earlier */\r
209 #    else\r
210         *buttons = joy->pJoystick.js.buttons;\r
211 #    endif\r
212 \r
213     if ( axes )\r
214     {\r
215         axes[ 0 ] = (float) joy->pJoystick.js.x;\r
216         axes[ 1 ] = (float) joy->pJoystick.js.y;\r
217     }\r
218 #endif\r
219 }\r
220 \r
221 \r
222 void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
223 {\r
224 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
225         int i = 0;\r
226        char *cp;\r
227 #endif\r
228 #ifdef JS_NEW\r
229        unsigned char u;\r
230         int i=0;\r
231 #else\r
232 #  if defined( __linux__ ) || TARGET_HOST_SOLARIS\r
233         int i = 0;\r
234     int counter = 0;\r
235 #  endif\r
236 #endif\r
237 \r
238 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
239     for( i = 0; i < _JS_MAX_AXES; i++ )\r
240         joy->pJoystick.os->cache_axes[ i ] = 0.0f;\r
241 \r
242     joy->pJoystick.os->cache_buttons = 0;\r
243 \r
244     joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK);\r
245 \r
246 #ifdef HAVE_ERRNO_H\r
247     if( joy->pJoystick.os->fd < 0 && errno == EACCES )\r
248         fgWarning ( "%s exists but is not readable by you", joy->pJoystick.os->fname );\r
249 #endif\r
250 \r
251     joy->error =( joy->pJoystick.os->fd < 0 );\r
252 \r
253     if( joy->error )\r
254         return;\r
255 \r
256     joy->num_axes = 0;\r
257     joy->num_buttons = 0;\r
258     if( joy->pJoystick.os->is_analog )\r
259     {\r
260         FILE *joyfile;\r
261         char joyfname[ 1024 ];\r
262         int noargs, in_no_axes;\r
263 \r
264         float axes [ _JS_MAX_AXES ];\r
265         int buttons[ _JS_MAX_AXES ];\r
266 \r
267         joy->num_axes    =  2;\r
268         joy->num_buttons = 32;\r
269 \r
270         fghJoystickRawRead( joy, buttons, axes );\r
271         joy->error = axes[ 0 ] < -1000000000.0f;\r
272         if( joy->error )\r
273             return;\r
274 \r
275         snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );\r
276 \r
277         joyfile = fopen( joyfname, "r" );\r
278         joy->error =( joyfile == NULL );\r
279         if( joy->error )\r
280             return;\r
281 \r
282         noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,\r
283                          &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],\r
284                          &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );\r
285         joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;\r
286         fclose( joyfile );\r
287         if( joy->error )\r
288             return;\r
289 \r
290         for( i = 0; i < _JS_MAX_AXES; i++ )\r
291         {\r
292             joy->dead_band[ i ] = 0.0f;\r
293             joy->saturate [ i ] = 1.0f;\r
294         }\r
295 \r
296         return;    /* End of analog code */\r
297     }\r
298 \r
299 #    ifdef HAVE_USB_JS\r
300     if( ! fghJoystickInitializeHID( joy->pJoystick.os, &joy->num_axes,\r
301                                     &joy->num_buttons ) )\r
302     {\r
303         close( joy->pJoystick.os->fd );\r
304         joy->error = GL_TRUE;\r
305         return;\r
306     }\r
307 \r
308     cp = strrchr( joy->pJoystick.os->fname, '/' );\r
309     if( cp )\r
310     {\r
311         if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==\r
312             0 )\r
313             strcpy( joy->name, &cp[1] );\r
314     }\r
315 \r
316     if( joy->num_axes > _JS_MAX_AXES )\r
317         joy->num_axes = _JS_MAX_AXES;\r
318 \r
319     for( i = 0; i < _JS_MAX_AXES; i++ )\r
320     {\r
321         /* We really should get this from the HID, but that data seems\r
322          * to be quite unreliable for analog-to-USB converters. Punt for\r
323          * now.\r
324          */\r
325         if( joy->pJoystick.os->axes_usage[ i ] == HUG_HAT_SWITCH )\r
326         {\r
327             joy->max   [ i ] = 1.0f;\r
328             joy->center[ i ] = 0.0f;\r
329             joy->min   [ i ] = -1.0f;\r
330         }\r
331         else\r
332         {\r
333             joy->max   [ i ] = 255.0f;\r
334             joy->center[ i ] = 127.0f;\r
335             joy->min   [ i ] = 0.0f;\r
336         }\r
337 \r
338         joy->dead_band[ i ] = 0.0f;\r
339         joy->saturate[ i ] = 1.0f;\r
340     }\r
341 #    endif\r
342 #endif\r
343 \r
344 #if defined( __linux__ ) || TARGET_HOST_SOLARIS\r
345     /* Default for older Linux systems. */\r
346     joy->num_axes    =  2;\r
347     joy->num_buttons = 32;\r
348 \r
349 #    ifdef JS_NEW\r
350     for( i = 0; i < _JS_MAX_AXES; i++ )\r
351         joy->pJoystick.tmp_axes[ i ] = 0.0f;\r
352 \r
353     joy->pJoystick.tmp_buttons = 0;\r
354 #    endif\r
355 \r
356     joy->pJoystick.fd = open( joy->pJoystick.fname, O_RDONLY );\r
357 \r
358     joy->error =( joy->pJoystick.fd < 0 );\r
359 \r
360     if( joy->error )\r
361         return;\r
362 \r
363     /* Set the correct number of axes for the linux driver */\r
364 #    ifdef JS_NEW\r
365     /* Melchior Franz's fixes for big-endian Linuxes since writing\r
366      *  to the upper byte of an uninitialized word doesn't work.\r
367      *  9 April 2003\r
368      */\r
369     ioctl( joy->pJoystick.fd, JSIOCGAXES, &u );\r
370     joy->num_axes = u;\r
371     ioctl( joy->pJoystick.fd, JSIOCGBUTTONS, &u );\r
372     joy->num_buttons = u;\r
373     ioctl( joy->pJoystick.fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );\r
374     fcntl( joy->pJoystick.fd, F_SETFL, O_NONBLOCK );\r
375 #    endif\r
376 \r
377     /*\r
378      * The Linux driver seems to return 512 for all axes\r
379      * when no stick is present - but there is a chance\r
380      * that could happen by accident - so it's gotta happen\r
381      * on both axes for at least 100 attempts.\r
382      *\r
383      * PWO: shouldn't be that done somehow wiser on the kernel level?\r
384      */\r
385 #    ifndef JS_NEW\r
386     counter = 0;\r
387 \r
388     do\r
389     {\r
390         fghJoystickRawRead( joy, NULL, joy->center );\r
391         counter++;\r
392     } while( !joy->error &&\r
393              counter < 100 &&\r
394              joy->center[ 0 ] == 512.0f &&\r
395              joy->center[ 1 ] == 512.0f );\r
396 \r
397     if ( counter >= 100 )\r
398         joy->error = GL_TRUE;\r
399 #    endif\r
400 \r
401     for( i = 0; i < _JS_MAX_AXES; i++ )\r
402     {\r
403 #    ifdef JS_NEW\r
404         joy->max   [ i ] =  32767.0f;\r
405         joy->center[ i ] =      0.0f;\r
406         joy->min   [ i ] = -32767.0f;\r
407 #    else\r
408         joy->max[ i ] = joy->center[ i ] * 2.0f;\r
409         joy->min[ i ] = 0.0f;\r
410 #    endif\r
411         joy->dead_band[ i ] = 0.0f;\r
412         joy->saturate [ i ] = 1.0f;\r
413     }\r
414 #endif\r
415 }\r
416 \r
417 \r
418 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
419 {\r
420 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
421     fgJoystick[ ident ]->id = ident;\r
422     fgJoystick[ ident ]->error = GL_FALSE;\r
423 \r
424     fgJoystick[ ident ]->pJoystick.os = calloc( 1, sizeof( struct os_specific_s ) );\r
425     memset( fgJoystick[ ident ]->pJoystick.os, 0, sizeof( struct os_specific_s ) );\r
426     if( ident < USB_IDENT_OFFSET )\r
427         fgJoystick[ ident ]->pJoystick.os->is_analog = 1;\r
428     if( fgJoystick[ ident ]->pJoystick.os->is_analog )\r
429         snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", AJSDEV, ident );\r
430     else\r
431         snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", UHIDDEV,\r
432                  ident - USB_IDENT_OFFSET );\r
433 #elif defined( __linux__ )\r
434     fgJoystick[ ident ]->id = ident;\r
435     fgJoystick[ ident ]->error = GL_FALSE;\r
436 \r
437     snprintf( fgJoystick[ident]->pJoystick.fname, sizeof(fgJoystick[ident]->pJoystick.fname), "/dev/input/js%d", ident );\r
438 \r
439     if( access( fgJoystick[ ident ]->pJoystick.fname, F_OK ) != 0 )\r
440         snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident );\r
441 #endif\r
442 }\r
443 \r
444 \r
445 void fgPlatformJoystickClose ( int ident )\r
446 {\r
447 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )\r
448     if( fgJoystick[ident]->pJoystick.os )\r
449     {\r
450         if( ! fgJoystick[ ident ]->error )\r
451             close( fgJoystick[ ident ]->pJoystick.os->fd );\r
452 #ifdef HAVE_USB_JS\r
453         if( fgJoystick[ ident ]->pJoystick.os->hids )\r
454             free (fgJoystick[ ident ]->pJoystick.os->hids);\r
455         if( fgJoystick[ ident ]->pJoystick.os->hid_data_buf )\r
456             free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf );\r
457 #endif\r
458         free( fgJoystick[ident]->pJoystick.os );\r
459         }\r
460 #endif\r
461 \r
462     if( ! fgJoystick[ident]->error )\r
463          close( fgJoystick[ ident ]->pJoystick.fd );\r
464 }\r
465 \r