2 * freeglut_joystick_x11.c
\r
4 * Joystick handling code
\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
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
18 * The above copyright notice and this permission notice shall be included
\r
19 * in all copies or substantial portions of the Software.
\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
30 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
\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
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
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
47 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
53 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
56 if ( joy->pJoystick.os->is_analog )
\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
64 if ( buttons != NULL )
\r
65 *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );
\r
69 axes[0] = (float) joy->pJoystick.os->ajs.x;
\r
70 axes[1] = (float) joy->pJoystick.os->ajs.y;
\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
81 for ( h = joy->pJoystick.os->hids; h; h = h->next )
\r
83 int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );
\r
85 int page = HID_PAGE ( h->usage );
\r
86 int usage = HID_USAGE ( h->usage );
\r
88 if ( page == HUP_GENERIC_DESKTOP )
\r
91 for ( i = 0; i < joy->num_axes; i++ )
\r
92 if (joy->pJoystick.os->axes_usage[i] == usage)
\r
94 if (usage == HUG_HAT_SWITCH)
\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
103 joy->pJoystick.os->cache_axes[i] = (float)d;
\r
108 else if (page == HUP_BUTTON)
\r
110 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
113 joy->pJoystick.os->cache_buttons |= (1 << ( usage - 1 ));
\r
115 joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
120 # ifdef HAVE_ERRNO_H
\r
121 if ( len < 0 && errno != EAGAIN )
\r
126 perror( joy->pJoystick.os->fname );
\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
139 status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) );
\r
141 if ( status != sizeof( struct js_event ) )
\r
143 # ifdef HAVE_ERRNO_H
\r
144 if ( errno == EAGAIN )
\r
146 /* Use the old values */
\r
148 *buttons = joy->pJoystick.tmp_buttons;
\r
150 memcpy( axes, joy->pJoystick.tmp_axes,
\r
151 sizeof( float ) * joy->num_axes );
\r
156 fgWarning ( "%s", joy->pJoystick.fname );
\r
157 joy->error = GL_TRUE;
\r
161 switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT )
\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
167 joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number );
\r
170 case JS_EVENT_AXIS:
\r
171 if ( joy->pJoystick.js.number < joy->num_axes )
\r
173 joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value;
\r
176 memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
\r
181 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
183 /* use the old values */
\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
193 *buttons = joy->pJoystick.tmp_buttons;
\r
197 status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN );
\r
199 if ( status != JS_RETURN )
\r
201 fgWarning( "%s", joy->pJoystick.fname );
\r
202 joy->error = GL_TRUE;
\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
210 *buttons = joy->pJoystick.js.buttons;
\r
215 axes[ 0 ] = (float) joy->pJoystick.js.x;
\r
216 axes[ 1 ] = (float) joy->pJoystick.js.y;
\r
222 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
224 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
232 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\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
242 joy->pJoystick.os->cache_buttons = 0;
\r
244 joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK);
\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
251 joy->error =( joy->pJoystick.os->fd < 0 );
\r
257 joy->num_buttons = 0;
\r
258 if( joy->pJoystick.os->is_analog )
\r
261 char joyfname[ 1024 ];
\r
262 int noargs, in_no_axes;
\r
264 float axes [ _JS_MAX_AXES ];
\r
265 int buttons[ _JS_MAX_AXES ];
\r
268 joy->num_buttons = 32;
\r
270 fghJoystickRawRead( joy, buttons, axes );
\r
271 joy->error = axes[ 0 ] < -1000000000.0f;
\r
275 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
277 joyfile = fopen( joyfname, "r" );
\r
278 joy->error =( joyfile == NULL );
\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
290 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
292 joy->dead_band[ i ] = 0.0f;
\r
293 joy->saturate [ i ] = 1.0f;
\r
296 return; /* End of analog code */
\r
299 # ifdef HAVE_USB_JS
\r
300 if( ! fghJoystickInitializeHID( joy->pJoystick.os, &joy->num_axes,
\r
301 &joy->num_buttons ) )
\r
303 close( joy->pJoystick.os->fd );
\r
304 joy->error = GL_TRUE;
\r
308 cp = strrchr( joy->pJoystick.os->fname, '/' );
\r
311 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
313 strcpy( joy->name, &cp[1] );
\r
316 if( joy->num_axes > _JS_MAX_AXES )
\r
317 joy->num_axes = _JS_MAX_AXES;
\r
319 for( i = 0; i < _JS_MAX_AXES; i++ )
\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
325 if( joy->pJoystick.os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
327 joy->max [ i ] = 1.0f;
\r
328 joy->center[ i ] = 0.0f;
\r
329 joy->min [ i ] = -1.0f;
\r
333 joy->max [ i ] = 255.0f;
\r
334 joy->center[ i ] = 127.0f;
\r
335 joy->min [ i ] = 0.0f;
\r
338 joy->dead_band[ i ] = 0.0f;
\r
339 joy->saturate[ i ] = 1.0f;
\r
344 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
345 /* Default for older Linux systems. */
\r
347 joy->num_buttons = 32;
\r
350 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
351 joy->pJoystick.tmp_axes[ i ] = 0.0f;
\r
353 joy->pJoystick.tmp_buttons = 0;
\r
356 joy->pJoystick.fd = open( joy->pJoystick.fname, O_RDONLY );
\r
358 joy->error =( joy->pJoystick.fd < 0 );
\r
363 /* Set the correct number of axes for the linux driver */
\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
369 ioctl( joy->pJoystick.fd, JSIOCGAXES, &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
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
383 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
390 fghJoystickRawRead( joy, NULL, joy->center );
\r
392 } while( !joy->error &&
\r
394 joy->center[ 0 ] == 512.0f &&
\r
395 joy->center[ 1 ] == 512.0f );
\r
397 if ( counter >= 100 )
\r
398 joy->error = GL_TRUE;
\r
401 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
404 joy->max [ i ] = 32767.0f;
\r
405 joy->center[ i ] = 0.0f;
\r
406 joy->min [ i ] = -32767.0f;
\r
408 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
409 joy->min[ i ] = 0.0f;
\r
411 joy->dead_band[ i ] = 0.0f;
\r
412 joy->saturate [ i ] = 1.0f;
\r
418 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
420 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
421 fgJoystick[ ident ]->id = ident;
\r
422 fgJoystick[ ident ]->error = GL_FALSE;
\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
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
437 snprintf( fgJoystick[ident]->pJoystick.fname, sizeof(fgJoystick[ident]->pJoystick.fname), "/dev/input/js%d", ident );
\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
445 void fgPlatformJoystickClose ( int ident )
\r
447 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
448 if( fgJoystick[ident]->pJoystick.os )
\r
450 if( ! fgJoystick[ ident ]->error )
\r
451 close( fgJoystick[ ident ]->pJoystick.os->fd );
\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
458 free( fgJoystick[ident]->pJoystick.os );
\r
462 if( ! fgJoystick[ident]->error )
\r
463 close( fgJoystick[ ident ]->pJoystick.fd );
\r