2 * freeglut_joystick.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
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
16 * The above copyright notice and this permission notice shall be included
\r
17 * in all copies or substantial portions of the Software.
\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
28 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
\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
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
41 * Initial defines from "js.h" starting around line 33 with the existing "freeglut_joystick.c"
\r
45 #if TARGET_HOST_MACINTOSH
\r
46 # include <InputSprocket.h>
\r
49 #if TARGET_HOST_MAC_OSX
\r
50 # include <mach/mach.h>
\r
51 # include <IOKit/IOkitLib.h>
\r
52 # include <IOKit/hid/IOHIDLib.h>
\r
55 #if TARGET_HOST_POSIX_X11
\r
56 # ifdef HAVE_SYS_IOCTL_H
\r
57 # include <sys/ioctl.h>
\r
59 # ifdef HAVE_FCNTL_H
\r
62 # ifdef HAVE_ERRNO_H
\r
64 # include <string.h>
\r
66 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
67 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
68 # define HAVE_USB_JS 1
\r
70 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
71 # include <sys/joystick.h>
\r
74 * XXX NetBSD/amd64 systems may find that they have to steal the
\r
75 * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
\r
76 * XXX I cannot comment whether that works for the interface, but
\r
77 * XXX it lets you compile...(^& I do not think that we can do away
\r
78 * XXX with this header.
\r
80 # include <machine/joystick.h> /* For analog joysticks */
\r
82 # define JS_DATA_TYPE joystick
\r
83 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
86 # if defined(__linux__)
\r
87 # include <linux/joystick.h>
\r
89 /* check the joystick driver version */
\r
90 # if defined(JS_VERSION) && JS_VERSION >= 0x010000
\r
93 # else /* Not BSD or Linux */
\r
97 * We'll put these values in and that should
\r
98 * allow the code to at least compile when there is
\r
99 * no support. The JS open routine should error out
\r
100 * and shut off all the code downstream anyway and if
\r
101 * the application doesn't use a joystick we'll be fine.
\r
104 struct JS_DATA_TYPE
\r
111 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
119 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
\r
121 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
123 # ifdef HAVE_USB_JS
\r
124 # if defined(__NetBSD__)
\r
125 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
126 # define HAVE_USBHID_H 1
\r
127 # ifdef HAVE_USBHID_H
\r
128 # include <usbhid.h>
\r
132 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
133 # ifdef HAVE_USBHID_H
\r
134 # include <usbhid.h>
\r
136 # include <libusbhid.h>
\r
139 # include <legacy/dev/usb/usb.h>
\r
140 # include <dev/usb/usbhid.h>
\r
142 /* Compatibility with older usb.h revisions */
\r
143 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
\r
144 # define USB_MAX_DEVNAMES MAXDEVNAMES
\r
148 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
\r
149 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
\r
150 struct os_specific_s {
\r
154 /* The following structure members are specific to analog joysticks */
\r
155 struct joystick ajs;
\r
156 # ifdef HAVE_USB_JS
\r
157 /* The following structure members are specific to USB joysticks */
\r
158 struct hid_item *hids;
\r
161 char *hid_data_buf;
\r
162 int axes_usage [ _JS_MAX_AXES ];
\r
164 /* We keep button and axes state ourselves, as they might not be updated
\r
165 * on every read of a USB device
\r
168 float cache_axes [ _JS_MAX_AXES ];
\r
171 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
\r
172 # define USB_IDENT_OFFSET 2
\r
174 # define USBDEV "/dev/usb"
\r
175 # define UHIDDEV "/dev/uhid"
\r
176 # define AJSDEV "/dev/joy"
\r
178 # ifdef HAVE_USB_JS
\r
180 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
\r
181 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
\r
182 * return the uhidN device name. We warn the user of this situation once.
\r
184 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
\r
186 struct usb_device_info di;
\r
190 for (a = 1; a < USB_MAX_DEVICES; a++) {
\r
192 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
\r
194 for (i = 0; i < USB_MAX_DEVNAMES; i++)
\r
195 if (di.udi_devnames[i][0] &&
\r
196 strcmp(di.udi_devnames[i], dev) == 0) {
\r
197 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
\r
198 strcpy(cp, di.udi_vendor);
\r
200 strcat(cp, di.udi_product);
\r
201 strncpy(out, cp, outlen - 1);
\r
202 out[outlen - 1] = 0;
\r
210 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
\r
215 static int protection_warned = 0;
\r
217 for (i = 0; i < 16; i++) {
\r
218 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
\r
219 f = open(buf, O_RDONLY);
\r
221 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
\r
226 #ifdef HAVE_ERRNO_H
\r
227 else if (errno == EACCES) {
\r
228 if (!protection_warned) {
\r
229 fgWarning ( "Can't open %s for read!", buf );
\r
230 protection_warned = 1;
\r
238 static int fghJoystickInitializeHID(struct os_specific_s *os,
\r
239 int *num_axes, int *num_buttons)
\r
241 int size, is_joystick;
\r
242 # ifdef HAVE_USBHID_H
\r
245 struct hid_data *d;
\r
249 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
\r
251 #ifdef HAVE_ERRNO_H
\r
252 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
\r
254 fgWarning ( "error: %s", os->fname );
\r
261 # ifdef HAVE_USBHID_H
\r
262 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
\r
264 /*** XXX {report_id} may not be the right variable? ***/
\r
265 #ifdef HAVE_ERRNO_H
\r
266 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
\r
268 fgWarning ( "error: %s%d", UHIDDEV, report_id );
\r
273 size = hid_report_size( rd, hid_input, report_id );
\r
275 size = hid_report_size( rd, 0, hid_input );
\r
277 os->hid_data_buf = calloc( 1, size );
\r
278 os->hid_dlen = size;
\r
281 # ifdef HAVE_USBHID_H
\r
282 d = hid_start_parse( rd, 1 << hid_input, report_id );
\r
284 d = hid_start_parse( rd, 1 << hid_input );
\r
286 while( hid_get_item( d, &h ) )
\r
288 int usage, page, interesting_hid;
\r
290 page = HID_PAGE( h.usage );
\r
291 usage = HID_USAGE( h.usage );
\r
293 /* This test is somewhat too simplistic, but this is how MicroSoft
\r
294 * does, so I guess it works for all joysticks/game pads. */
\r
295 is_joystick = is_joystick ||
\r
296 ( h.kind == hid_collection &&
\r
297 page == HUP_GENERIC_DESKTOP &&
\r
298 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
\r
300 if( h.kind != hid_input )
\r
306 interesting_hid = TRUE;
\r
307 if( page == HUP_GENERIC_DESKTOP )
\r
318 if( *num_axes < _JS_MAX_AXES )
\r
320 os->axes_usage[ *num_axes ] = usage;
\r
324 case HUG_HAT_SWITCH:
\r
325 /* Allocate two axes for a hat */
\r
326 if( *num_axes + 1 < _JS_MAX_AXES )
\r
328 os->axes_usage[ *num_axes ] = usage;
\r
330 os->axes_usage[ *num_axes ] = usage;
\r
335 interesting_hid = FALSE;
\r
339 else if( page == HUP_BUTTON )
\r
341 interesting_hid = ( usage > 0 ) &&
\r
342 ( usage <= _JS_MAX_BUTTONS );
\r
344 if( interesting_hid && usage - 1 > *num_buttons )
\r
345 *num_buttons = usage - 1;
\r
348 if( interesting_hid )
\r
351 os->hids = calloc( 1, sizeof ( struct hid_item ) );
\r
355 hid_end_parse( d );
\r
357 return os->hids != NULL;
\r
363 * Functions associated with the "jsJoystick" class in PLIB
\r
365 #if TARGET_HOST_MAC_OSX
\r
366 #define K_NUM_DEVICES 32
\r
368 io_object_t ioDevices[K_NUM_DEVICES];
\r
370 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
\r
371 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
\r
373 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
\r
374 /* callback for CFArrayApply */
\r
375 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
\r
377 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
\r
378 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
\r
379 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
\r
383 /* External function declarations (mostly platform-specific) */
\r
384 extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
\r
385 extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
\r
386 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
\r
387 extern void fgPlatformJoystickClose ( int ident );
\r
390 * The static joystick structure pointer
\r
392 #define MAX_NUM_JOYSTICKS 2
\r
393 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
396 * Read the raw joystick data
\r
398 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
407 for( i = 0; i < joy->num_axes; i++ )
\r
408 axes[ i ] = 1500.0f;
\r
413 fgPlatformJoystickRawRead ( joy, buttons, axes );
\r
417 * Correct the joystick axis data
\r
419 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
421 if( value < joy->center[ axis ] )
\r
423 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
424 joy->min[ axis ] );
\r
426 if( xx < -joy->saturate[ axis ] )
\r
429 if( xx > -joy->dead_band [ axis ] )
\r
432 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
433 joy->dead_band[ axis ] );
\r
435 return ( xx < -1.0f ) ? -1.0f : xx;
\r
439 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
440 joy->center[ axis ] );
\r
442 if( xx > joy->saturate[ axis ] )
\r
445 if( xx < joy->dead_band[ axis ] )
\r
448 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
449 joy->dead_band[ axis ] );
\r
451 return ( xx > 1.0f ) ? 1.0f : xx;
\r
456 * Read the corrected joystick data
\r
458 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
460 float raw_axes[ _JS_MAX_AXES ];
\r
469 for ( i=0; i<joy->num_axes; i++ )
\r
473 fghJoystickRawRead( joy, buttons, raw_axes );
\r
476 for( i=0; i<joy->num_axes; i++ )
\r
477 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
481 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
485 #if TARGET_HOST_MAC_OSX
\r
486 /** open the IOKit connection, enumerate all the HID devices, add their
\r
487 interface references to the static array. We then use the array index
\r
488 as the device number when we come to open() the joystick. */
\r
489 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
491 CFMutableDictionaryRef hidMatch = NULL;
\r
492 IOReturn rv = kIOReturnSuccess;
\r
494 io_iterator_t hidIterator;
\r
497 /* build a dictionary matching HID devices */
\r
498 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
500 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
501 if (rv != kIOReturnSuccess || !hidIterator) {
\r
502 fgWarning( "no joystick (HID) devices found" );
\r
507 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
508 /* filter out keyboard and mouse devices */
\r
509 CFDictionaryRef properties = getCFProperties(ioDev);
\r
512 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
513 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
514 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
515 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
517 /* keep only joystick devices */
\r
518 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
519 (usage == kHIDUsage_GD_Joystick)
\r
520 || (usage == kHIDUsage_GD_GamePad)
\r
521 || (usage == kHIDUsage_GD_MultiAxisController)
\r
522 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
523 /* add it to the array */
\r
524 ioDevices[numDevices++] = ioDev;
\r
527 IOObjectRelease(hidIterator);
\r
530 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
533 CFMutableDictionaryRef cfProperties;
\r
536 /* comment copied from darwin/SDL_sysjoystick.c */
\r
537 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
538 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
541 io_registry_entry_t parent1, parent2;
\r
543 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
544 if (rv != kIOReturnSuccess) {
\r
545 fgWarning ( "error getting device entry parent");
\r
549 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
550 if (rv != kIOReturnSuccess) {
\r
551 fgWarning ( "error getting device entry parent 2");
\r
556 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
557 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
558 if (rv != kIOReturnSuccess || !cfProperties) {
\r
559 fgWarning ( "error getting device properties");
\r
563 return cfProperties;
\r
566 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
568 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
569 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
573 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
576 /** element enumerator function : pass NULL for top-level*/
\r
577 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
579 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
580 "Joystick element type mismatch",
\r
581 "fghJoystickEnumerateElements" );
\r
583 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
584 CFArrayApplyFunction((CFArrayRef) element, range,
\r
585 &fghJoystickElementEnumerator, joy );
\r
588 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
590 long cookie, lmin, lmax;
\r
591 int index = joy->num_axes++;
\r
593 CFNumberGetValue ((CFNumberRef)
\r
594 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
595 kCFNumberLongType, &cookie);
\r
597 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
599 CFNumberGetValue ((CFNumberRef)
\r
600 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
601 kCFNumberLongType, &lmin);
\r
603 CFNumberGetValue ((CFNumberRef)
\r
604 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
605 kCFNumberLongType, &lmax);
\r
607 joy->min[index] = lmin;
\r
608 joy->max[index] = lmax;
\r
609 joy->dead_band[index] = 0.0;
\r
610 joy->saturate[index] = 1.0;
\r
611 joy->center[index] = (lmax + lmin) * 0.5;
\r
614 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
617 CFNumberGetValue ((CFNumberRef)
\r
618 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
619 kCFNumberLongType, &cookie);
\r
621 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
622 /* anything else for buttons? */
\r
625 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
627 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
628 /* do we map hats to axes or buttons? */
\r
633 * Platform-Specific Code
\r
636 #if TARGET_HOST_MACINTOSH
\r
637 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
645 for ( i = 0; i < joy->num_buttons; i++ )
\r
648 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
651 *buttons |= state << i;
\r
657 for ( i = 0; i < joy->num_axes; i++ )
\r
660 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
663 axes [i] = (float) state;
\r
669 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
674 /* XXX FIXME: get joystick name in Mac */
\r
676 err = ISpStartup( );
\r
680 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
682 joy->error = GL_TRUE;
\r
684 /* initialize the needs structure */
\r
685 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
687 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
688 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
689 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
690 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
691 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
692 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
693 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
694 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
695 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
697 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
698 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
699 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
700 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
701 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
702 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
703 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
704 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
705 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
706 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
707 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
708 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
709 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
710 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
711 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
712 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
713 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
714 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
715 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
716 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
717 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
718 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
719 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
720 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
721 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
722 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
723 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
724 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
725 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
726 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
727 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
728 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
731 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
734 /* next two calls allow keyboard and mouse to emulate other input
\r
735 * devices (gamepads, joysticks, etc)
\r
738 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
742 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
746 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
747 joy->isp_needs, joy->isp_elem,
\r
749 ISP_CHECK_ERR( err )
\r
751 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
752 'freeglut', nil, 0, 128, 0 );
\r
753 ISP_CHECK_ERR( err )
\r
755 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
756 joy->num_axes = joy->isp_num_axis;
\r
758 for( i = 0; i < joy->num_axes; i++ )
\r
760 joy->dead_band[ i ] = 0;
\r
761 joy->saturate [ i ] = 1;
\r
762 joy->center [ i ] = kISpAxisMiddle;
\r
763 joy->max [ i ] = kISpAxisMaximum;
\r
764 joy->min [ i ] = kISpAxisMinimum;
\r
767 joy->error = GL_FALSE;
\r
770 joy->num_buttons = joy->num_axes = 0;
\r
774 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
776 fgJoystick[ ident ]->id = ident;
\r
777 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
778 fgJoystick[ ident ]->error = GL_FALSE;
\r
782 void fgPlatformJoystickClose ( int ident )
\r
790 #if TARGET_HOST_MAC_OSX
\r
791 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
795 if ( buttons != NULL )
\r
799 for ( i = 0; i < joy->num_buttons; i++ )
\r
801 IOHIDEventStruct hidEvent;
\r
802 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
803 if ( hidEvent.value )
\r
804 *buttons |= 1 << i;
\r
808 if ( axes != NULL )
\r
810 for ( i = 0; i < joy->num_axes; i++ )
\r
812 IOHIDEventStruct hidEvent;
\r
813 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
814 axes[i] = hidEvent.value;
\r
820 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
824 IOCFPlugInInterface **plugin;
\r
826 HRESULT pluginResult;
\r
828 CFDictionaryRef props;
\r
829 CFTypeRef topLevelElement;
\r
831 if( joy->id >= numDevices )
\r
833 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
837 /* create device interface */
\r
838 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
839 kIOHIDDeviceUserClientTypeID,
\r
840 kIOCFPlugInInterfaceID,
\r
843 if( rv != kIOReturnSuccess )
\r
845 fgWarning( "error creating plugin for io device" );
\r
849 pluginResult = ( *plugin )->QueryInterface(
\r
851 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
852 &( LPVOID )joy->hidDev
\r
855 if( pluginResult != S_OK )
\r
856 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
858 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
859 if( joy->hidDev == NULL )
\r
862 /* store the interface in this instance */
\r
863 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
864 if( rv != kIOReturnSuccess )
\r
866 fgWarning( "error opening device interface");
\r
870 props = getCFProperties( ioDevices[ joy->id ] );
\r
872 /* recursively enumerate all the bits */
\r
873 CFTypeRef topLevelElement =
\r
874 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
875 enumerateElements( topLevelElement );
\r
877 CFRelease( props );
\r
881 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
883 fgJoystick[ ident ]->id = ident;
\r
884 fgJoystick[ ident ]->error = GL_FALSE;
\r
885 fgJoystick[ ident ]->num_axes = 0;
\r
886 fgJoystick[ ident ]->num_buttons = 0;
\r
888 if( numDevices < 0 )
\r
890 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
893 mach_port_t masterPort;
\r
894 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
895 if( rv != kIOReturnSuccess )
\r
897 fgWarning( "error getting master Mach port" );
\r
900 fghJoystickFindDevices( masterPort );
\r
903 if ( ident >= numDevices )
\r
905 fgJoystick[ ident ]->error = GL_TRUE;
\r
909 /* get the name now too */
\r
910 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
911 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
912 CFSTR( kIOHIDProductKey ) );
\r
914 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
917 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
918 CFStringGetSystemEncoding( ) ) )
\r
920 fgWarning( "error getting device name" );
\r
926 void fgPlatformJoystickClose ( int ident )
\r
928 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
929 close( fgJoystick[ ident ]->hidDev );
\r
933 #if TARGET_HOST_POSIX_X11
\r
934 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
940 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
943 if ( joy->os->is_analog )
\r
945 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
946 if ( status != sizeof(joy->os->ajs) ) {
\r
947 perror ( joy->os->fname );
\r
948 joy->error = GL_TRUE;
\r
951 if ( buttons != NULL )
\r
952 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
954 if ( axes != NULL )
\r
956 axes[0] = (float) joy->os->ajs.x;
\r
957 axes[1] = (float) joy->os->ajs.y;
\r
963 # ifdef HAVE_USB_JS
\r
964 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
966 struct hid_item *h;
\r
968 for ( h = joy->os->hids; h; h = h->next )
\r
970 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
972 int page = HID_PAGE ( h->usage );
\r
973 int usage = HID_USAGE ( h->usage );
\r
975 if ( page == HUP_GENERIC_DESKTOP )
\r
978 for ( i = 0; i < joy->num_axes; i++ )
\r
979 if (joy->os->axes_usage[i] == usage)
\r
981 if (usage == HUG_HAT_SWITCH)
\r
983 if (d < 0 || d > 8)
\r
984 d = 0; /* safety */
\r
985 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
986 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
990 joy->os->cache_axes[i] = (float)d;
\r
995 else if (page == HUP_BUTTON)
\r
997 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
1000 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
1002 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
1007 # ifdef HAVE_ERRNO_H
\r
1008 if ( len < 0 && errno != EAGAIN )
\r
1013 perror( joy->os->fname );
\r
1016 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
1017 if ( axes != NULL )
\r
1018 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
1026 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
1028 if ( status != sizeof( struct js_event ) )
\r
1030 # ifdef HAVE_ERRNO_H
\r
1031 if ( errno == EAGAIN )
\r
1033 /* Use the old values */
\r
1035 *buttons = joy->tmp_buttons;
\r
1037 memcpy( axes, joy->tmp_axes,
\r
1038 sizeof( float ) * joy->num_axes );
\r
1043 fgWarning ( "%s", joy->fname );
\r
1044 joy->error = GL_TRUE;
\r
1048 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
1050 case JS_EVENT_BUTTON:
\r
1051 if( joy->js.value == 0 ) /* clear the flag */
\r
1052 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
1054 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
1057 case JS_EVENT_AXIS:
\r
1058 if ( joy->js.number < joy->num_axes )
\r
1060 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
1063 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
1068 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
1070 /* use the old values */
\r
1072 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
1073 if ( axes != NULL )
\r
1074 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
1080 *buttons = joy->tmp_buttons;
\r
1084 status = read( joy->fd, &joy->js, JS_RETURN );
\r
1086 if ( status != JS_RETURN )
\r
1088 fgWarning( "%s", joy->fname );
\r
1089 joy->error = GL_TRUE;
\r
1094 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1095 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
1097 *buttons = joy->js.buttons;
\r
1102 axes[ 0 ] = (float) joy->js.x;
\r
1103 axes[ 1 ] = (float) joy->js.y;
\r
1109 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
1111 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1118 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1124 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1125 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1126 joy->os->cache_axes[ i ] = 0.0f;
\r
1128 joy->os->cache_buttons = 0;
\r
1130 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1132 #ifdef HAVE_ERRNO_H
\r
1133 if( joy->os->fd < 0 && errno == EACCES )
\r
1134 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1137 joy->error =( joy->os->fd < 0 );
\r
1142 joy->num_axes = 0;
\r
1143 joy->num_buttons = 0;
\r
1144 if( joy->os->is_analog )
\r
1147 char joyfname[ 1024 ];
\r
1148 int noargs, in_no_axes;
\r
1150 float axes [ _JS_MAX_AXES ];
\r
1151 int buttons[ _JS_MAX_AXES ];
\r
1153 joy->num_axes = 2;
\r
1154 joy->num_buttons = 32;
\r
1156 fghJoystickRawRead( joy, buttons, axes );
\r
1157 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1161 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1163 joyfile = fopen( joyfname, "r" );
\r
1164 joy->error =( joyfile == NULL );
\r
1168 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1169 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1170 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1171 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1172 fclose( joyfile );
\r
1176 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1178 joy->dead_band[ i ] = 0.0f;
\r
1179 joy->saturate [ i ] = 1.0f;
\r
1182 return; /* End of analog code */
\r
1185 # ifdef HAVE_USB_JS
\r
1186 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1187 &joy->num_buttons ) )
\r
1189 close( joy->os->fd );
\r
1190 joy->error = GL_TRUE;
\r
1194 cp = strrchr( joy->os->fname, '/' );
\r
1197 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1199 strcpy( joy->name, &cp[1] );
\r
1202 if( joy->num_axes > _JS_MAX_AXES )
\r
1203 joy->num_axes = _JS_MAX_AXES;
\r
1205 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1207 /* We really should get this from the HID, but that data seems
\r
1208 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1211 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1213 joy->max [ i ] = 1.0f;
\r
1214 joy->center[ i ] = 0.0f;
\r
1215 joy->min [ i ] = -1.0f;
\r
1219 joy->max [ i ] = 255.0f;
\r
1220 joy->center[ i ] = 127.0f;
\r
1221 joy->min [ i ] = 0.0f;
\r
1224 joy->dead_band[ i ] = 0.0f;
\r
1225 joy->saturate[ i ] = 1.0f;
\r
1230 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1231 /* Default for older Linux systems. */
\r
1232 joy->num_axes = 2;
\r
1233 joy->num_buttons = 32;
\r
1236 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1237 joy->tmp_axes[ i ] = 0.0f;
\r
1239 joy->tmp_buttons = 0;
\r
1242 joy->fd = open( joy->fname, O_RDONLY );
\r
1244 joy->error =( joy->fd < 0 );
\r
1249 /* Set the correct number of axes for the linux driver */
\r
1251 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1252 * to the upper byte of an uninitialized word doesn't work.
\r
1255 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1256 joy->num_axes = u;
\r
1257 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1258 joy->num_buttons = u;
\r
1259 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1260 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1264 * The Linux driver seems to return 512 for all axes
\r
1265 * when no stick is present - but there is a chance
\r
1266 * that could happen by accident - so it's gotta happen
\r
1267 * on both axes for at least 100 attempts.
\r
1269 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1276 fghJoystickRawRead( joy, NULL, joy->center );
\r
1278 } while( !joy->error &&
\r
1280 joy->center[ 0 ] == 512.0f &&
\r
1281 joy->center[ 1 ] == 512.0f );
\r
1283 if ( counter >= 100 )
\r
1284 joy->error = GL_TRUE;
\r
1287 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1290 joy->max [ i ] = 32767.0f;
\r
1291 joy->center[ i ] = 0.0f;
\r
1292 joy->min [ i ] = -32767.0f;
\r
1294 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1295 joy->min[ i ] = 0.0f;
\r
1297 joy->dead_band[ i ] = 0.0f;
\r
1298 joy->saturate [ i ] = 1.0f;
\r
1304 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
1306 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1307 fgJoystick[ ident ]->id = ident;
\r
1308 fgJoystick[ ident ]->error = GL_FALSE;
\r
1310 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1311 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
1312 if( ident < USB_IDENT_OFFSET )
\r
1313 fgJoystick[ ident ]->os->is_analog = 1;
\r
1314 if( fgJoystick[ ident ]->os->is_analog )
\r
1315 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
1317 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
1318 ident - USB_IDENT_OFFSET );
\r
1319 #elif defined( __linux__ )
\r
1320 fgJoystick[ ident ]->id = ident;
\r
1321 fgJoystick[ ident ]->error = GL_FALSE;
\r
1323 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
1325 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
1326 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
1331 void fgPlatformJoystickClose ( int ident )
\r
1333 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1334 if( fgJoystick[ident]->os )
\r
1336 if( ! fgJoystick[ ident ]->error )
\r
1337 close( fgJoystick[ ident ]->os->fd );
\r
1338 #ifdef HAVE_USB_JS
\r
1339 if( fgJoystick[ ident ]->os->hids )
\r
1340 free (fgJoystick[ ident ]->os->hids);
\r
1341 if( fgJoystick[ ident ]->os->hid_data_buf )
\r
1342 free( fgJoystick[ ident ]->os->hid_data_buf );
\r
1344 free( fgJoystick[ident]->os );
\r
1348 if( ! fgJoystick[ident]->error )
\r
1349 close( fgJoystick[ ident ]->fd );
\r
1358 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1361 * Default values (for no joystick -- each conditional will reset the
\r
1364 joy->error = TRUE;
\r
1365 joy->num_axes = joy->num_buttons = 0;
\r
1366 joy->name[ 0 ] = '\0';
\r
1368 fgPlatformJoystickOpen ( joy );
\r
1373 * This function replaces the constructor method in the JS library.
\r
1375 static void fghJoystickInit( int ident )
\r
1377 if( ident >= MAX_NUM_JOYSTICKS )
\r
1378 fgError( "Too large a joystick number: %d", ident );
\r
1380 if( fgJoystick[ ident ] )
\r
1381 fgError( "illegal attempt to initialize joystick device again" );
\r
1383 fgJoystick[ ident ] =
\r
1384 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1386 /* Set defaults */
\r
1387 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1388 fgJoystick[ ident ]->error = GL_TRUE;
\r
1390 fgPlatformJoystickInit( fgJoystick, ident );
\r
1392 fghJoystickOpen( fgJoystick[ ident ] );
\r
1396 * Try initializing all the joysticks (well, both of them)
\r
1398 void fgInitialiseJoysticks ( void )
\r
1400 if( !fgState.JoysticksInitialised )
\r
1403 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1404 fghJoystickInit( ident );
\r
1406 fgState.JoysticksInitialised = GL_TRUE;
\r
1411 void fgJoystickClose( void )
\r
1414 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1416 if( fgJoystick[ ident ] )
\r
1418 fgPlatformJoystickClose ( ident );
\r
1420 free( fgJoystick[ ident ] );
\r
1421 fgJoystick[ ident ] = NULL;
\r
1422 /* show joystick has been deinitialized */
\r
1428 * Polls the joystick and executes the joystick callback hooked to the
\r
1429 * window specified in the function's parameter:
\r
1431 void fgJoystickPollWindow( SFG_Window* window )
\r
1433 float axes[ _JS_MAX_AXES ];
\r
1437 freeglut_return_if_fail( window );
\r
1438 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1440 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1442 if( fgJoystick[ident] )
\r
1444 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1446 if( !fgJoystick[ident]->error )
\r
1447 INVOKE_WCB( *window, Joystick,
\r
1449 (int) ( axes[ 0 ] * 1000.0f ),
\r
1450 (int) ( axes[ 1 ] * 1000.0f ),
\r
1451 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1458 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1460 int fgJoystickDetect( void )
\r
1464 fgInitialiseJoysticks ();
\r
1466 if ( !fgState.JoysticksInitialised )
\r
1469 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1470 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1477 * Joystick information functions
\r
1479 int glutJoystickGetNumAxes( int ident )
\r
1481 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1482 return fgJoystick[ ident ]->num_axes;
\r
1484 int glutJoystickGetNumButtons( int ident )
\r
1486 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1487 return fgJoystick[ ident ]->num_buttons;
\r
1489 int glutJoystickNotWorking( int ident )
\r
1491 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1492 return fgJoystick[ ident ]->error;
\r
1495 float glutJoystickGetDeadBand( int ident, int axis )
\r
1497 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1498 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1500 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1502 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1503 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1506 float glutJoystickGetSaturation( int ident, int axis )
\r
1508 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1509 return fgJoystick[ ident ]->saturate[ axis ];
\r
1511 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1513 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1514 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1517 void glutJoystickSetMinRange( int ident, float *axes )
\r
1519 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1520 memcpy( fgJoystick[ ident ]->min, axes,
\r
1521 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1523 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1525 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1526 memcpy( fgJoystick[ ident ]->max, axes,
\r
1527 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1529 void glutJoystickSetCenter( int ident, float *axes )
\r
1531 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1532 memcpy( fgJoystick[ ident ]->center, axes,
\r
1533 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1536 void glutJoystickGetMinRange( int ident, float *axes )
\r
1538 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1539 memcpy( axes, fgJoystick[ ident ]->min,
\r
1540 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1542 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1544 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1545 memcpy( axes, fgJoystick[ ident ]->max,
\r
1546 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1548 void glutJoystickGetCenter( int ident, float *axes )
\r
1550 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1551 memcpy( axes, fgJoystick[ ident ]->center,
\r
1552 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1555 /*** END OF FILE ***/
\r