146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* 246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL - Simple DirectMedia Layer 346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Copyright (C) 1997-2004 Sam Lantinga 446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner This library is free software; you can redistribute it and/or 646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner modify it under the terms of the GNU Library General Public 746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner License as published by the Free Software Foundation; either 846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner version 2 of the License, or (at your option) any later version. 946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner This library is distributed in the hope that it will be useful, 1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner but WITHOUT ANY WARRANTY; without even the implied warranty of 1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Library General Public License for more details. 1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner You should have received a copy of the GNU Library General Public 1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner License along with this library; if not, write to the Free 1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Sam Lantinga 2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner slouken@libsdl.org 2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/ 2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h" 2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef SDL_JOYSTICK_IOKIT 2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* SDL joystick driver for Darwin / Mac OS X, based on the IOKit HID API */ 2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Written 2001 by Max Horn */ 2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <unistd.h> 3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <ctype.h> 3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <sysexits.h> 3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <mach/mach.h> 3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <mach/mach_error.h> 3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <IOKit/IOKitLib.h> 3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <IOKit/IOCFPlugIn.h> 3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef MACOS_10_0_4 3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <IOKit/hidsystem/IOHIDUsageTables.h> 3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else 3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* The header was moved here in Mac OS X 10.1 */ 4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> 4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif 4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <IOKit/hid/IOHIDLib.h> 4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <IOKit/hid/IOHIDKeys.h> 4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <CoreFoundation/CoreFoundation.h> 4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <Carbon/Carbon.h> /* for NewPtrClear, DisposePtr */ 4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_joystick.h" 4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_sysjoystick.h" 4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "../SDL_joystick_c.h" 5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstruct recElement 5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */ 5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long min; /* reported min value possible */ 5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long max; /* reported max value possible */ 5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if 0 5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* TODO: maybe should handle the following stuff somehow? */ 5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long scaledMin; /* reported scaled min value possible */ 6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long scaledMax; /* reported scaled max value possible */ 6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long size; /* size in bits of data return from element */ 6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Boolean relative; /* are reports relative to last report (deltas) */ 6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Boolean wrapping; /* does element wrap around (one value higher than max is min) */ 6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Boolean nonLinear; /* are the values reported non-linear relative to element movement */ 6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Boolean preferredState; /* does element have a preferred state (such as a button) */ 6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Boolean nullState; /* does element have null state */ 6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif /* 0 */ 6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* runtime variables used for auto-calibration */ 7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long minReport; /* min returned value */ 7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long maxReport; /* max returned value */ 7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner struct recElement * pNext; /* next element in list */ 7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}; 7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnertypedef struct recElement recElement; 7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstruct joystick_hwdata 7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOHIDDeviceInterface ** interface; /* interface to device, NULL = no interface */ 8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char product[256]; /* name of product */ 8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long usage; /* usage page from IOUSBHID Parser.h which defines general usage */ 8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */ 8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long axes; /* number of axis (calculated, not reported by device) */ 8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long buttons; /* number of buttons (calculated, not reported by device) */ 8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long hats; /* number of hat switches (calculated, not reported by device) */ 8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long elements; /* number of total elements (shouldbe total of above) (calculated, not reported by device) */ 8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement* firstAxis; 9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement* firstButton; 9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement* firstHat; 9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int removed; 9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int uncentered; 9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner struct joystick_hwdata* pNext; /* next device */ 9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}; 9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnertypedef struct joystick_hwdata recDevice; 10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Linked list of all available devices */ 10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic recDevice *gpDeviceList = NULL; 10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDReportErrorNum (char * strError, long numError) 10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError(strError); 10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice); 11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* returns current value for element, polling element 11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * will return 0 on error conditions which should be accounted for by application 11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic SInt32 HIDGetElementValue (recDevice *pDevice, recElement *pElement) 11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOReturn result = kIOReturnSuccess; 12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOHIDEventStruct hidEvent; 12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner hidEvent.value = 0; 12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (NULL != pDevice && NULL != pElement && NULL != pDevice->interface) 12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = (*(pDevice->interface))->getElementValue(pDevice->interface, pElement->cookie, &hidEvent); 12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess == result) 12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* record min and max for auto calibration */ 12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (hidEvent.value < pElement->minReport) 13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->minReport = hidEvent.value; 13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (hidEvent.value > pElement->maxReport) 13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->maxReport = hidEvent.value; 13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* auto user scale */ 13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return hidEvent.value; 13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic SInt32 HIDScaledCalibratedValue (recDevice *pDevice, recElement *pElement, long min, long max) 14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner float deviceScale = max - min; 14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner float readScale = pElement->maxReport - pElement->minReport; 14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SInt32 value = HIDGetElementValue(pDevice, pElement); 14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (readScale == 0) 14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return value; /* no scaling at all */ 14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return ((value - pElement->minReport) * deviceScale / readScale) + min; 14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDRemovalCallback(void * target, 15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOReturn result, 15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner void * refcon, 15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner void * sender) 15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *device = (recDevice *) refcon; 15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device->removed = 1; 15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device->uncentered = 1; 16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Create and open an interface to device, required prior to extracting values or building queues. 16546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * Note: appliction now owns the device and must close and release it prior to exiting 16646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 16746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 16846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic IOReturn HIDCreateOpenDeviceInterface (io_object_t hidDevice, recDevice *pDevice) 16946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 17046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOReturn result = kIOReturnSuccess; 17146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HRESULT plugInResult = S_OK; 17246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SInt32 score = 0; 17346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOCFPlugInInterface ** ppPlugInInterface = NULL; 17446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 17546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (NULL == pDevice->interface) 17646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 17746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID, 17846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner kIOCFPlugInInterfaceID, &ppPlugInInterface, &score); 17946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess == result) 18046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 18146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Call a method of the intermediate plug-in to create the device interface */ 18246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface, 18346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &(pDevice->interface)); 18446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (S_OK != plugInResult) 18546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("Couldn�t query HID class device interface from plugInInterface", plugInResult); 18646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (*ppPlugInInterface)->Release (ppPlugInInterface); 18746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 18846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 18946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result); 19046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 19146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (NULL != pDevice->interface) 19246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 19346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = (*(pDevice->interface))->open (pDevice->interface, 0); 19446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != result) 19546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("Failed to open pDevice->interface via open.", result); 19646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 19746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (*(pDevice->interface))->setRemovalCallback (pDevice->interface, HIDRemovalCallback, pDevice, pDevice); 19846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 19946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 20046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return result; 20146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 20246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 20346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Closes and releases interface to device, should be done prior to exting application 20446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * Note: will have no affect if device or interface do not exist 20546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * application will "own" the device if interface is not closed 20646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * (device may have to be plug and re-plugged in different location to get it working again without a restart) 20746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 20846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 20946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic IOReturn HIDCloseReleaseInterface (recDevice *pDevice) 21046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 21146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOReturn result = kIOReturnSuccess; 21246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 21346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ((NULL != pDevice) && (NULL != pDevice->interface)) 21446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 21546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* close the interface */ 21646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = (*(pDevice->interface))->close (pDevice->interface); 21746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnNotOpen == result) 21846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 21946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* do nothing as device was not opened, thus can't be closed */ 22046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 22146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else if (kIOReturnSuccess != result) 22246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("Failed to close IOHIDDeviceInterface.", result); 22346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* release the interface */ 22446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = (*(pDevice->interface))->Release (pDevice->interface); 22546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != result) 22646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("Failed to release IOHIDDeviceInterface.", result); 22746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice->interface = NULL; 22846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 22946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return result; 23046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 23146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 23246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* extracts actual specific element information from each element CF dictionary entry */ 23346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 23446be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDGetElementInfo (CFTypeRef refElement, recElement *pElement) 23546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 23646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long number; 23746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refType; 23846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 23946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementCookieKey)); 24046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 24146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->cookie = (IOHIDElementCookie) number; 24246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMinKey)); 24346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 24446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->minReport = pElement->min = number; 24546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMaxKey)); 24646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 24746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->maxReport = pElement->max = number; 24846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* 24946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner TODO: maybe should handle the following stuff somehow? 25046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 25146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey)); 25246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 25346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->scaledMin = number; 25446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMaxKey)); 25546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 25646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->scaledMax = number; 25746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementSizeKey)); 25846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 25946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->size = number; 26046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsRelativeKey)); 26146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType) 26246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->relative = CFBooleanGetValue (refType); 26346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsWrappingKey)); 26446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType) 26546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->wrapping = CFBooleanGetValue (refType); 26646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsNonLinearKey)); 26746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType) 26846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->nonLinear = CFBooleanGetValue (refType); 26946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasPreferedStateKey)); 27046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType) 27146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->preferredState = CFBooleanGetValue (refType); 27246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey)); 27346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refType) 27446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement->nullState = CFBooleanGetValue (refType); 27546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/ 27646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 27746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 27846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* examines CF dictionary vlaue in device element hierarchy to determine if it is element of interest or a collection of more elements 27946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * if element of interest allocate storage, add to list and retrieve element specific info 28046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * if collection then pass on to deconstruction collection into additional individual elements 28146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 28246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 28346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDAddElement (CFTypeRef refElement, recDevice* pDevice) 28446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 28546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement* element = NULL; 28646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement** headElement = NULL; 28746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner long elementType, usagePage, usage; 28846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refElementType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementTypeKey)); 28946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refUsagePage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsagePageKey)); 29046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refUsage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsageKey)); 29146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 29246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 29346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ((refElementType) && (CFNumberGetValue (refElementType, kCFNumberLongType, &elementType))) 29446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 29546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* look at types of interest */ 29646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) || 29746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (elementType == kIOHIDElementTypeInput_Axis)) 29846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 29946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refUsagePage && CFNumberGetValue (refUsagePage, kCFNumberLongType, &usagePage) && 30046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refUsage && CFNumberGetValue (refUsage, kCFNumberLongType, &usage)) 30146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 30246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */ 30346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 30446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDPage_GenericDesktop: 30546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 30646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch (usage) /* look at usage to determine function */ 30746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 30846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_X: 30946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Y: 31046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Z: 31146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Rx: 31246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Ry: 31346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Rz: 31446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Slider: 31546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Dial: 31646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Wheel: 31746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = (recElement *) NewPtrClear (sizeof (recElement)); 31846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (element) 31946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 32046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice->axes++; 32146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner headElement = &(pDevice->firstAxis); 32246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 32346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 32446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDUsage_GD_Hatswitch: 32546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = (recElement *) NewPtrClear (sizeof (recElement)); 32646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (element) 32746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 32846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice->hats++; 32946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner headElement = &(pDevice->firstHat); 33046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 33146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 33246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 33346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 33446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 33546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case kHIDPage_Button: 33646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = (recElement *) NewPtrClear (sizeof (recElement)); 33746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (element) 33846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 33946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice->buttons++; 34046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner headElement = &(pDevice->firstButton); 34146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 34246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 34346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner default: 34446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 34546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 34646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 34746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 34846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else if (kIOHIDElementTypeCollection == elementType) 34946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDGetCollectionElements ((CFMutableDictionaryRef) refElement, pDevice); 35046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 35146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 35246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (element && headElement) /* add to list */ 35346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 35446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice->elements++; 35546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (NULL == *headElement) 35646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *headElement = element; 35746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 35846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 35946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement *elementPrevious, *elementCurrent; 36046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner elementCurrent = *headElement; 36146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (elementCurrent) 36246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 36346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner elementPrevious = elementCurrent; 36446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner elementCurrent = elementPrevious->pNext; 36546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 36646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner elementPrevious->pNext = element; 36746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 36846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element->pNext = NULL; 36946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDGetElementInfo (refElement, element); 37046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 37146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 37246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 37346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* collects information from each array member in device element list (each array memeber = element) */ 37446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 37546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDGetElementsCFArrayHandler (const void * value, void * parameter) 37646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 37746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (CFGetTypeID (value) == CFDictionaryGetTypeID ()) 37846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDAddElement ((CFTypeRef) value, (recDevice *) parameter); 37946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 38046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 38146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* handles retrieval of element information from arrays of elements in device IO registry information */ 38246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 38346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDGetElements (CFTypeRef refElementCurrent, recDevice *pDevice) 38446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 38546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeID type = CFGetTypeID (refElementCurrent); 38646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (type == CFArrayGetTypeID()) /* if element is an array */ 38746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 38846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFRange range = {0, CFArrayGetCount (refElementCurrent)}; 38946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* CountElementsCFArrayHandler called for each array member */ 39046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFArrayApplyFunction (refElementCurrent, range, HIDGetElementsCFArrayHandler, pDevice); 39146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 39246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 39346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 39446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* handles extracting element information from element collection CF types 39546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * used from top level element decoding and hierarchy deconstruction to flatten device element list 39646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 39746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 39846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice) 39946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 40046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refElementTop = CFDictionaryGetValue (deviceProperties, CFSTR(kIOHIDElementKey)); 40146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refElementTop) 40246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDGetElements (refElementTop, pDevice); 40346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 40446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 40546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */ 40646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 40746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDTopLevelElementHandler (const void * value, void * parameter) 40846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 40946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refCF = 0; 41046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) 41146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return; 41246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsagePageKey)); 41346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage)) 41446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage."); 41546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsageKey)); 41646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage)) 41746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage."); 41846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 41946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 42046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* extracts device info from CF dictionary records in IO registry */ 42146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 42246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDGetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, recDevice *pDevice) 42346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 42446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFMutableDictionaryRef usbProperties = 0; 42546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner io_registry_entry_t parent1, parent2; 42646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 42746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also 42846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties 42946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 43046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) && 43146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) && 43246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) 43346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 43446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (usbProperties) 43546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 43646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refCF = 0; 43746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* get device info 43846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * try hid dictionary first, if fail then go to usb dictionary 43946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 44046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 44146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 44246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* get product name */ 44346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey)); 44446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!refCF) 44546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name")); 44646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refCF) 44746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 44846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!CFStringGetCString (refCF, pDevice->product, 256, CFStringGetSystemEncoding ())) 44946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("CFStringGetCString error retrieving pDevice->product."); 45046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 45146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 45246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* get usage page and usage */ 45346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); 45446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refCF) 45546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 45646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage)) 45746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage."); 45846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); 45946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (refCF) 46046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage)) 46146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage."); 46246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 46346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 46446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (NULL == refCF) /* get top level element HID usage page or usage */ 46546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 46646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* use top level element instead */ 46746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFTypeRef refCFTopElement = 0; 46846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey)); 46946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 47046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* refCFTopElement points to an array of element dictionaries */ 47146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFRange range = {0, CFArrayGetCount (refCFTopElement)}; 47246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFArrayApplyFunction (refCFTopElement, range, HIDTopLevelElementHandler, pDevice); 47346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 47446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 47546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 47646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFRelease (usbProperties); 47746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 47846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 47946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("IORegistryEntryCreateCFProperties failed to create usbProperties."); 48046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 48146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != IOObjectRelease (parent2)) 48246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("IOObjectRelease error with parent2."); 48346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != IOObjectRelease (parent1)) 48446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError ("IOObjectRelease error with parent1."); 48546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 48646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 48746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 48846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 48946be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic recDevice *HIDBuildDevice (io_object_t hidDevice) 49046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 49146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *pDevice = (recDevice *) NewPtrClear (sizeof (recDevice)); 49246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (pDevice) 49346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 49446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* get dictionary for HID properties */ 49546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFMutableDictionaryRef hidProperties = 0; 49646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner kern_return_t result = IORegistryEntryCreateCFProperties (hidDevice, &hidProperties, kCFAllocatorDefault, kNilOptions); 49746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ((result == KERN_SUCCESS) && hidProperties) 49846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 49946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* create device interface */ 50046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = HIDCreateOpenDeviceInterface (hidDevice, pDevice); 50146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess == result) 50246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 50346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDGetDeviceInfo (hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */ 50446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDGetCollectionElements (hidProperties, pDevice); 50546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 50646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 50746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 50846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner DisposePtr((Ptr)pDevice); 50946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice = NULL; 51046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 51146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFRelease (hidProperties); 51246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 51346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 51446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 51546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner DisposePtr((Ptr)pDevice); 51646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDevice = NULL; 51746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 51846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 51946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return pDevice; 52046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 52146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 52246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* disposes of the element list associated with a device and the memory associated with the list 52346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 52446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 52546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic void HIDDisposeElementList (recElement **elementList) 52646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 52746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement *pElement = *elementList; 52846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (pElement) 52946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 53046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement *pElementNext = pElement->pNext; 53146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner DisposePtr ((Ptr) pElement); 53246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pElement = pElementNext; 53346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 53446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *elementList = NULL; 53546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 53646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 53746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL 53846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * all your device no longer belong to us... (i.e., you do not 'own' the device anymore) 53946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 54046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 54146be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic recDevice *HIDDisposeDevice (recDevice **ppDevice) 54246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 54346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner kern_return_t result = KERN_SUCCESS; 54446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *pDeviceNext = NULL; 54546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (*ppDevice) 54646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 54746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* save next device prior to disposing of this device */ 54846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pDeviceNext = (*ppDevice)->pNext; 54946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 55046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* free element lists */ 55146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDDisposeElementList (&(*ppDevice)->firstAxis); 55246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDDisposeElementList (&(*ppDevice)->firstButton); 55346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDDisposeElementList (&(*ppDevice)->firstHat); 55446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 55546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = HIDCloseReleaseInterface (*ppDevice); /* function sanity checks interface value (now application does not own device) */ 55646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != result) 55746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("HIDCloseReleaseInterface failed when trying to dipose device.", result); 55846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner DisposePtr ((Ptr)*ppDevice); 55946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *ppDevice = NULL; 56046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 56146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return pDeviceNext; 56246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 56346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 56446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 56546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Function to scan the system for joysticks. 56646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * Joystick 0 should be the system default joystick. 56746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * This function should return the number of available joysticks, or -1 56846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * on an unrecoverable fatal error. 56946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 57046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SYS_JoystickInit(void) 57146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 57246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner IOReturn result = kIOReturnSuccess; 57346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner mach_port_t masterPort = 0; 57446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner io_iterator_t hidObjectIterator = 0; 57546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFMutableDictionaryRef hidMatchDictionary = NULL; 57646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *device, *lastDevice; 57746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner io_object_t ioHIDDeviceObject = 0; 57846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 57946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_numjoysticks = 0; 58046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 58146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (gpDeviceList) 58246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 58346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError("Joystick: Device list already inited."); 58446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return -1; 58546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 58646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 58746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = IOMasterPort (bootstrap_port, &masterPort); 58846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != result) 58946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 59046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError("Joystick: IOMasterPort error with bootstrap_port."); 59146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return -1; 59246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 59346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 59446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Set up a matching dictionary to search I/O Registry by class name for all HID class devices. */ 59546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner hidMatchDictionary = IOServiceMatching (kIOHIDDeviceKey); 59646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (hidMatchDictionary) 59746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 59846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Add key for device type (joystick, in this case) to refine the matching dictionary. */ 59946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 60046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* NOTE: we now perform this filtering later 60146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner UInt32 usagePage = kHIDPage_GenericDesktop; 60246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner UInt32 usage = kHIDUsage_GD_Joystick; 60346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFNumberRef refUsage = NULL, refUsagePage = NULL; 60446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 60546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage); 60646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage); 60746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage); 60846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage); 60946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 61046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 61146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 61246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 61346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching."); 61446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return -1; 61546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 61646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 61746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /*/ Now search I/O Registry for matching devices. */ 61846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = IOServiceGetMatchingServices (masterPort, hidMatchDictionary, &hidObjectIterator); 61946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Check for errors */ 62046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (kIOReturnSuccess != result) 62146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 62246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_SetError("Joystick: Couldn't create a HID object iterator."); 62346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return -1; 62446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 62546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!hidObjectIterator) /* there are no joysticks */ 62646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 62746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner gpDeviceList = NULL; 62846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_numjoysticks = 0; 62946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return 0; 63046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 63146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. */ 63246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 63346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* build flat linked list of devices from device iterator */ 63446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 63546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner gpDeviceList = lastDevice = NULL; 63646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 63746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while ((ioHIDDeviceObject = IOIteratorNext (hidObjectIterator))) 63846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 63946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* build a device record */ 64046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device = HIDBuildDevice (ioHIDDeviceObject); 64146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (!device) 64246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner continue; 64346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 64446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* dump device object, it is no longer needed */ 64546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = IOObjectRelease (ioHIDDeviceObject); 64646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* if (KERN_SUCCESS != result) 64746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result); 64846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/ 64946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 65046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Filter device list to non-keyboard/mouse stuff */ 65146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (device->usagePage != kHIDPage_GenericDesktop) || 65246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ((device->usage != kHIDUsage_GD_Joystick && 65346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device->usage != kHIDUsage_GD_GamePad && 65446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device->usage != kHIDUsage_GD_MultiAxisController)) ) { 65546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 65646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* release memory for the device */ 65746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner HIDDisposeDevice (&device); 65846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner DisposePtr((Ptr)device); 65946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner continue; 66046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 66146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 66246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Add device to the end of the list */ 66346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (lastDevice) 66446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lastDevice->pNext = device; 66546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else 66646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner gpDeviceList = device; 66746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lastDevice = device; 66846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 66946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner result = IOObjectRelease (hidObjectIterator); /* release the iterator */ 67046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 67146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Count the total number of devices we found */ 67246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device = gpDeviceList; 67346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (device) 67446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 67546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_numjoysticks++; 67646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device = device->pNext; 67746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 67846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 67946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_numjoysticks; 68046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 68146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 68246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Function to get the device-dependent name of a joystick */ 68346be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerconst char *SDL_SYS_JoystickName(int index) 68446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 68546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *device = gpDeviceList; 68646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 68746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner for (; index > 0; index--) 68846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device = device->pNext; 68946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 69046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return device->product; 69146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 69246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 69346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Function to open a joystick for use. 69446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * The joystick to open is specified by the index field of the joystick. 69546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * This should fill the nbuttons and naxes fields of the joystick structure. 69646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * It returns 0, or -1 if there is an error. 69746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 69846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_SYS_JoystickOpen(SDL_Joystick *joystick) 69946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 70046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *device = gpDeviceList; 70146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int index; 70246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 70346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner for (index = joystick->index; index > 0; index--) 70446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device = device->pNext; 70546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 70646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner joystick->hwdata = device; 70746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner joystick->name = device->product; 70846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 70946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner joystick->naxes = device->axes; 71046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner joystick->nhats = device->hats; 71146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner joystick->nballs = 0; 71246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner joystick->nbuttons = device->buttons; 71346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 71446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return 0; 71546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 71646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 71746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Function to update the state of a joystick - called as a device poll. 71846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * This function shouldn't update the joystick structure directly, 71946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * but instead should call SDL_PrivateJoystick*() to deliver events 72046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * and update joystick device state. 72146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 72246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnervoid SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) 72346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 72446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recDevice *device = joystick->hwdata; 72546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner recElement *element; 72646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SInt32 value; 72746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int i; 72846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 72946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (device->removed) /* device was unplugged; ignore it. */ 73046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 73146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (device->uncentered) 73246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 73346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner device->uncentered = 0; 73446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 73546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Tell the app that everything is centered/unpressed... */ 73646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner for (i = 0; i < device->axes; i++) 73746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_PrivateJoystickAxis(joystick, i, 0); 73846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 73946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner for (i = 0; i < device->buttons; i++) 74046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_PrivateJoystickButton(joystick, i, 0); 74146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 74246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner for (i = 0; i < device->hats; i++) 74346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); 74446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 74546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 74646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return; 74746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 74846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 74946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = device->firstAxis; 75046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner i = 0; 75146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (element) 75246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 75346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner value = HIDScaledCalibratedValue(device, element, -32768, 32767); 75446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( value != joystick->axes[i] ) 75546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_PrivateJoystickAxis(joystick, i, value); 75646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = element->pNext; 75746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++i; 75846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 75946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 76046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = device->firstButton; 76146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner i = 0; 76246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (element) 76346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 76446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner value = HIDGetElementValue(device, element); 76546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (value > 1) /* handle pressure-sensitive buttons */ 76646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner value = 1; 76746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( value != joystick->buttons[i] ) 76846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_PrivateJoystickButton(joystick, i, value); 76946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = element->pNext; 77046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++i; 77146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 77246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 77346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = device->firstHat; 77446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner i = 0; 77546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (element) 77646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 77746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 pos = 0; 77846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 77946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner value = HIDGetElementValue(device, element); 78046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (element->max == 3) /* 4 position hatswitch - scale up value */ 78146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner value *= 2; 78246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner else if (element->max != 7) /* Neither a 4 nor 8 positions - fall back to default position (centered) */ 78346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner value = -1; 78446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch(value) 78546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 78646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 0: 78746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_UP; 78846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 78946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 1: 79046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_RIGHTUP; 79146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 79246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 2: 79346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_RIGHT; 79446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 79546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 3: 79646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_RIGHTDOWN; 79746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 79846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 4: 79946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_DOWN; 80046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 80146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 5: 80246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_LEFTDOWN; 80346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 80446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 6: 80546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_LEFT; 80646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 80746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case 7: 80846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_LEFTUP; 80946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 81046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner default: 81146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Every other value is mapped to center. We do that because some 81246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * joysticks use 8 and some 15 for this value, and apparently 81346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner * there are even more variants out there - so we try to be generous. 81446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 81546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner pos = SDL_HAT_CENTERED; 81646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 81746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 81846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( pos != joystick->hats[i] ) 81946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_PrivateJoystickHat(joystick, i, pos); 82046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner element = element->pNext; 82146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++i; 82246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 82346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 82446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return; 82546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 82646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 82746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Function to close a joystick after use */ 82846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnervoid SDL_SYS_JoystickClose(SDL_Joystick *joystick) 82946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 83046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Should we do anything here? */ 83146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return; 83246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 83346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 83446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Function to perform any system-specific joystick related cleanup */ 83546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnervoid SDL_SYS_JoystickQuit(void) 83646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 83746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while (NULL != gpDeviceList) 83846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner gpDeviceList = HIDDisposeDevice (&gpDeviceList); 83946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 84046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 84146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif /* SDL_JOYSTICK_IOKIT */ 842