4 * Joystick handling code
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Steve Baker, <sjbaker1@airmail.net>
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
30 * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
31 * Many thanks for Steve Baker for permission to pull from that library.
34 #include <GL/freeglut.h>
35 #include "fg_internal.h"
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
43 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
45 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
48 # if defined(__NetBSD__)
54 # include <dev/usb/usb.h>
55 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
59 # include <libusbhid.h>
61 # include <legacy/dev/usb/usb.h>
63 # include <dev/usb/usbhid.h>
65 /* Compatibility with older usb.h revisions */
66 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
67 # define USB_MAX_DEVNAMES MAXDEVNAMES
71 static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
72 static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
73 struct os_specific_s {
77 /* The following structure members are specific to analog joysticks */
80 /* The following structure members are specific to USB joysticks */
81 struct hid_item *hids;
85 int axes_usage [ _JS_MAX_AXES ];
87 /* We keep button and axes state ourselves, as they might not be updated
88 * on every read of a USB device
91 float cache_axes [ _JS_MAX_AXES ];
94 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
95 # define USB_IDENT_OFFSET 2
97 # define USBDEV "/dev/usb"
98 # define UHIDDEV "/dev/uhid"
99 # define AJSDEV "/dev/joy"
103 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
104 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
105 * return the uhidN device name. We warn the user of this situation once.
107 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
109 struct usb_device_info di;
113 for (a = 1; a < USB_MAX_DEVICES; a++) {
115 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
117 for (i = 0; i < USB_MAX_DEVNAMES; i++)
118 if (di.udi_devnames[i][0] &&
119 strcmp(di.udi_devnames[i], dev) == 0) {
120 cp = calloc( 1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
121 strcpy(cp, di.udi_vendor);
123 strcat(cp, di.udi_product);
124 strncpy(out, cp, outlen - 1);
133 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
138 static int protection_warned = 0;
140 for (i = 0; i < 16; i++) {
141 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
142 f = open(buf, O_RDONLY);
144 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
149 else if (errno == EACCES) {
150 if (!protection_warned) {
151 fgWarning ( "Can't open %s for read!", buf );
152 protection_warned = 1;
159 static int fghJoystickInitializeHID(struct os_specific_s *os,
160 int *num_axes, int *num_buttons)
162 int size, is_joystick;
163 # ifdef HAVE_USBHID_H
170 if ( ( rd = hid_get_report_desc( os->fd ) ) == 0 )
172 fgWarning ( "error: %s: %s", os->fname, strerror( errno ) );
178 # ifdef HAVE_USBHID_H
179 if( ioctl( os->fd, USB_GET_REPORT_ID, &report_id ) < 0)
181 /*** XXX {report_id} may not be the right variable? ***/
182 fgWarning ( "error: %s%d: %s", UHIDDEV, report_id, strerror( errno ) );
186 size = hid_report_size( rd, hid_input, report_id );
188 size = hid_report_size( rd, 0, hid_input );
190 os->hid_data_buf = calloc( 1, size );
194 # ifdef HAVE_USBHID_H
195 d = hid_start_parse( rd, 1 << hid_input, report_id );
197 d = hid_start_parse( rd, 1 << hid_input );
199 while( hid_get_item( d, &h ) )
201 int usage, page, interesting_hid;
203 page = HID_PAGE( h.usage );
204 usage = HID_USAGE( h.usage );
206 /* This test is somewhat too simplistic, but this is how MicroSoft
207 * does, so I guess it works for all joysticks/game pads. */
208 is_joystick = is_joystick ||
209 ( h.kind == hid_collection &&
210 page == HUP_GENERIC_DESKTOP &&
211 ( usage == HUG_JOYSTICK || usage == HUG_GAME_PAD ) );
213 if( h.kind != hid_input )
219 interesting_hid = TRUE;
220 if( page == HUP_GENERIC_DESKTOP )
231 if( *num_axes < _JS_MAX_AXES )
233 os->axes_usage[ *num_axes ] = usage;
238 /* Allocate two axes for a hat */
239 if( *num_axes + 1 < _JS_MAX_AXES )
241 os->axes_usage[ *num_axes ] = usage;
243 os->axes_usage[ *num_axes ] = usage;
248 interesting_hid = FALSE;
252 else if( page == HUP_BUTTON )
254 interesting_hid = ( usage > 0 ) &&
255 ( usage <= _JS_MAX_BUTTONS );
257 if( interesting_hid && usage - 1 > *num_buttons )
258 *num_buttons = usage - 1;
261 if( interesting_hid )
264 os->hids = calloc( 1, sizeof ( struct hid_item ) );
270 return os->hids != NULL;
276 * Functions associated with the "jsJoystick" class in PLIB
278 #if TARGET_HOST_MAC_OSX
279 #define K_NUM_DEVICES 32
281 io_object_t ioDevices[K_NUM_DEVICES];
283 static void fghJoystickFindDevices ( SFG_Joystick* joy, mach_port_t );
284 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick* joy, io_object_t );
286 static void fghJoystickEnumerateElements ( SFG_Joystick* joy, CFTypeRef element );
287 /* callback for CFArrayApply */
288 static void fghJoystickElementEnumerator ( SFG_Joystick* joy, void *element, void* vjs );
290 static void fghJoystickAddAxisElement ( SFG_Joystick* joy, CFDictionaryRef axis );
291 static void fghJoystickAddButtonElement ( SFG_Joystick* joy, CFDictionaryRef button );
292 static void fghJoystickAddHatElement ( SFG_Joystick* joy, CFDictionaryRef hat );
296 /* External function declarations (mostly platform-specific) */
297 extern void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes );
298 extern void fgPlatformJoystickOpen( SFG_Joystick* joy );
299 extern void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident );
300 extern void fgPlatformJoystickClose ( int ident );
303 * The static joystick structure pointer
305 #define MAX_NUM_JOYSTICKS 2
306 SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
309 * Read the raw joystick data
311 static void fghJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
320 for( i = 0; i < joy->num_axes; i++ )
326 fgPlatformJoystickRawRead ( joy, buttons, axes );
330 * Correct the joystick axis data
332 static float fghJoystickFudgeAxis( SFG_Joystick* joy, float value, int axis )
334 if( value < joy->center[ axis ] )
336 float xx = ( value - joy->center[ axis ] ) / ( joy->center[ axis ] -
339 if( xx < -joy->saturate[ axis ] )
342 if( xx > -joy->dead_band [ axis ] )
345 xx = ( xx + joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
346 joy->dead_band[ axis ] );
348 return ( xx < -1.0f ) ? -1.0f : xx;
352 float xx = ( value - joy->center [ axis ] ) / ( joy->max[ axis ] -
353 joy->center[ axis ] );
355 if( xx > joy->saturate[ axis ] )
358 if( xx < joy->dead_band[ axis ] )
361 xx = ( xx - joy->dead_band[ axis ] ) / ( joy->saturate[ axis ] -
362 joy->dead_band[ axis ] );
364 return ( xx > 1.0f ) ? 1.0f : xx;
369 * Read the corrected joystick data
371 static void fghJoystickRead( SFG_Joystick* joy, int* buttons, float* axes )
373 float raw_axes[ _JS_MAX_AXES ];
382 for ( i=0; i<joy->num_axes; i++ )
386 fghJoystickRawRead( joy, buttons, raw_axes );
389 for( i=0; i<joy->num_axes; i++ )
390 axes[ i ] = fghJoystickFudgeAxis( joy, raw_axes[ i ], i );
394 * Happy happy happy joy joy joy (happy new year toudi :D)
398 #if TARGET_HOST_MAC_OSX
399 /** open the IOKit connection, enumerate all the HID devices, add their
400 interface references to the static array. We then use the array index
401 as the device number when we come to open() the joystick. */
402 static int fghJoystickFindDevices ( SFG_Joystick *joy, mach_port_t masterPort )
404 CFMutableDictionaryRef hidMatch = NULL;
405 IOReturn rv = kIOReturnSuccess;
407 io_iterator_t hidIterator;
410 /* build a dictionary matching HID devices */
411 hidMatch = IOServiceMatching(kIOHIDDeviceKey);
413 rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
414 if (rv != kIOReturnSuccess || !hidIterator) {
415 fgWarning( "no joystick (HID) devices found" );
420 while ((ioDev = IOIteratorNext(hidIterator))) {
421 /* filter out keyboard and mouse devices */
422 CFDictionaryRef properties = getCFProperties(ioDev);
425 CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
426 CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
427 CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
428 CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
430 /* keep only joystick devices */
431 if ( ( page == kHIDPage_GenericDesktop ) && (
432 (usage == kHIDUsage_GD_Joystick)
433 || (usage == kHIDUsage_GD_GamePad)
434 || (usage == kHIDUsage_GD_MultiAxisController)
435 || (usage == kHIDUsage_GD_Hatswitch) /* last two necessary ? */
436 /* add it to the array */
437 ioDevices[numDevices++] = ioDev;
440 IOObjectRelease(hidIterator);
443 static CFDictionaryRef fghJoystickGetCFProperties ( SFG_Joystick *joy, io_object_t ioDev )
446 CFMutableDictionaryRef cfProperties;
449 /* comment copied from darwin/SDL_sysjoystick.c */
450 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
451 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
454 io_registry_entry_t parent1, parent2;
456 rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1);
457 if (rv != kIOReturnSuccess) {
458 fgWarning ( "error getting device entry parent");
462 rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2);
463 if (rv != kIOReturnSuccess) {
464 fgWarning ( "error getting device entry parent 2");
469 rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
470 &cfProperties, kCFAllocatorDefault, kNilOptions);
471 if (rv != kIOReturnSuccess || !cfProperties) {
472 fgWarning ( "error getting device properties");
479 static void fghJoystickElementEnumerator ( SFG_Joystick *joy, void *element, void* vjs )
481 if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
482 fgError ( "%s", "element enumerator passed non-dictionary value");
486 static_cast<jsJoystick*>(vjs)->parseElement ( (CFDictionaryRef) element );
489 /** element enumerator function : pass NULL for top-level*/
490 static void fghJoystickEnumerateElements ( SFG_Joystick *joy, CFTypeRef element )
492 FREEGLUT_INTERNAL_ERROR_EXIT( (CFGetTypeID(element) == CFArrayGetTypeID(),
493 "Joystick element type mismatch",
494 "fghJoystickEnumerateElements" );
496 CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
497 CFArrayApplyFunction((CFArrayRef) element, range,
498 &fghJoystickElementEnumerator, joy );
501 static void fghJoystickAddAxisElement ( SFG_Joystick *joy, CFDictionaryRef axis )
503 long cookie, lmin, lmax;
504 int index = joy->num_axes++;
506 CFNumberGetValue ((CFNumberRef)
507 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementCookieKey) ),
508 kCFNumberLongType, &cookie);
510 joy->pJoystick.axisCookies[index] = (IOHIDElementCookie) cookie;
512 CFNumberGetValue ((CFNumberRef)
513 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMinKey) ),
514 kCFNumberLongType, &lmin);
516 CFNumberGetValue ((CFNumberRef)
517 CFDictionaryGetValue ( axis, CFSTR(kIOHIDElementMaxKey) ),
518 kCFNumberLongType, &lmax);
520 joy->min[index] = lmin;
521 joy->max[index] = lmax;
522 joy->dead_band[index] = 0.0;
523 joy->saturate[index] = 1.0;
524 joy->center[index] = (lmax + lmin) * 0.5;
527 static void fghJoystickAddButtonElement ( SFG_Joystick *joy, CFDictionaryRef button )
530 CFNumberGetValue ((CFNumberRef)
531 CFDictionaryGetValue ( button, CFSTR(kIOHIDElementCookieKey) ),
532 kCFNumberLongType, &cookie);
534 joy->pJoystick.buttonCookies[num_buttons++] = (IOHIDElementCookie) cookie;
535 /* anything else for buttons? */
538 static void fghJoystickAddHatElement ( SFG_Joystick *joy, CFDictionaryRef button )
540 /* hatCookies[num_hats++] = (IOHIDElementCookie) cookie; */
541 /* do we map hats to axes or buttons? */
546 * Platform-Specific Code
549 #if TARGET_HOST_MACINTOSH
550 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
558 for ( i = 0; i < joy->num_buttons; i++ )
561 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i + ISP_NUM_AXIS ], &state);
564 *buttons |= state << i;
570 for ( i = 0; i < joy->num_axes; i++ )
573 int err = ISpElement_GetSimpleState ( joy->pJoystick.isp_elem [ i ], &state );
576 axes [i] = (float) state;
582 void fgPlatformJoystickOpen( SFG_Joystick* joy )
587 /* XXX FIXME: get joystick name in Mac */
593 #define ISP_CHECK_ERR(x) if( x != noErr ) { joy->error = GL_TRUE; return; }
595 joy->error = GL_TRUE;
597 /* initialize the needs structure */
598 ISpNeed temp_isp_needs[ ISP_NUM_NEEDS ] =
600 { "\pX-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
601 { "\pY-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
602 { "\pZ-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
603 { "\pR-Axis", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
604 { "\pAxis 4", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
605 { "\pAxis 5", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
606 { "\pAxis 6", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
607 { "\pAxis 7", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
608 { "\pAxis 8", 128, 0, 0, kISpElementKind_Axis, kISpElementLabel_None, 0, 0, 0, 0 },
610 { "\pButton 0", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
611 { "\pButton 1", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
612 { "\pButton 2", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
613 { "\pButton 3", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
614 { "\pButton 4", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
615 { "\pButton 5", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
616 { "\pButton 6", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
617 { "\pButton 7", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
618 { "\pButton 8", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
619 { "\pButton 9", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
620 { "\pButton 10", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
621 { "\pButton 11", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
622 { "\pButton 12", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
623 { "\pButton 13", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
624 { "\pButton 14", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
625 { "\pButton 15", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
626 { "\pButton 16", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
627 { "\pButton 17", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
628 { "\pButton 18", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
629 { "\pButton 19", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
630 { "\pButton 20", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
631 { "\pButton 21", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
632 { "\pButton 22", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
633 { "\pButton 23", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
634 { "\pButton 24", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
635 { "\pButton 25", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
636 { "\pButton 26", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
637 { "\pButton 27", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
638 { "\pButton 28", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
639 { "\pButton 29", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
640 { "\pButton 30", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
641 { "\pButton 31", 128, 0, 0, kISpElementKind_Button, kISpElementLabel_Btn_Select, 0, 0, 0, 0 },
644 memcpy( joy->pJoystick.isp_needs, temp_isp_needs, sizeof (temp_isp_needs ) );
647 /* next two calls allow keyboard and mouse to emulate other input
648 * devices (gamepads, joysticks, etc)
651 err = ISpDevices_ActivateClass ( kISpDeviceClass_Keyboard );
655 err = ISpDevices_ActivateClass ( kISpDeviceClass_Mouse );
659 err = ISpElement_NewVirtualFromNeeds( ISP_NUM_NEEDS,
660 joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
664 err = ISpInit( ISP_NUM_NEEDS, joy->pJoystick.isp_needs, joy->pJoystick.isp_elem,
665 'freeglut', nil, 0, 128, 0 );
668 joy->num_buttons = ISP_NUM_NEEDS - ISP_NUM_AXIS;
669 joy->num_axes = ISP_NUM_AXIS;
671 for( i = 0; i < joy->num_axes; i++ )
673 joy->dead_band[ i ] = 0;
674 joy->saturate [ i ] = 1;
675 joy->center [ i ] = kISpAxisMiddle;
676 joy->max [ i ] = kISpAxisMaximum;
677 joy->min [ i ] = kISpAxisMinimum;
680 joy->error = GL_FALSE;
683 joy->num_buttons = joy->num_axes = 0;
687 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
689 fgJoystick[ ident ]->id = ident;
690 snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */
691 fgJoystick[ ident ]->error = GL_FALSE;
695 void fgPlatformJoystickClose ( int ident )
703 #if TARGET_HOST_MAC_OSX
704 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
708 if ( buttons != NULL )
712 for ( i = 0; i < joy->num_buttons; i++ )
714 IOHIDEventStruct hidEvent;
715 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );
716 if ( hidEvent.value )
723 for ( i = 0; i < joy->num_axes; i++ )
725 IOHIDEventStruct hidEvent;
726 (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );
727 axes[i] = hidEvent.value;
733 void fgPlatformJoystickOpen( SFG_Joystick* joy )
737 IOCFPlugInInterface **plugin;
739 HRESULT pluginResult;
741 CFDictionaryRef props;
742 CFTypeRef topLevelElement;
744 if( joy->id >= numDevices )
746 fgWarning( "device index out of range in fgJoystickOpen()" );
750 /* create device interface */
751 rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],
752 kIOHIDDeviceUserClientTypeID,
753 kIOCFPlugInInterfaceID,
756 if( rv != kIOReturnSuccess )
758 fgWarning( "error creating plugin for io device" );
762 pluginResult = ( *plugin )->QueryInterface(
764 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
765 &( LPVOID )joy->pJoystick.hidDev
768 if( pluginResult != S_OK )
769 fgWarning ( "QI-ing IO plugin to HID Device interface failed" );
771 ( *plugin )->Release( plugin ); /* don't leak a ref */
772 if( joy->pJoystick.hidDev == NULL )
775 /* store the interface in this instance */
776 rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );
777 if( rv != kIOReturnSuccess )
779 fgWarning( "error opening device interface");
783 props = getCFProperties( ioDevices[ joy->id ] );
785 /* recursively enumerate all the bits */
786 CFTypeRef topLevelElement =
787 CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );
788 enumerateElements( topLevelElement );
794 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
796 fgJoystick[ ident ]->id = ident;
797 fgJoystick[ ident ]->error = GL_FALSE;
798 fgJoystick[ ident ]->num_axes = 0;
799 fgJoystick[ ident ]->num_buttons = 0;
803 /* do first-time init (since we can't over-ride jsInit, hmm */
806 mach_port_t masterPort;
807 IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );
808 if( rv != kIOReturnSuccess )
810 fgWarning( "error getting master Mach port" );
813 fghJoystickFindDevices( masterPort );
816 if ( ident >= numDevices )
818 fgJoystick[ ident ]->error = GL_TRUE;
822 /* get the name now too */
823 CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );
824 CFTypeRef ref = CFDictionaryGetValue( properties,
825 CFSTR( kIOHIDProductKey ) );
827 ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );
830 !CFStringGetCString( ( CFStringRef )ref, name, 128,
831 CFStringGetSystemEncoding( ) ) )
833 fgWarning( "error getting device name" );
839 void fgPlatformJoystickClose ( int ident )
841 ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->
842 close( fgJoystick[ ident ]->pJoystick.hidDev );
849 static void fghJoystickOpen( SFG_Joystick* joy )
852 * Default values (for no joystick -- each conditional will reset the
856 joy->num_axes = joy->num_buttons = 0;
857 joy->name[ 0 ] = '\0';
859 fgPlatformJoystickOpen ( joy );
864 * This function replaces the constructor method in the JS library.
866 static void fghJoystickInit( int ident )
868 if( ident >= MAX_NUM_JOYSTICKS )
869 fgError( "Too large a joystick number: %d", ident );
871 if( fgJoystick[ ident ] )
872 fgError( "illegal attempt to initialize joystick device again" );
874 fgJoystick[ ident ] =
875 ( SFG_Joystick * )calloc( sizeof( SFG_Joystick ), 1 );
878 fgJoystick[ ident ]->num_axes = fgJoystick[ ident ]->num_buttons = 0;
879 fgJoystick[ ident ]->error = GL_TRUE;
881 fgPlatformJoystickInit( fgJoystick, ident );
883 fghJoystickOpen( fgJoystick[ ident ] );
887 * Try initializing all the joysticks (well, both of them)
889 void fgInitialiseJoysticks ( void )
891 if( !fgState.JoysticksInitialised )
894 for ( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
895 fghJoystickInit( ident );
897 fgState.JoysticksInitialised = GL_TRUE;
902 void fgJoystickClose( void )
905 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
907 if( fgJoystick[ ident ] )
909 fgPlatformJoystickClose ( ident );
911 free( fgJoystick[ ident ] );
912 fgJoystick[ ident ] = NULL;
913 /* show joystick has been deinitialized */
919 * Polls the joystick and executes the joystick callback hooked to the
920 * window specified in the function's parameter:
922 void fgJoystickPollWindow( SFG_Window* window )
924 float axes[ _JS_MAX_AXES ];
928 freeglut_return_if_fail( window );
929 freeglut_return_if_fail( FETCH_WCB( *window, Joystick ) );
931 for( ident = 0; ident < MAX_NUM_JOYSTICKS; ident++ )
933 if( fgJoystick[ident] )
935 fghJoystickRead( fgJoystick[ident], &buttons, axes );
937 if( !fgJoystick[ident]->error )
938 INVOKE_WCB( *window, Joystick,
940 (int) ( axes[ 0 ] * 1000.0f ),
941 (int) ( axes[ 1 ] * 1000.0f ),
942 (int) ( axes[ 2 ] * 1000.0f ) )
949 * Implementation for glutDeviceGet(GLUT_HAS_JOYSTICK)
951 int fgJoystickDetect( void )
955 fgInitialiseJoysticks ();
957 if ( !fgState.JoysticksInitialised )
960 for( ident=0; ident<MAX_NUM_JOYSTICKS; ident++ )
961 if( fgJoystick[ident] && !fgJoystick[ident]->error )
968 * Joystick information, setup and execution functions
972 * Forces the joystick callback to be executed
974 void FGAPIENTRY glutForceJoystickFunc( void )
976 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutForceJoystickFunc" );
977 #if !defined(_WIN32_WCE)
978 freeglut_return_if_fail( fgStructure.CurrentWindow != NULL );
979 freeglut_return_if_fail( FETCH_WCB( *( fgStructure.CurrentWindow ), Joystick ) );
980 fgJoystickPollWindow( fgStructure.CurrentWindow );
981 #endif /* !defined(_WIN32_WCE) */
983 int glutJoystickGetNumAxes( int ident )
985 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumAxes" );
986 return fgJoystick[ ident ]->num_axes;
988 int glutJoystickGetNumButtons( int ident )
990 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetNumButtons" );
991 return fgJoystick[ ident ]->num_buttons;
993 int glutJoystickNotWorking( int ident )
995 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickNotWorking" );
996 return fgJoystick[ ident ]->error;
999 float glutJoystickGetDeadBand( int ident, int axis )
1001 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetDeadBand" );
1002 return fgJoystick[ ident ]->dead_band [ axis ];
1004 void glutJoystickSetDeadBand( int ident, int axis, float db )
1006 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetDeadBand" );
1007 fgJoystick[ ident ]->dead_band[ axis ] = db;
1010 float glutJoystickGetSaturation( int ident, int axis )
1012 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetSaturation" );
1013 return fgJoystick[ ident ]->saturate[ axis ];
1015 void glutJoystickSetSaturation( int ident, int axis, float st )
1017 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetSaturation" );
1018 fgJoystick[ ident ]->saturate [ axis ] = st;
1021 void glutJoystickSetMinRange( int ident, float *axes )
1023 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMinRange" );
1024 memcpy( fgJoystick[ ident ]->min, axes,
1025 fgJoystick[ ident ]->num_axes * sizeof( float ) );
1027 void glutJoystickSetMaxRange( int ident, float *axes )
1029 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetMaxRange" );
1030 memcpy( fgJoystick[ ident ]->max, axes,
1031 fgJoystick[ ident ]->num_axes * sizeof( float ) );
1033 void glutJoystickSetCenter( int ident, float *axes )
1035 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickSetCenter" );
1036 memcpy( fgJoystick[ ident ]->center, axes,
1037 fgJoystick[ ident ]->num_axes * sizeof( float ) );
1040 void glutJoystickGetMinRange( int ident, float *axes )
1042 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMinRange" );
1043 memcpy( axes, fgJoystick[ ident ]->min,
1044 fgJoystick[ ident ]->num_axes * sizeof( float ) );
1046 void glutJoystickGetMaxRange( int ident, float *axes )
1048 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetMaxRange" );
1049 memcpy( axes, fgJoystick[ ident ]->max,
1050 fgJoystick[ ident ]->num_axes * sizeof( float ) );
1052 void glutJoystickGetCenter( int ident, float *axes )
1054 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickGetCenter" );
1055 memcpy( axes, fgJoystick[ ident ]->center,
1056 fgJoystick[ ident ]->num_axes * sizeof( float ) );
1059 /*** END OF FILE ***/