+\r
+ joy->error = GL_FALSE;\r
+ }\r
+ else\r
+ joy->num_buttons = joy->num_axes = 0;\r
+}\r
+\r
+\r
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
+{\r
+ fgJoystick[ ident ]->id = ident;\r
+ snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident ); /* FIXME */\r
+ fgJoystick[ ident ]->error = GL_FALSE;\r
+}\r
+\r
+\r
+void fgPlatformJoystickClose ( int ident )\r
+{\r
+ ISpSuspend( );\r
+ ISpStop( );\r
+ ISpShutdown( );\r
+}\r
+#endif\r
+\r
+#if TARGET_HOST_MAC_OSX\r
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
+{\r
+ int i;\r
+\r
+ if ( buttons != NULL )\r
+ {\r
+ *buttons = 0;\r
+\r
+ for ( i = 0; i < joy->num_buttons; i++ )\r
+ {\r
+ IOHIDEventStruct hidEvent;\r
+ (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.buttonCookies[i], &hidEvent );\r
+ if ( hidEvent.value )\r
+ *buttons |= 1 << i;\r
+ }\r
+ }\r
+\r
+ if ( axes != NULL )\r
+ {\r
+ for ( i = 0; i < joy->num_axes; i++ )\r
+ {\r
+ IOHIDEventStruct hidEvent;\r
+ (*(joy->pJoystick.hidDev))->getElementValue ( joy->pJoystick.hidDev, joy->pJoystick.axisCookies[i], &hidEvent );\r
+ axes[i] = hidEvent.value;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+void fgPlatformJoystickOpen( SFG_Joystick* joy )\r
+{\r
+ IOReturn rv;\r
+ SInt32 score;\r
+ IOCFPlugInInterface **plugin;\r
+\r
+ HRESULT pluginResult;\r
+\r
+ CFDictionaryRef props;\r
+ CFTypeRef topLevelElement;\r
+\r
+ if( joy->id >= numDevices )\r
+ {\r
+ fgWarning( "device index out of range in fgJoystickOpen()" );\r
+ return;\r
+ }\r
+\r
+ /* create device interface */\r
+ rv = IOCreatePlugInInterfaceForService( ioDevices[ joy->id ],\r
+ kIOHIDDeviceUserClientTypeID,\r
+ kIOCFPlugInInterfaceID,\r
+ &plugin, &score );\r
+\r
+ if( rv != kIOReturnSuccess )\r
+ {\r
+ fgWarning( "error creating plugin for io device" );\r
+ return;\r
+ }\r
+\r
+ pluginResult = ( *plugin )->QueryInterface(\r
+ plugin,\r
+ CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),\r
+ &( LPVOID )joy->pJoystick.hidDev\r
+ );\r
+\r
+ if( pluginResult != S_OK )\r
+ fgWarning ( "QI-ing IO plugin to HID Device interface failed" );\r
+\r
+ ( *plugin )->Release( plugin ); /* don't leak a ref */\r
+ if( joy->pJoystick.hidDev == NULL )\r
+ return;\r
+\r
+ /* store the interface in this instance */\r
+ rv = ( *( joy->pJoystick.hidDev ) )->open( joy->pJoystick.hidDev, 0 );\r
+ if( rv != kIOReturnSuccess )\r
+ {\r
+ fgWarning( "error opening device interface");\r
+ return;\r
+ }\r
+\r
+ props = getCFProperties( ioDevices[ joy->id ] );\r
+\r
+ /* recursively enumerate all the bits */\r
+ CFTypeRef topLevelElement =\r
+ CFDictionaryGetValue( props, CFSTR( kIOHIDElementKey ) );\r
+ enumerateElements( topLevelElement );\r
+\r
+ CFRelease( props );\r
+}\r
+\r
+\r
+void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )\r
+{\r
+ fgJoystick[ ident ]->id = ident;\r
+ fgJoystick[ ident ]->error = GL_FALSE;\r
+ fgJoystick[ ident ]->num_axes = 0;\r
+ fgJoystick[ ident ]->num_buttons = 0;\r
+\r
+ if( numDevices < 0 )\r
+ {\r
+ /* do first-time init (since we can't over-ride jsInit, hmm */\r
+ numDevices = 0;\r
+\r
+ mach_port_t masterPort;\r
+ IOReturn rv = IOMasterPort( bootstrap_port, &masterPort );\r
+ if( rv != kIOReturnSuccess )\r
+ {\r
+ fgWarning( "error getting master Mach port" );\r
+ return;\r
+ }\r
+ fghJoystickFindDevices( masterPort );\r
+ }\r
+\r
+ if ( ident >= numDevices )\r
+ {\r
+ fgJoystick[ ident ]->error = GL_TRUE;\r
+ return;\r
+ }\r
+\r
+ /* get the name now too */\r
+ CFDictionaryRef properties = getCFProperties( ioDevices[ ident ] );\r
+ CFTypeRef ref = CFDictionaryGetValue( properties,\r
+ CFSTR( kIOHIDProductKey ) );\r
+ if (!ref)\r
+ ref = CFDictionaryGetValue(properties, CFSTR( "USB Product Name" ) );\r
+\r
+ if( !ref ||\r
+ !CFStringGetCString( ( CFStringRef )ref, name, 128,\r
+ CFStringGetSystemEncoding( ) ) )\r
+ {\r
+ fgWarning( "error getting device name" );\r
+ name[ 0 ] = '\0';\r
+ }\r
+}\r
+\r
+\r
+void fgPlatformJoystickClose ( int ident )\r
+{\r
+ ( *( fgJoystick[ ident ]->pJoystick.hidDev ) )->\r
+ close( fgJoystick[ ident ]->pJoystick.hidDev );\r
+}\r
+#endif\r
+\r
+#if TARGET_HOST_POSIX_X11\r
+void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )\r
+{\r
+ int status;\r
+\r
+ int i;\r
+\r
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)\r
+ int len;\r
+\r
+ if ( joy->pJoystick.os->is_analog )\r
+ {\r
+ int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) );\r
+ if ( status != sizeof(joy->pJoystick.os->ajs) ) {\r
+ perror ( joy->pJoystick.os->fname );\r
+ joy->error = GL_TRUE;\r
+ return;\r
+ }\r
+ if ( buttons != NULL )\r
+ *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );\r
+\r
+ if ( axes != NULL )\r
+ {\r
+ axes[0] = (float) joy->pJoystick.os->ajs.x;\r
+ axes[1] = (float) joy->pJoystick.os->ajs.y;\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+# ifdef HAVE_USB_JS\r
+ while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen )\r
+ {\r
+ struct hid_item *h;\r
+\r
+ for ( h = joy->pJoystick.os->hids; h; h = h->next )\r
+ {\r
+ int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );\r
+\r
+ int page = HID_PAGE ( h->usage );\r
+ int usage = HID_USAGE ( h->usage );\r
+\r
+ if ( page == HUP_GENERIC_DESKTOP )\r
+ {\r
+ int i;\r
+ for ( i = 0; i < joy->num_axes; i++ )\r
+ if (joy->pJoystick.os->axes_usage[i] == usage)\r
+ {\r
+ if (usage == HUG_HAT_SWITCH)\r
+ {\r
+ if (d < 0 || d > 8)\r
+ d = 0; /* safety */\r
+ joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d];\r
+ joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d];\r
+ }\r
+ else\r
+ {\r
+ joy->pJoystick.os->cache_axes[i] = (float)d;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ else if (page == HUP_BUTTON)\r
+ {\r
+ if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)\r
+ {\r
+ if (d)\r
+ joy->pJoystick.os->cache_buttons |= (1 << ( usage - 1 ));\r
+ else\r
+ joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));\r
+ }\r
+ }\r
+ }\r