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