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_MS_WINDOWS && !defined(_WIN32_WCE)
\r
56 # include <windows.h>
\r
57 # include <mmsystem.h>
\r
58 # include <regstr.h>
\r
62 #if TARGET_HOST_POSIX_X11
\r
63 # ifdef HAVE_SYS_IOCTL_H
\r
64 # include <sys/ioctl.h>
\r
66 # ifdef HAVE_FCNTL_H
\r
69 # ifdef HAVE_ERRNO_H
\r
71 # include <string.h>
\r
73 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
74 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
75 # define HAVE_USB_JS 1
\r
77 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
78 # include <sys/joystick.h>
\r
81 * XXX NetBSD/amd64 systems may find that they have to steal the
\r
82 * XXX /usr/include/machine/joystick.h from a NetBSD/i386 system.
\r
83 * XXX I cannot comment whether that works for the interface, but
\r
84 * XXX it lets you compile...(^& I do not think that we can do away
\r
85 * XXX with this header.
\r
87 # include <machine/joystick.h> /* For analog joysticks */
\r
89 # define JS_DATA_TYPE joystick
\r
90 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
93 # if defined(__linux__)
\r
94 # include <linux/joystick.h>
\r
96 /* check the joystick driver version */
\r
97 # if defined(JS_VERSION) && JS_VERSION >= 0x010000
\r
100 # else /* Not BSD or Linux */
\r
104 * We'll put these values in and that should
\r
105 * allow the code to at least compile when there is
\r
106 * no support. The JS open routine should error out
\r
107 * and shut off all the code downstream anyway and if
\r
108 * the application doesn't use a joystick we'll be fine.
\r
111 struct JS_DATA_TYPE
\r
118 # define JS_RETURN (sizeof(struct JS_DATA_TYPE))
\r
126 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
\r
128 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
130 # ifdef HAVE_USB_JS
\r
131 # if defined(__NetBSD__)
\r
132 /* XXX The below hack is done until freeglut's autoconf is updated. */
\r
133 # define HAVE_USBHID_H 1
\r
134 # ifdef HAVE_USBHID_H
\r
135 # include <usbhid.h>
\r
139 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
\r
140 # ifdef HAVE_USBHID_H
\r
141 # include <usbhid.h>
\r
143 # include <libusbhid.h>
\r
146 # include <legacy/dev/usb/usb.h>
\r
147 # include <dev/usb/usbhid.h>
\r
149 /* Compatibility with older usb.h revisions */
\r
150 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
\r
151 # define USB_MAX_DEVNAMES MAXDEVNAMES
\r
155 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
\r
156 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
\r
157 struct os_specific_s {
\r
161 /* The following structure members are specific to analog joysticks */
\r
162 struct joystick ajs;
\r
163 # ifdef HAVE_USB_JS
\r
164 /* The following structure members are specific to USB joysticks */
\r
165 struct hid_item *hids;
\r
168 char *hid_data_buf;
\r
169 int axes_usage [ _JS_MAX_AXES ];
\r
171 /* We keep button and axes state ourselves, as they might not be updated
\r
172 * on every read of a USB device
\r
175 float cache_axes [ _JS_MAX_AXES ];
\r
178 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
\r
179 # define USB_IDENT_OFFSET 2
\r
181 # define USBDEV "/dev/usb"
\r
182 # define UHIDDEV "/dev/uhid"
\r
183 # define AJSDEV "/dev/joy"
\r
185 # ifdef HAVE_USB_JS
\r
187 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
\r
188 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
\r
189 * return the uhidN device name. We warn the user of this situation once.
\r
191 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
\r
193 struct usb_device_info di;
\r
197 for (a = 1; a < USB_MAX_DEVICES; a++) {
\r
199 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
\r
201 for (i = 0; i < USB_MAX_DEVNAMES; i++)
\r
202 if (di.udi_devnames[i][0] &&
\r
203 strcmp(di.udi_devnames[i], dev) == 0) {
\r
204 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
\r
205 strcpy(cp, di.udi_vendor);
\r
207 strcat(cp, di.udi_product);
\r
208 strncpy(out, cp, outlen - 1);
\r
209 out[outlen - 1] = 0;
\r
217 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
\r
222 static int protection_warned = 0;
\r
224 for (i = 0; i < 16; i++) {
\r
225 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
\r
226 f = open(buf, O_RDONLY);
\r
228 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
\r
233 #ifdef HAVE_ERRNO_H
\r
234 else if (errno == EACCES) {
\r
235 if (!protection_warned) {
\r
236 fgWarning ( "Can't open %s for read!", buf );
\r
237 protection_warned = 1;
\r
245 static int fghJoystickInitializeHID(struct os_specific_s *os,
\r
246 int *num_axes, int *num_buttons)
\r
248 int size, is_joystick;
\r
249 # ifdef HAVE_USBHID_H
\r
252 struct hid_data *d;
\r
256 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
\r
258 #ifdef HAVE_ERRNO_H
\r
259 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
\r
261 fgWarning ( "error: %s", os->fname );
\r
268 # ifdef HAVE_USBHID_H
\r
269 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
\r
271 /*** XXX {report_id} may not be the right variable? ***/
\r
272 #ifdef HAVE_ERRNO_H
\r
273 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
\r
275 fgWarning ( "error: %s%d", UHIDDEV, report_id );
\r
280 size = hid_report_size( rd, hid_input, report_id );
\r
282 size = hid_report_size( rd, 0, hid_input );
\r
284 os->hid_data_buf = calloc( 1, size );
\r
285 os->hid_dlen = size;
\r
288 # ifdef HAVE_USBHID_H
\r
289 d = hid_start_parse( rd, 1 << hid_input, report_id );
\r
291 d = hid_start_parse( rd, 1 << hid_input );
\r
293 while( hid_get_item( d, &h ) )
\r
295 int usage, page, interesting_hid;
\r
297 page = HID_PAGE( h.usage );
\r
298 usage = HID_USAGE( h.usage );
\r
300 /* This test is somewhat too simplistic, but this is how MicroSoft
\r
301 * does, so I guess it works for all joysticks/game pads. */
\r
302 is_joystick = is_joystick ||
\r
303 ( h.kind == hid_collection &&
\r
304 page == HUP_GENERIC_DESKTOP &&
\r
305 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
\r
307 if( h.kind != hid_input )
\r
313 interesting_hid = TRUE;
\r
314 if( page == HUP_GENERIC_DESKTOP )
\r
325 if( *num_axes < _JS_MAX_AXES )
\r
327 os->axes_usage[ *num_axes ] = usage;
\r
331 case HUG_HAT_SWITCH:
\r
332 /* Allocate two axes for a hat */
\r
333 if( *num_axes + 1 < _JS_MAX_AXES )
\r
335 os->axes_usage[ *num_axes ] = usage;
\r
337 os->axes_usage[ *num_axes ] = usage;
\r
342 interesting_hid = FALSE;
\r
346 else if( page == HUP_BUTTON )
\r
348 interesting_hid = ( usage > 0 ) &&
\r
349 ( usage <= _JS_MAX_BUTTONS );
\r
351 if( interesting_hid && usage - 1 > *num_buttons )
\r
352 *num_buttons = usage - 1;
\r
355 if( interesting_hid )
\r
358 os->hids = calloc( 1, sizeof ( struct hid_item ) );
\r
362 hid_end_parse( d );
\r
364 return os->hids != NULL;
\r
370 * Functions associated with the "jsJoystick" class in PLIB
\r
372 #if TARGET_HOST_MAC_OSX
\r
373 #define K_NUM_DEVICES 32
\r
375 io_object_t ioDevices[K_NUM_DEVICES];
\r
377 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
\r
378 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
\r
380 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
\r
381 /* callback for CFArrayApply */
\r
382 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
\r
384 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
\r
385 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
\r
386 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
\r
390 /* External function declarations (mostly platform-specific) */
\r
391 extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
\r
392 extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
\r
393 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
\r
394 extern void fgPlatformJoystickClose ( int ident );
\r
397 * The static joystick structure pointer
\r
399 #define MAX_NUM_JOYSTICKS 2
\r
400 static SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
\r
403 * Read the raw joystick data
\r
405 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
414 for( i = 0; i < joy->num_axes; i++ )
\r
415 axes[ i ] = 1500.0f;
\r
420 fgPlatformJoystickRawRead ( joy, buttons, axes );
\r
424 * Correct the joystick axis data
\r
426 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
\r
428 if( value < joy->center[ axis ] )
\r
430 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
\r
431 joy->min[ axis ] );
\r
433 if( xx < -joy->saturate[ axis ] )
\r
436 if( xx > -joy->dead_band [ axis ] )
\r
439 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
440 joy->dead_band[ axis ] );
\r
442 return ( xx < -1.0f ) ? -1.0f : xx;
\r
446 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
\r
447 joy->center[ axis ] );
\r
449 if( xx > joy->saturate[ axis ] )
\r
452 if( xx < joy->dead_band[ axis ] )
\r
455 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
\r
456 joy->dead_band[ axis ] );
\r
458 return ( xx > 1.0f ) ? 1.0f : xx;
\r
463 * Read the corrected joystick data
\r
465 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
467 float raw_axes[ _JS_MAX_AXES ];
\r
476 for ( i=0; i<joy->num_axes; i++ )
\r
480 fghJoystickRawRead( joy, buttons, raw_axes );
\r
483 for( i=0; i<joy->num_axes; i++ )
\r
484 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
\r
488 * Happy happy happy joy joy joy (happy new year toudi :D)
\r
492 #if TARGET_HOST_MAC_OSX
\r
493 /** open the IOKit connection, enumerate all the HID devices, add their
\r
494 interface references to the static array. We then use the array index
\r
495 as the device number when we come to open() the joystick. */
\r
496 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
\r
498 CFMutableDictionaryRef hidMatch = NULL;
\r
499 IOReturn rv = kIOReturnSuccess;
\r
501 io_iterator_t hidIterator;
\r
504 /* build a dictionary matching HID devices */
\r
505 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
\r
507 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
\r
508 if (rv != kIOReturnSuccess || !hidIterator) {
\r
509 fgWarning( "no joystick (HID) devices found" );
\r
514 while ((ioDev = IOIteratorNext(hidIterator))) {
\r
515 /* filter out keyboard and mouse devices */
\r
516 CFDictionaryRef properties = getCFProperties(ioDev);
\r
519 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
\r
520 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
\r
521 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
\r
522 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
\r
524 /* keep only joystick devices */
\r
525 if ( ( page == kHIDPage_GenericDesktop ) && (
\r
526 (usage == kHIDUsage_GD_Joystick)
\r
527 || (usage == kHIDUsage_GD_GamePad)
\r
528 || (usage == kHIDUsage_GD_MultiAxisController)
\r
529 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
\r
530 /* add it to the array */
\r
531 ioDevices[numDevices++] = ioDev;
\r
534 IOObjectRelease(hidIterator);
\r
537 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
\r
540 CFMutableDictionaryRef cfProperties;
\r
543 /* comment copied from darwin/SDL_sysjoystick.c */
\r
544 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
\r
545 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
\r
548 io_registry_entry_t parent1, parent2;
\r
550 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
\r
551 if (rv != kIOReturnSuccess) {
\r
552 fgWarning ( "error getting device entry parent");
\r
556 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
\r
557 if (rv != kIOReturnSuccess) {
\r
558 fgWarning ( "error getting device entry parent 2");
\r
563 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
\r
564 &cfProperties, kCFAllocatorDefault, kNilOptions);
\r
565 if (rv != kIOReturnSuccess || !cfProperties) {
\r
566 fgWarning ( "error getting device properties");
\r
570 return cfProperties;
\r
573 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
\r
575 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
\r
576 fgError ( "%s", "element enumerator passed non-dictionary value");
\r
580 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
\r
583 /** element enumerator function : pass NULL for top-level*/
\r
584 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
\r
586 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
\r
587 "Joystick element type mismatch",
\r
588 "fghJoystickEnumerateElements" );
\r
590 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
\r
591 CFArrayApplyFunction((CFArrayRef) element, range,
\r
592 &fghJoystickElementEnumerator, joy );
\r
595 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
\r
597 long cookie, lmin, lmax;
\r
598 int index = joy->num_axes++;
\r
600 CFNumberGetValue ((CFNumberRef)
\r
601 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
\r
602 kCFNumberLongType, &cookie);
\r
604 axisCookies[index] = (IOHIDElementCookie) cookie;
\r
606 CFNumberGetValue ((CFNumberRef)
\r
607 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
\r
608 kCFNumberLongType, &lmin);
\r
610 CFNumberGetValue ((CFNumberRef)
\r
611 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
\r
612 kCFNumberLongType, &lmax);
\r
614 joy->min[index] = lmin;
\r
615 joy->max[index] = lmax;
\r
616 joy->dead_band[index] = 0.0;
\r
617 joy->saturate[index] = 1.0;
\r
618 joy->center[index] = (lmax + lmin) * 0.5;
\r
621 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
624 CFNumberGetValue ((CFNumberRef)
\r
625 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
\r
626 kCFNumberLongType, &cookie);
\r
628 joy->buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
\r
629 /* anything else for buttons? */
\r
632 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
\r
634 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
\r
635 /* do we map hats to axes or buttons? */
\r
640 * Platform-Specific Code
\r
643 #if TARGET_HOST_MACINTOSH
\r
644 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
652 for ( i = 0; i < joy->num_buttons; i++ )
\r
655 int err = ISpElement_GetSimpleState ( isp_elem [ i + isp_num_axis ], &state);
\r
658 *buttons |= state << i;
\r
664 for ( i = 0; i < joy->num_axes; i++ )
\r
667 int err = ISpElement_GetSimpleState ( isp_elem [ i ], &state );
\r
670 axes [i] = (float) state;
\r
676 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
681 /* XXX FIXME: get joystick name in Mac */
\r
683 err = ISpStartup( );
\r
687 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
\r
689 joy->error = GL_TRUE;
\r
691 /* initialize the needs structure */
\r
692 ISpNeed temp_isp_needs[ isp_num_needs ] =
\r
694 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
695 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
696 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
697 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
698 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
699 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
700 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
701 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
702 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
\r
704 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
705 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
706 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
707 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
708 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
709 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
710 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
711 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
712 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
713 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
714 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
715 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
716 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
717 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
718 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
719 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
720 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
721 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
722 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
723 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
724 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
725 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
726 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
727 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
728 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
729 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
730 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
731 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
732 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
733 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
734 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
735 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
\r
738 memcpy( joy->isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
\r
741 /* next two calls allow keyboard and mouse to emulate other input
\r
742 * devices (gamepads, joysticks, etc)
\r
745 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
\r
749 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
\r
753 err = ISpElement_NewVirtualFromNeeds( joy->isp_num_needs,
\r
754 joy->isp_needs, joy->isp_elem,
\r
756 ISP_CHECK_ERR( err )
\r
758 err = ISpInit( joy->isp_num_needs, joy->isp_needs, joy->isp_elem,
\r
759 'freeglut', nil, 0, 128, 0 );
\r
760 ISP_CHECK_ERR( err )
\r
762 joy->num_buttons = joy->isp_num_needs - joy->isp_num_axis;
\r
763 joy->num_axes = joy->isp_num_axis;
\r
765 for( i = 0; i < joy->num_axes; i++ )
\r
767 joy->dead_band[ i ] = 0;
\r
768 joy->saturate [ i ] = 1;
\r
769 joy->center [ i ] = kISpAxisMiddle;
\r
770 joy->max [ i ] = kISpAxisMaximum;
\r
771 joy->min [ i ] = kISpAxisMinimum;
\r
774 joy->error = GL_FALSE;
\r
777 joy->num_buttons = joy->num_axes = 0;
\r
781 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
783 fgJoystick[ ident ]->id = ident;
\r
784 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident ); /* FIXME */
\r
785 fgJoystick[ ident ]->error = GL_FALSE;
\r
789 void fgPlatformJoystickClose ( int ident )
\r
797 #if TARGET_HOST_MAC_OSX
\r
798 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
802 if ( buttons != NULL )
\r
806 for ( i = 0; i < joy->num_buttons; i++ )
\r
808 IOHIDEventStruct hidEvent;
\r
809 (*(joy->hidDev))->getElementValue ( joy->hidDev, buttonCookies[i], &hidEvent );
\r
810 if ( hidEvent.value )
\r
811 *buttons |= 1 << i;
\r
815 if ( axes != NULL )
\r
817 for ( i = 0; i < joy->num_axes; i++ )
\r
819 IOHIDEventStruct hidEvent;
\r
820 (*(joy->hidDev))->getElementValue ( joy->hidDev, axisCookies[i], &hidEvent );
\r
821 axes[i] = hidEvent.value;
\r
827 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
831 IOCFPlugInInterface **plugin;
\r
833 HRESULT pluginResult;
\r
835 CFDictionaryRef props;
\r
836 CFTypeRef topLevelElement;
\r
838 if( joy->id >= numDevices )
\r
840 fgWarning( "device index out of range in fgJoystickOpen()" );
\r
844 /* create device interface */
\r
845 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
\r
846 kIOHIDDeviceUserClientTypeID,
\r
847 kIOCFPlugInInterfaceID,
\r
850 if( rv != kIOReturnSuccess )
\r
852 fgWarning( "error creating plugin for io device" );
\r
856 pluginResult = ( *plugin )->QueryInterface(
\r
858 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
\r
859 &( LPVOID )joy->hidDev
\r
862 if( pluginResult != S_OK )
\r
863 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
\r
865 ( *plugin )->Release( plugin ); /* don't leak a ref */
\r
866 if( joy->hidDev == NULL )
\r
869 /* store the interface in this instance */
\r
870 rv = ( *( joy->hidDev ) )->open( joy->hidDev, 0 );
\r
871 if( rv != kIOReturnSuccess )
\r
873 fgWarning( "error opening device interface");
\r
877 props = getCFProperties( ioDevices[ joy->id ] );
\r
879 /* recursively enumerate all the bits */
\r
880 CFTypeRef topLevelElement =
\r
881 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
\r
882 enumerateElements( topLevelElement );
\r
884 CFRelease( props );
\r
888 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
890 fgJoystick[ ident ]->id = ident;
\r
891 fgJoystick[ ident ]->error = GL_FALSE;
\r
892 fgJoystick[ ident ]->num_axes = 0;
\r
893 fgJoystick[ ident ]->num_buttons = 0;
\r
895 if( numDevices < 0 )
\r
897 /* do first-time init (since we can't over-ride jsInit, hmm */
\r
900 mach_port_t masterPort;
\r
901 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
\r
902 if( rv != kIOReturnSuccess )
\r
904 fgWarning( "error getting master Mach port" );
\r
907 fghJoystickFindDevices( masterPort );
\r
910 if ( ident >= numDevices )
\r
912 fgJoystick[ ident ]->error = GL_TRUE;
\r
916 /* get the name now too */
\r
917 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
\r
918 CFTypeRef ref = CFDictionaryGetValue( properties,
\r
919 CFSTR( kIOHIDProductKey ) );
\r
921 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
\r
924 !CFStringGetCString( ( CFStringRef )ref, name, 128,
\r
925 CFStringGetSystemEncoding( ) ) )
\r
927 fgWarning( "error getting device name" );
\r
933 void fgPlatformJoystickClose ( int ident )
\r
935 ( *( fgJoystick[ ident ]->hidDev ) )->
\r
936 close( fgJoystick[ ident ]->hidDev );
\r
940 #if TARGET_HOST_POSIX_X11
\r
941 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
\r
947 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
\r
950 if ( joy->os->is_analog )
\r
952 int status = read ( joy->os->fd, &joy->os->ajs, sizeof(joy->os->ajs) );
\r
953 if ( status != sizeof(joy->os->ajs) ) {
\r
954 perror ( joy->os->fname );
\r
955 joy->error = GL_TRUE;
\r
958 if ( buttons != NULL )
\r
959 *buttons = ( joy->os->ajs.b1 ? 1 : 0 ) | ( joy->os->ajs.b2 ? 2 : 0 );
\r
961 if ( axes != NULL )
\r
963 axes[0] = (float) joy->os->ajs.x;
\r
964 axes[1] = (float) joy->os->ajs.y;
\r
970 # ifdef HAVE_USB_JS
\r
971 while ( ( len = read ( joy->os->fd, joy->os->hid_data_buf, joy->os->hid_dlen ) ) == joy->os->hid_dlen )
\r
973 struct hid_item *h;
\r
975 for ( h = joy->os->hids; h; h = h->next )
\r
977 int d = hid_get_data ( joy->os->hid_data_buf, h );
\r
979 int page = HID_PAGE ( h->usage );
\r
980 int usage = HID_USAGE ( h->usage );
\r
982 if ( page == HUP_GENERIC_DESKTOP )
\r
985 for ( i = 0; i < joy->num_axes; i++ )
\r
986 if (joy->os->axes_usage[i] == usage)
\r
988 if (usage == HUG_HAT_SWITCH)
\r
990 if (d < 0 || d > 8)
\r
991 d = 0; /* safety */
\r
992 joy->os->cache_axes[i] = (float)hatmap_x[d];
\r
993 joy->os->cache_axes[i + 1] = (float)hatmap_y[d];
\r
997 joy->os->cache_axes[i] = (float)d;
\r
1002 else if (page == HUP_BUTTON)
\r
1004 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
\r
1007 joy->os->cache_buttons |= (1 << ( usage - 1 ));
\r
1009 joy->os->cache_buttons &= ~(1 << ( usage - 1 ));
\r
1014 # ifdef HAVE_ERRNO_H
\r
1015 if ( len < 0 && errno != EAGAIN )
\r
1020 perror( joy->os->fname );
\r
1023 if ( buttons != NULL ) *buttons = joy->os->cache_buttons;
\r
1024 if ( axes != NULL )
\r
1025 memcpy ( axes, joy->os->cache_axes, sizeof(float) * joy->num_axes );
\r
1033 status = read ( joy->fd, &joy->js, sizeof(struct js_event) );
\r
1035 if ( status != sizeof( struct js_event ) )
\r
1037 # ifdef HAVE_ERRNO_H
\r
1038 if ( errno == EAGAIN )
\r
1040 /* Use the old values */
\r
1042 *buttons = joy->tmp_buttons;
\r
1044 memcpy( axes, joy->tmp_axes,
\r
1045 sizeof( float ) * joy->num_axes );
\r
1050 fgWarning ( "%s", joy->fname );
\r
1051 joy->error = GL_TRUE;
\r
1055 switch ( joy->js.type & ~JS_EVENT_INIT )
\r
1057 case JS_EVENT_BUTTON:
\r
1058 if( joy->js.value == 0 ) /* clear the flag */
\r
1059 joy->tmp_buttons &= ~( 1 << joy->js.number );
\r
1061 joy->tmp_buttons |= ( 1 << joy->js.number );
\r
1064 case JS_EVENT_AXIS:
\r
1065 if ( joy->js.number < joy->num_axes )
\r
1067 joy->tmp_axes[ joy->js.number ] = ( float )joy->js.value;
\r
1070 memcpy( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
1075 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
\r
1077 /* use the old values */
\r
1079 if ( buttons != NULL ) *buttons = joy->tmp_buttons;
\r
1080 if ( axes != NULL )
\r
1081 memcpy ( axes, joy->tmp_axes, sizeof(float) * joy->num_axes );
\r
1087 *buttons = joy->tmp_buttons;
\r
1091 status = read( joy->fd, &joy->js, JS_RETURN );
\r
1093 if ( status != JS_RETURN )
\r
1095 fgWarning( "%s", joy->fname );
\r
1096 joy->error = GL_TRUE;
\r
1101 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1102 *buttons = ( joy->js.b1 ? 1 : 0 ) | ( joy->js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
\r
1104 *buttons = joy->js.buttons;
\r
1109 axes[ 0 ] = (float) joy->js.x;
\r
1110 axes[ 1 ] = (float) joy->js.y;
\r
1116 void fgPlatformJoystickOpen( SFG_Joystick* joy )
\r
1118 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1125 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1131 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1132 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1133 joy->os->cache_axes[ i ] = 0.0f;
\r
1135 joy->os->cache_buttons = 0;
\r
1137 joy->os->fd = open( joy->os->fname, O_RDONLY | O_NONBLOCK);
\r
1139 #ifdef HAVE_ERRNO_H
\r
1140 if( joy->os->fd < 0 && errno == EACCES )
\r
1141 fgWarning ( "%s exists but is not readable by you", joy->os->fname );
\r
1144 joy->error =( joy->os->fd < 0 );
\r
1149 joy->num_axes = 0;
\r
1150 joy->num_buttons = 0;
\r
1151 if( joy->os->is_analog )
\r
1154 char joyfname[ 1024 ];
\r
1155 int noargs, in_no_axes;
\r
1157 float axes [ _JS_MAX_AXES ];
\r
1158 int buttons[ _JS_MAX_AXES ];
\r
1160 joy->num_axes = 2;
\r
1161 joy->num_buttons = 32;
\r
1163 fghJoystickRawRead( joy, buttons, axes );
\r
1164 joy->error = axes[ 0 ] < -1000000000.0f;
\r
1168 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
\r
1170 joyfile = fopen( joyfname, "r" );
\r
1171 joy->error =( joyfile == NULL );
\r
1175 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
\r
1176 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
\r
1177 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
\r
1178 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
\r
1179 fclose( joyfile );
\r
1183 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1185 joy->dead_band[ i ] = 0.0f;
\r
1186 joy->saturate [ i ] = 1.0f;
\r
1189 return; /* End of analog code */
\r
1192 # ifdef HAVE_USB_JS
\r
1193 if( ! fghJoystickInitializeHID( joy->os, &joy->num_axes,
\r
1194 &joy->num_buttons ) )
\r
1196 close( joy->os->fd );
\r
1197 joy->error = GL_TRUE;
\r
1201 cp = strrchr( joy->os->fname, '/' );
\r
1204 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
\r
1206 strcpy( joy->name, &cp[1] );
\r
1209 if( joy->num_axes > _JS_MAX_AXES )
\r
1210 joy->num_axes = _JS_MAX_AXES;
\r
1212 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1214 /* We really should get this from the HID, but that data seems
\r
1215 * to be quite unreliable for analog-to-USB converters. Punt for
\r
1218 if( joy->os->axes_usage[ i ] == HUG_HAT_SWITCH )
\r
1220 joy->max [ i ] = 1.0f;
\r
1221 joy->center[ i ] = 0.0f;
\r
1222 joy->min [ i ] = -1.0f;
\r
1226 joy->max [ i ] = 255.0f;
\r
1227 joy->center[ i ] = 127.0f;
\r
1228 joy->min [ i ] = 0.0f;
\r
1231 joy->dead_band[ i ] = 0.0f;
\r
1232 joy->saturate[ i ] = 1.0f;
\r
1237 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
\r
1238 /* Default for older Linux systems. */
\r
1239 joy->num_axes = 2;
\r
1240 joy->num_buttons = 32;
\r
1243 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1244 joy->tmp_axes[ i ] = 0.0f;
\r
1246 joy->tmp_buttons = 0;
\r
1249 joy->fd = open( joy->fname, O_RDONLY );
\r
1251 joy->error =( joy->fd < 0 );
\r
1256 /* Set the correct number of axes for the linux driver */
\r
1258 /* Melchior Franz's fixes for big-endian Linuxes since writing
\r
1259 * to the upper byte of an uninitialized word doesn't work.
\r
1262 ioctl( joy->fd, JSIOCGAXES, &u );
\r
1263 joy->num_axes = u;
\r
1264 ioctl( joy->fd, JSIOCGBUTTONS, &u );
\r
1265 joy->num_buttons = u;
\r
1266 ioctl( joy->fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
\r
1267 fcntl( joy->fd, F_SETFL, O_NONBLOCK );
\r
1271 * The Linux driver seems to return 512 for all axes
\r
1272 * when no stick is present - but there is a chance
\r
1273 * that could happen by accident - so it's gotta happen
\r
1274 * on both axes for at least 100 attempts.
\r
1276 * PWO: shouldn't be that done somehow wiser on the kernel level?
\r
1283 fghJoystickRawRead( joy, NULL, joy->center );
\r
1285 } while( !joy->error &&
\r
1287 joy->center[ 0 ] == 512.0f &&
\r
1288 joy->center[ 1 ] == 512.0f );
\r
1290 if ( counter >= 100 )
\r
1291 joy->error = GL_TRUE;
\r
1294 for( i = 0; i < _JS_MAX_AXES; i++ )
\r
1297 joy->max [ i ] = 32767.0f;
\r
1298 joy->center[ i ] = 0.0f;
\r
1299 joy->min [ i ] = -32767.0f;
\r
1301 joy->max[ i ] = joy->center[ i ] * 2.0f;
\r
1302 joy->min[ i ] = 0.0f;
\r
1304 joy->dead_band[ i ] = 0.0f;
\r
1305 joy->saturate [ i ] = 1.0f;
\r
1311 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
\r
1313 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1314 fgJoystick[ ident ]->id = ident;
\r
1315 fgJoystick[ ident ]->error = GL_FALSE;
\r
1317 fgJoystick[ ident ]->os = calloc( 1, sizeof( struct os_specific_s ) );
\r
1318 memset( fgJoystick[ ident ]->os, 0, sizeof( struct os_specific_s ) );
\r
1319 if( ident < USB_IDENT_OFFSET )
\r
1320 fgJoystick[ ident ]->os->is_analog = 1;
\r
1321 if( fgJoystick[ ident ]->os->is_analog )
\r
1322 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", AJSDEV, ident );
\r
1324 snprintf( fgJoystick[ ident ]->os->fname, sizeof(fgJoystick[ ident ]->os->fname), "%s%d", UHIDDEV,
\r
1325 ident - USB_IDENT_OFFSET );
\r
1326 #elif defined( __linux__ )
\r
1327 fgJoystick[ ident ]->id = ident;
\r
1328 fgJoystick[ ident ]->error = GL_FALSE;
\r
1330 snprintf( fgJoystick[ident]->fname, sizeof(fgJoystick[ident]->fname), "/dev/input/js%d", ident );
\r
1332 if( access( fgJoystick[ ident ]->fname, F_OK ) != 0 )
\r
1333 snprintf( fgJoystick[ ident ]->fname, sizeof(fgJoystick[ ident ]->fname), "/dev/js%d", ident );
\r
1338 void fgPlatformJoystickClose ( int ident )
\r
1340 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
\r
1341 if( fgJoystick[ident]->os )
\r
1343 if( ! fgJoystick[ ident ]->error )
\r
1344 close( fgJoystick[ ident ]->os->fd );
\r
1345 #ifdef HAVE_USB_JS
\r
1346 if( fgJoystick[ ident ]->os->hids )
\r
1347 free (fgJoystick[ ident ]->os->hids);
\r
1348 if( fgJoystick[ ident ]->os->hid_data_buf )
\r
1349 free( fgJoystick[ ident ]->os->hid_data_buf );
\r
1351 free( fgJoystick[ident]->os );
\r
1355 if( ! fgJoystick[ident]->error )
\r
1356 close( fgJoystick[ ident ]->fd );
\r
1365 static void fghJoystickOpen( SFG_Joystick* joy )
\r
1368 * Default values (for no joystick -- each conditional will reset the
\r
1371 joy->error = TRUE;
\r
1372 joy->num_axes = joy->num_buttons = 0;
\r
1373 joy->name[ 0 ] = '\0';
\r
1375 fgPlatformJoystickOpen ( joy );
\r
1380 * This function replaces the constructor method in the JS library.
\r
1382 static void fghJoystickInit( int ident )
\r
1384 if( ident >= MAX_NUM_JOYSTICKS )
\r
1385 fgError( "Too large a joystick number: %d", ident );
\r
1387 if( fgJoystick[ ident ] )
\r
1388 fgError( "illegal attempt to initialize joystick device again" );
\r
1390 fgJoystick[ ident ] =
\r
1391 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
\r
1393 /* Set defaults */
\r
1394 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
\r
1395 fgJoystick[ ident ]->error = GL_TRUE;
\r
1397 fgPlatformJoystickInit( fgJoystick, ident );
\r
1399 fghJoystickOpen( fgJoystick[ ident ] );
\r
1403 * Try initializing all the joysticks (well, both of them)
\r
1405 void fgInitialiseJoysticks ( void )
\r
1407 if( !fgState.JoysticksInitialised )
\r
1410 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1411 fghJoystickInit( ident );
\r
1413 fgState.JoysticksInitialised = GL_TRUE;
\r
1418 void fgJoystickClose( void )
\r
1421 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1423 if( fgJoystick[ ident ] )
\r
1425 fgPlatformJoystickClose ( ident );
\r
1427 free( fgJoystick[ ident ] );
\r
1428 fgJoystick[ ident ] = NULL;
\r
1429 /* show joystick has been deinitialized */
\r
1435 * Polls the joystick and executes the joystick callback hooked to the
\r
1436 * window specified in the function's parameter:
\r
1438 void fgJoystickPollWindow( SFG_Window* window )
\r
1440 float axes[ _JS_MAX_AXES ];
\r
1444 freeglut_return_if_fail( window );
\r
1445 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
\r
1447 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
\r
1449 if( fgJoystick[ident] )
\r
1451 fghJoystickRead( fgJoystick[ident], &buttons, axes );
\r
1453 if( !fgJoystick[ident]->error )
\r
1454 INVOKE_WCB( *window, Joystick,
\r
1456 (int) ( axes[ 0 ] * 1000.0f ),
\r
1457 (int) ( axes[ 1 ] * 1000.0f ),
\r
1458 (int) ( axes[ 2 ] * 1000.0f ) )
\r
1465 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
\r
1467 int fgJoystickDetect( void )
\r
1471 fgInitialiseJoysticks ();
\r
1473 if ( !fgState.JoysticksInitialised )
\r
1476 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
\r
1477 if( fgJoystick[ident] && !fgJoystick[ident]->error )
\r
1484 * Joystick information functions
\r
1486 int glutJoystickGetNumAxes( int ident )
\r
1488 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
\r
1489 return fgJoystick[ ident ]->num_axes;
\r
1491 int glutJoystickGetNumButtons( int ident )
\r
1493 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
\r
1494 return fgJoystick[ ident ]->num_buttons;
\r
1496 int glutJoystickNotWorking( int ident )
\r
1498 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
\r
1499 return fgJoystick[ ident ]->error;
\r
1502 float glutJoystickGetDeadBand( int ident, int axis )
\r
1504 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
\r
1505 return fgJoystick[ ident ]->dead_band [ axis ];
\r
1507 void glutJoystickSetDeadBand( int ident, int axis, float db )
\r
1509 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
\r
1510 fgJoystick[ ident ]->dead_band[ axis ] = db;
\r
1513 float glutJoystickGetSaturation( int ident, int axis )
\r
1515 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
\r
1516 return fgJoystick[ ident ]->saturate[ axis ];
\r
1518 void glutJoystickSetSaturation( int ident, int axis, float st )
\r
1520 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
\r
1521 fgJoystick[ ident ]->saturate [ axis ] = st;
\r
1524 void glutJoystickSetMinRange( int ident, float *axes )
\r
1526 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
\r
1527 memcpy( fgJoystick[ ident ]->min, axes,
\r
1528 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1530 void glutJoystickSetMaxRange( int ident, float *axes )
\r
1532 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
\r
1533 memcpy( fgJoystick[ ident ]->max, axes,
\r
1534 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1536 void glutJoystickSetCenter( int ident, float *axes )
\r
1538 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
\r
1539 memcpy( fgJoystick[ ident ]->center, axes,
\r
1540 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1543 void glutJoystickGetMinRange( int ident, float *axes )
\r
1545 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
\r
1546 memcpy( axes, fgJoystick[ ident ]->min,
\r
1547 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1549 void glutJoystickGetMaxRange( int ident, float *axes )
\r
1551 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
\r
1552 memcpy( axes, fgJoystick[ ident ]->max,
\r
1553 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1555 void glutJoystickGetCenter( int ident, float *axes )
\r
1557 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
\r
1558 memcpy( axes, fgJoystick[ ident ]->center,
\r
1559 fgJoystick[ ident ]->num_axes * sizeof( float ) );
\r
1562 /*** END OF FILE ***/
\r