comparison src/joystick/darwin/SDL_sysjoystick.c @ 1895:c121d94672cb

SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 10 Jul 2006 21:04:37 +0000
parents 92947e3a18db
children b0048df1701a
comparison
equal deleted inserted replaced
1894:c69cee13dd76 1895:c121d94672cb
40 #include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> 40 #include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
41 #endif 41 #endif
42 #include <IOKit/hid/IOHIDLib.h> 42 #include <IOKit/hid/IOHIDLib.h>
43 #include <IOKit/hid/IOHIDKeys.h> 43 #include <IOKit/hid/IOHIDKeys.h>
44 #include <CoreFoundation/CoreFoundation.h> 44 #include <CoreFoundation/CoreFoundation.h>
45 #include <Carbon/Carbon.h> /* for NewPtrClear, DisposePtr */ 45 #include <Carbon/Carbon.h> /* for NewPtrClear, DisposePtr */
46 46
47 #include "SDL_joystick.h" 47 #include "SDL_joystick.h"
48 #include "../SDL_sysjoystick.h" 48 #include "../SDL_sysjoystick.h"
49 #include "../SDL_joystick_c.h" 49 #include "../SDL_joystick_c.h"
50 50
51 struct recElement 51 struct recElement
52 { 52 {
53 IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */ 53 IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */
54 long min; /* reported min value possible */ 54 long min; /* reported min value possible */
55 long max; /* reported max value possible */ 55 long max; /* reported max value possible */
56 #if 0 56 #if 0
57 /* TODO: maybe should handle the following stuff somehow? */ 57 /* TODO: maybe should handle the following stuff somehow? */
58 58
59 long scaledMin; /* reported scaled min value possible */ 59 long scaledMin; /* reported scaled min value possible */
60 long scaledMax; /* reported scaled max value possible */ 60 long scaledMax; /* reported scaled max value possible */
61 long size; /* size in bits of data return from element */ 61 long size; /* size in bits of data return from element */
62 Boolean relative; /* are reports relative to last report (deltas) */ 62 Boolean relative; /* are reports relative to last report (deltas) */
63 Boolean wrapping; /* does element wrap around (one value higher than max is min) */ 63 Boolean wrapping; /* does element wrap around (one value higher than max is min) */
64 Boolean nonLinear; /* are the values reported non-linear relative to element movement */ 64 Boolean nonLinear; /* are the values reported non-linear relative to element movement */
65 Boolean preferredState; /* does element have a preferred state (such as a button) */ 65 Boolean preferredState; /* does element have a preferred state (such as a button) */
66 Boolean nullState; /* does element have null state */ 66 Boolean nullState; /* does element have null state */
67 #endif /* 0 */ 67 #endif /* 0 */
68 68
69 /* runtime variables used for auto-calibration */ 69 /* runtime variables used for auto-calibration */
70 long minReport; /* min returned value */ 70 long minReport; /* min returned value */
71 long maxReport; /* max returned value */ 71 long maxReport; /* max returned value */
72 72
73 struct recElement * pNext; /* next element in list */ 73 struct recElement *pNext; /* next element in list */
74 }; 74 };
75 typedef struct recElement recElement; 75 typedef struct recElement recElement;
76 76
77 struct joystick_hwdata 77 struct joystick_hwdata
78 { 78 {
79 IOHIDDeviceInterface ** interface; /* interface to device, NULL = no interface */ 79 IOHIDDeviceInterface **interface; /* interface to device, NULL = no interface */
80 80
81 char product[256]; /* name of product */ 81 char product[256]; /* name of product */
82 long usage; /* usage page from IOUSBHID Parser.h which defines general usage */ 82 long usage; /* usage page from IOUSBHID Parser.h which defines general usage */
83 long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */ 83 long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */
84 84
85 long axes; /* number of axis (calculated, not reported by device) */ 85 long axes; /* number of axis (calculated, not reported by device) */
86 long buttons; /* number of buttons (calculated, not reported by device) */ 86 long buttons; /* number of buttons (calculated, not reported by device) */
87 long hats; /* number of hat switches (calculated, not reported by device) */ 87 long hats; /* number of hat switches (calculated, not reported by device) */
88 long elements; /* number of total elements (shouldbe total of above) (calculated, not reported by device) */ 88 long elements; /* number of total elements (shouldbe total of above) (calculated, not reported by device) */
89 89
90 recElement* firstAxis; 90 recElement *firstAxis;
91 recElement* firstButton; 91 recElement *firstButton;
92 recElement* firstHat; 92 recElement *firstHat;
93 93
94 int removed; 94 int removed;
95 int uncentered; 95 int uncentered;
96 96
97 struct joystick_hwdata* pNext; /* next device */ 97 struct joystick_hwdata *pNext; /* next device */
98 }; 98 };
99 typedef struct joystick_hwdata recDevice; 99 typedef struct joystick_hwdata recDevice;
100 100
101 101
102 /* Linked list of all available devices */ 102 /* Linked list of all available devices */
103 static recDevice *gpDeviceList = NULL; 103 static recDevice *gpDeviceList = NULL;
104 104
105 105
106 static void HIDReportErrorNum (char * strError, long numError) 106 static void
107 { 107 HIDReportErrorNum(char *strError, long numError)
108 SDL_SetError(strError); 108 {
109 } 109 SDL_SetError(strError);
110 110 }
111 static void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice); 111
112 static void HIDGetCollectionElements(CFMutableDictionaryRef deviceProperties,
113 recDevice * pDevice);
112 114
113 /* returns current value for element, polling element 115 /* returns current value for element, polling element
114 * will return 0 on error conditions which should be accounted for by application 116 * will return 0 on error conditions which should be accounted for by application
115 */ 117 */
116 118
117 static SInt32 HIDGetElementValue (recDevice *pDevice, recElement *pElement) 119 static SInt32
118 { 120 HIDGetElementValue(recDevice * pDevice, recElement * pElement)
119 IOReturn result = kIOReturnSuccess; 121 {
120 IOHIDEventStruct hidEvent; 122 IOReturn result = kIOReturnSuccess;
121 hidEvent.value = 0; 123 IOHIDEventStruct hidEvent;
122 124 hidEvent.value = 0;
123 if (NULL != pDevice && NULL != pElement && NULL != pDevice->interface) 125
124 { 126 if (NULL != pDevice && NULL != pElement && NULL != pDevice->interface) {
125 result = (*(pDevice->interface))->getElementValue(pDevice->interface, pElement->cookie, &hidEvent); 127 result =
126 if (kIOReturnSuccess == result) 128 (*(pDevice->interface))->getElementValue(pDevice->interface,
127 { 129 pElement->cookie,
128 /* record min and max for auto calibration */ 130 &hidEvent);
129 if (hidEvent.value < pElement->minReport) 131 if (kIOReturnSuccess == result) {
130 pElement->minReport = hidEvent.value; 132 /* record min and max for auto calibration */
131 if (hidEvent.value > pElement->maxReport) 133 if (hidEvent.value < pElement->minReport)
132 pElement->maxReport = hidEvent.value; 134 pElement->minReport = hidEvent.value;
133 } 135 if (hidEvent.value > pElement->maxReport)
134 } 136 pElement->maxReport = hidEvent.value;
135 137 }
136 /* auto user scale */ 138 }
137 return hidEvent.value; 139
138 } 140 /* auto user scale */
139 141 return hidEvent.value;
140 static SInt32 HIDScaledCalibratedValue (recDevice *pDevice, recElement *pElement, long min, long max) 142 }
141 { 143
142 float deviceScale = max - min; 144 static SInt32
143 float readScale = pElement->maxReport - pElement->minReport; 145 HIDScaledCalibratedValue(recDevice * pDevice, recElement * pElement,
144 SInt32 value = HIDGetElementValue(pDevice, pElement); 146 long min, long max)
145 if (readScale == 0) 147 {
146 return value; /* no scaling at all */ 148 float deviceScale = max - min;
147 else 149 float readScale = pElement->maxReport - pElement->minReport;
148 return ((value - pElement->minReport) * deviceScale / readScale) + min; 150 SInt32 value = HIDGetElementValue(pDevice, pElement);
149 } 151 if (readScale == 0)
150 152 return value; /* no scaling at all */
151 153 else
152 static void HIDRemovalCallback(void * target, 154 return ((value - pElement->minReport) * deviceScale / readScale) +
153 IOReturn result, 155 min;
154 void * refcon, 156 }
155 void * sender) 157
156 { 158
157 recDevice *device = (recDevice *) refcon; 159 static void
158 device->removed = 1; 160 HIDRemovalCallback(void *target, IOReturn result, void *refcon, void *sender)
159 device->uncentered = 1; 161 {
162 recDevice *device = (recDevice *) refcon;
163 device->removed = 1;
164 device->uncentered = 1;
160 } 165 }
161 166
162 167
163 168
164 /* Create and open an interface to device, required prior to extracting values or building queues. 169 /* Create and open an interface to device, required prior to extracting values or building queues.
165 * Note: appliction now owns the device and must close and release it prior to exiting 170 * Note: appliction now owns the device and must close and release it prior to exiting
166 */ 171 */
167 172
168 static IOReturn HIDCreateOpenDeviceInterface (io_object_t hidDevice, recDevice *pDevice) 173 static IOReturn
169 { 174 HIDCreateOpenDeviceInterface(io_object_t hidDevice, recDevice * pDevice)
170 IOReturn result = kIOReturnSuccess; 175 {
171 HRESULT plugInResult = S_OK; 176 IOReturn result = kIOReturnSuccess;
172 SInt32 score = 0; 177 HRESULT plugInResult = S_OK;
173 IOCFPlugInInterface ** ppPlugInInterface = NULL; 178 SInt32 score = 0;
174 179 IOCFPlugInInterface **ppPlugInInterface = NULL;
175 if (NULL == pDevice->interface) 180
176 { 181 if (NULL == pDevice->interface) {
177 result = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID, 182 result =
178 kIOCFPlugInInterfaceID, &ppPlugInInterface, &score); 183 IOCreatePlugInInterfaceForService(hidDevice,
179 if (kIOReturnSuccess == result) 184 kIOHIDDeviceUserClientTypeID,
180 { 185 kIOCFPlugInInterfaceID,
181 /* Call a method of the intermediate plug-in to create the device interface */ 186 &ppPlugInInterface, &score);
182 plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface, 187 if (kIOReturnSuccess == result) {
183 CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &(pDevice->interface)); 188 /* Call a method of the intermediate plug-in to create the device interface */
184 if (S_OK != plugInResult) 189 plugInResult =
185 HIDReportErrorNum ("CouldnŐt query HID class device interface from plugInInterface", plugInResult); 190 (*ppPlugInInterface)->QueryInterface(ppPlugInInterface,
186 (*ppPlugInInterface)->Release (ppPlugInInterface); 191 CFUUIDGetUUIDBytes
187 } 192 (kIOHIDDeviceInterfaceID),
188 else 193 (void *) &(pDevice->
189 HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result); 194 interface));
190 } 195 if (S_OK != plugInResult)
191 if (NULL != pDevice->interface) 196 HIDReportErrorNum
192 { 197 ("CouldnŐt query HID class device interface from plugInInterface",
193 result = (*(pDevice->interface))->open (pDevice->interface, 0); 198 plugInResult);
194 if (kIOReturnSuccess != result) 199 (*ppPlugInInterface)->Release(ppPlugInInterface);
195 HIDReportErrorNum ("Failed to open pDevice->interface via open.", result); 200 } else
196 else 201 HIDReportErrorNum
197 (*(pDevice->interface))->setRemovalCallback (pDevice->interface, HIDRemovalCallback, pDevice, pDevice); 202 ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.",
198 203 result);
199 } 204 }
200 return result; 205 if (NULL != pDevice->interface) {
206 result = (*(pDevice->interface))->open(pDevice->interface, 0);
207 if (kIOReturnSuccess != result)
208 HIDReportErrorNum
209 ("Failed to open pDevice->interface via open.", result);
210 else
211 (*(pDevice->interface))->setRemovalCallback(pDevice->interface,
212 HIDRemovalCallback,
213 pDevice, pDevice);
214
215 }
216 return result;
201 } 217 }
202 218
203 /* Closes and releases interface to device, should be done prior to exting application 219 /* Closes and releases interface to device, should be done prior to exting application
204 * Note: will have no affect if device or interface do not exist 220 * Note: will have no affect if device or interface do not exist
205 * application will "own" the device if interface is not closed 221 * application will "own" the device if interface is not closed
206 * (device may have to be plug and re-plugged in different location to get it working again without a restart) 222 * (device may have to be plug and re-plugged in different location to get it working again without a restart)
207 */ 223 */
208 224
209 static IOReturn HIDCloseReleaseInterface (recDevice *pDevice) 225 static IOReturn
210 { 226 HIDCloseReleaseInterface(recDevice * pDevice)
211 IOReturn result = kIOReturnSuccess; 227 {
212 228 IOReturn result = kIOReturnSuccess;
213 if ((NULL != pDevice) && (NULL != pDevice->interface)) 229
214 { 230 if ((NULL != pDevice) && (NULL != pDevice->interface)) {
215 /* close the interface */ 231 /* close the interface */
216 result = (*(pDevice->interface))->close (pDevice->interface); 232 result = (*(pDevice->interface))->close(pDevice->interface);
217 if (kIOReturnNotOpen == result) 233 if (kIOReturnNotOpen == result) {
218 { 234 /* do nothing as device was not opened, thus can't be closed */
219 /* do nothing as device was not opened, thus can't be closed */ 235 } else if (kIOReturnSuccess != result)
220 } 236 HIDReportErrorNum("Failed to close IOHIDDeviceInterface.",
221 else if (kIOReturnSuccess != result) 237 result);
222 HIDReportErrorNum ("Failed to close IOHIDDeviceInterface.", result); 238 /* release the interface */
223 /* release the interface */ 239 result = (*(pDevice->interface))->Release(pDevice->interface);
224 result = (*(pDevice->interface))->Release (pDevice->interface); 240 if (kIOReturnSuccess != result)
225 if (kIOReturnSuccess != result) 241 HIDReportErrorNum("Failed to release IOHIDDeviceInterface.",
226 HIDReportErrorNum ("Failed to release IOHIDDeviceInterface.", result); 242 result);
227 pDevice->interface = NULL; 243 pDevice->interface = NULL;
228 } 244 }
229 return result; 245 return result;
230 } 246 }
231 247
232 /* extracts actual specific element information from each element CF dictionary entry */ 248 /* extracts actual specific element information from each element CF dictionary entry */
233 249
234 static void HIDGetElementInfo (CFTypeRef refElement, recElement *pElement) 250 static void
235 { 251 HIDGetElementInfo(CFTypeRef refElement, recElement * pElement)
236 long number; 252 {
237 CFTypeRef refType; 253 long number;
238 254 CFTypeRef refType;
239 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementCookieKey)); 255
240 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 256 refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementCookieKey));
241 pElement->cookie = (IOHIDElementCookie) number; 257 if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
242 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMinKey)); 258 pElement->cookie = (IOHIDElementCookie) number;
243 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 259 refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMinKey));
244 pElement->min = number; 260 if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
245 pElement->maxReport = pElement->min; 261 pElement->min = number;
246 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMaxKey)); 262 pElement->maxReport = pElement->min;
247 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 263 refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMaxKey));
248 pElement->max = number; 264 if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
249 pElement->minReport = pElement->max; 265 pElement->max = number;
266 pElement->minReport = pElement->max;
250 /* 267 /*
251 TODO: maybe should handle the following stuff somehow? 268 TODO: maybe should handle the following stuff somehow?
252 269
253 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey)); 270 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey));
254 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 271 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
273 pElement->preferredState = CFBooleanGetValue (refType); 290 pElement->preferredState = CFBooleanGetValue (refType);
274 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey)); 291 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey));
275 if (refType) 292 if (refType)
276 pElement->nullState = CFBooleanGetValue (refType); 293 pElement->nullState = CFBooleanGetValue (refType);
277 */ 294 */
278 } 295 }
279 296
280 /* examines CF dictionary vlaue in device element hierarchy to determine if it is element of interest or a collection of more elements 297 /* examines CF dictionary vlaue in device element hierarchy to determine if it is element of interest or a collection of more elements
281 * if element of interest allocate storage, add to list and retrieve element specific info 298 * if element of interest allocate storage, add to list and retrieve element specific info
282 * if collection then pass on to deconstruction collection into additional individual elements 299 * if collection then pass on to deconstruction collection into additional individual elements
283 */ 300 */
284 301
285 static void HIDAddElement (CFTypeRef refElement, recDevice* pDevice) 302 static void
286 { 303 HIDAddElement(CFTypeRef refElement, recDevice * pDevice)
287 recElement* element = NULL; 304 {
288 recElement** headElement = NULL; 305 recElement *element = NULL;
289 long elementType, usagePage, usage; 306 recElement **headElement = NULL;
290 CFTypeRef refElementType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementTypeKey)); 307 long elementType, usagePage, usage;
291 CFTypeRef refUsagePage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsagePageKey)); 308 CFTypeRef refElementType =
292 CFTypeRef refUsage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsageKey)); 309 CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementTypeKey));
293 310 CFTypeRef refUsagePage =
294 311 CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsagePageKey));
295 if ((refElementType) && (CFNumberGetValue (refElementType, kCFNumberLongType, &elementType))) 312 CFTypeRef refUsage =
296 { 313 CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsageKey));
297 /* look at types of interest */ 314
298 if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) || 315
299 (elementType == kIOHIDElementTypeInput_Axis)) 316 if ((refElementType)
300 { 317 &&
301 if (refUsagePage && CFNumberGetValue (refUsagePage, kCFNumberLongType, &usagePage) && 318 (CFNumberGetValue(refElementType, kCFNumberLongType, &elementType))) {
302 refUsage && CFNumberGetValue (refUsage, kCFNumberLongType, &usage)) 319 /* look at types of interest */
303 { 320 if ((elementType == kIOHIDElementTypeInput_Misc)
304 switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */ 321 || (elementType == kIOHIDElementTypeInput_Button)
305 { 322 || (elementType == kIOHIDElementTypeInput_Axis)) {
306 case kHIDPage_GenericDesktop: 323 if (refUsagePage
307 { 324 && CFNumberGetValue(refUsagePage, kCFNumberLongType,
308 switch (usage) /* look at usage to determine function */ 325 &usagePage) && refUsage
309 { 326 && CFNumberGetValue(refUsage, kCFNumberLongType, &usage)) {
310 case kHIDUsage_GD_X: 327 switch (usagePage) { /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
311 case kHIDUsage_GD_Y: 328 case kHIDPage_GenericDesktop:
312 case kHIDUsage_GD_Z: 329 {
313 case kHIDUsage_GD_Rx: 330 switch (usage) { /* look at usage to determine function */
314 case kHIDUsage_GD_Ry: 331 case kHIDUsage_GD_X:
315 case kHIDUsage_GD_Rz: 332 case kHIDUsage_GD_Y:
316 case kHIDUsage_GD_Slider: 333 case kHIDUsage_GD_Z:
317 case kHIDUsage_GD_Dial: 334 case kHIDUsage_GD_Rx:
318 case kHIDUsage_GD_Wheel: 335 case kHIDUsage_GD_Ry:
319 element = (recElement *) NewPtrClear (sizeof (recElement)); 336 case kHIDUsage_GD_Rz:
320 if (element) 337 case kHIDUsage_GD_Slider:
321 { 338 case kHIDUsage_GD_Dial:
322 pDevice->axes++; 339 case kHIDUsage_GD_Wheel:
323 headElement = &(pDevice->firstAxis); 340 element = (recElement *)
324 } 341 NewPtrClear(sizeof(recElement));
325 break; 342 if (element) {
326 case kHIDUsage_GD_Hatswitch: 343 pDevice->axes++;
327 element = (recElement *) NewPtrClear (sizeof (recElement)); 344 headElement = &(pDevice->firstAxis);
328 if (element) 345 }
329 { 346 break;
330 pDevice->hats++; 347 case kHIDUsage_GD_Hatswitch:
331 headElement = &(pDevice->firstHat); 348 element = (recElement *)
332 } 349 NewPtrClear(sizeof(recElement));
333 break; 350 if (element) {
334 } 351 pDevice->hats++;
335 } 352 headElement = &(pDevice->firstHat);
336 break; 353 }
337 case kHIDPage_Button: 354 break;
338 element = (recElement *) NewPtrClear (sizeof (recElement)); 355 }
339 if (element) 356 }
340 { 357 break;
341 pDevice->buttons++; 358 case kHIDPage_Button:
342 headElement = &(pDevice->firstButton); 359 element = (recElement *)
343 } 360 NewPtrClear(sizeof(recElement));
344 break; 361 if (element) {
345 default: 362 pDevice->buttons++;
346 break; 363 headElement = &(pDevice->firstButton);
347 } 364 }
348 } 365 break;
349 } 366 default:
350 else if (kIOHIDElementTypeCollection == elementType) 367 break;
351 HIDGetCollectionElements ((CFMutableDictionaryRef) refElement, pDevice); 368 }
352 } 369 }
353 370 } else if (kIOHIDElementTypeCollection == elementType)
354 if (element && headElement) /* add to list */ 371 HIDGetCollectionElements((CFMutableDictionaryRef) refElement,
355 { 372 pDevice);
356 pDevice->elements++; 373 }
357 if (NULL == *headElement) 374
358 *headElement = element; 375 if (element && headElement) { /* add to list */
359 else 376 pDevice->elements++;
360 { 377 if (NULL == *headElement)
361 recElement *elementPrevious, *elementCurrent; 378 *headElement = element;
362 elementCurrent = *headElement; 379 else {
363 while (elementCurrent) 380 recElement *elementPrevious, *elementCurrent;
364 { 381 elementCurrent = *headElement;
365 elementPrevious = elementCurrent; 382 while (elementCurrent) {
366 elementCurrent = elementPrevious->pNext; 383 elementPrevious = elementCurrent;
367 } 384 elementCurrent = elementPrevious->pNext;
368 elementPrevious->pNext = element; 385 }
369 } 386 elementPrevious->pNext = element;
370 element->pNext = NULL; 387 }
371 HIDGetElementInfo (refElement, element); 388 element->pNext = NULL;
372 } 389 HIDGetElementInfo(refElement, element);
390 }
373 } 391 }
374 392
375 /* collects information from each array member in device element list (each array memeber = element) */ 393 /* collects information from each array member in device element list (each array memeber = element) */
376 394
377 static void HIDGetElementsCFArrayHandler (const void * value, void * parameter) 395 static void
378 { 396 HIDGetElementsCFArrayHandler(const void *value, void *parameter)
379 if (CFGetTypeID (value) == CFDictionaryGetTypeID ()) 397 {
380 HIDAddElement ((CFTypeRef) value, (recDevice *) parameter); 398 if (CFGetTypeID(value) == CFDictionaryGetTypeID())
399 HIDAddElement((CFTypeRef) value, (recDevice *) parameter);
381 } 400 }
382 401
383 /* handles retrieval of element information from arrays of elements in device IO registry information */ 402 /* handles retrieval of element information from arrays of elements in device IO registry information */
384 403
385 static void HIDGetElements (CFTypeRef refElementCurrent, recDevice *pDevice) 404 static void
386 { 405 HIDGetElements(CFTypeRef refElementCurrent, recDevice * pDevice)
387 CFTypeID type = CFGetTypeID (refElementCurrent); 406 {
388 if (type == CFArrayGetTypeID()) /* if element is an array */ 407 CFTypeID type = CFGetTypeID(refElementCurrent);
389 { 408 if (type == CFArrayGetTypeID()) { /* if element is an array */
390 CFRange range = {0, CFArrayGetCount (refElementCurrent)}; 409 CFRange range = { 0, CFArrayGetCount(refElementCurrent) };
391 /* CountElementsCFArrayHandler called for each array member */ 410 /* CountElementsCFArrayHandler called for each array member */
392 CFArrayApplyFunction (refElementCurrent, range, HIDGetElementsCFArrayHandler, pDevice); 411 CFArrayApplyFunction(refElementCurrent, range,
393 } 412 HIDGetElementsCFArrayHandler, pDevice);
394 } 413 }
414 }
395 415
396 /* handles extracting element information from element collection CF types 416 /* handles extracting element information from element collection CF types
397 * used from top level element decoding and hierarchy deconstruction to flatten device element list 417 * used from top level element decoding and hierarchy deconstruction to flatten device element list
398 */ 418 */
399 419
400 static void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice) 420 static void
401 { 421 HIDGetCollectionElements(CFMutableDictionaryRef deviceProperties,
402 CFTypeRef refElementTop = CFDictionaryGetValue (deviceProperties, CFSTR(kIOHIDElementKey)); 422 recDevice * pDevice)
403 if (refElementTop) 423 {
404 HIDGetElements (refElementTop, pDevice); 424 CFTypeRef refElementTop =
425 CFDictionaryGetValue(deviceProperties, CFSTR(kIOHIDElementKey));
426 if (refElementTop)
427 HIDGetElements(refElementTop, pDevice);
405 } 428 }
406 429
407 /* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */ 430 /* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */
408 431
409 static void HIDTopLevelElementHandler (const void * value, void * parameter) 432 static void
410 { 433 HIDTopLevelElementHandler(const void *value, void *parameter)
411 CFTypeRef refCF = 0; 434 {
412 if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) 435 CFTypeRef refCF = 0;
413 return; 436 if (CFGetTypeID(value) != CFDictionaryGetTypeID())
414 refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsagePageKey)); 437 return;
415 if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage)) 438 refCF = CFDictionaryGetValue(value, CFSTR(kIOHIDElementUsagePageKey));
416 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage."); 439 if (!CFNumberGetValue
417 refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsageKey)); 440 (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage))
418 if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage)) 441 SDL_SetError("CFNumberGetValue error retrieving pDevice->usagePage.");
419 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage."); 442 refCF = CFDictionaryGetValue(value, CFSTR(kIOHIDElementUsageKey));
443 if (!CFNumberGetValue
444 (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage))
445 SDL_SetError("CFNumberGetValue error retrieving pDevice->usage.");
420 } 446 }
421 447
422 /* extracts device info from CF dictionary records in IO registry */ 448 /* extracts device info from CF dictionary records in IO registry */
423 449
424 static void HIDGetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, recDevice *pDevice) 450 static void
425 { 451 HIDGetDeviceInfo(io_object_t hidDevice, CFMutableDictionaryRef hidProperties,
426 CFMutableDictionaryRef usbProperties = 0; 452 recDevice * pDevice)
427 io_registry_entry_t parent1, parent2; 453 {
428 454 CFMutableDictionaryRef usbProperties = 0;
429 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also 455 io_registry_entry_t parent1, parent2;
430 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties 456
431 */ 457 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
432 if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) && 458 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
433 (KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) && 459 */
434 (KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) 460 if ((KERN_SUCCESS ==
435 { 461 IORegistryEntryGetParentEntry(hidDevice, kIOServicePlane, &parent1))
436 if (usbProperties) 462 && (KERN_SUCCESS ==
437 { 463 IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2))
438 CFTypeRef refCF = 0; 464 && (KERN_SUCCESS ==
439 /* get device info 465 IORegistryEntryCreateCFProperties(parent2, &usbProperties,
440 * try hid dictionary first, if fail then go to usb dictionary 466 kCFAllocatorDefault,
441 */ 467 kNilOptions))) {
442 468 if (usbProperties) {
443 469 CFTypeRef refCF = 0;
444 /* get product name */ 470 /* get device info
445 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey)); 471 * try hid dictionary first, if fail then go to usb dictionary
446 if (!refCF) 472 */
447 refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name")); 473
448 if (refCF) 474
449 { 475 /* get product name */
450 if (!CFStringGetCString (refCF, pDevice->product, 256, CFStringGetSystemEncoding ())) 476 refCF =
451 SDL_SetError ("CFStringGetCString error retrieving pDevice->product."); 477 CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey));
452 } 478 if (!refCF)
453 479 refCF =
454 /* get usage page and usage */ 480 CFDictionaryGetValue(usbProperties,
455 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); 481 CFSTR("USB Product Name"));
456 if (refCF) 482 if (refCF) {
457 { 483 if (!CFStringGetCString
458 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage)) 484 (refCF, pDevice->product, 256,
459 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage."); 485 CFStringGetSystemEncoding()))
460 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); 486 SDL_SetError
461 if (refCF) 487 ("CFStringGetCString error retrieving pDevice->product.");
462 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage)) 488 }
463 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage."); 489
464 } 490 /* get usage page and usage */
465 491 refCF =
466 if (NULL == refCF) /* get top level element HID usage page or usage */ 492 CFDictionaryGetValue(hidProperties,
467 { 493 CFSTR(kIOHIDPrimaryUsagePageKey));
468 /* use top level element instead */ 494 if (refCF) {
469 CFTypeRef refCFTopElement = 0; 495 if (!CFNumberGetValue
470 refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey)); 496 (refCF, kCFNumberLongType, &pDevice->usagePage))
471 { 497 SDL_SetError
472 /* refCFTopElement points to an array of element dictionaries */ 498 ("CFNumberGetValue error retrieving pDevice->usagePage.");
473 CFRange range = {0, CFArrayGetCount (refCFTopElement)}; 499 refCF =
474 CFArrayApplyFunction (refCFTopElement, range, HIDTopLevelElementHandler, pDevice); 500 CFDictionaryGetValue(hidProperties,
475 } 501 CFSTR(kIOHIDPrimaryUsageKey));
476 } 502 if (refCF)
477 503 if (!CFNumberGetValue
478 CFRelease (usbProperties); 504 (refCF, kCFNumberLongType, &pDevice->usage))
479 } 505 SDL_SetError
480 else 506 ("CFNumberGetValue error retrieving pDevice->usage.");
481 SDL_SetError ("IORegistryEntryCreateCFProperties failed to create usbProperties."); 507 }
482 508
483 if (kIOReturnSuccess != IOObjectRelease (parent2)) 509 if (NULL == refCF) { /* get top level element HID usage page or usage */
484 SDL_SetError ("IOObjectRelease error with parent2."); 510 /* use top level element instead */
485 if (kIOReturnSuccess != IOObjectRelease (parent1)) 511 CFTypeRef refCFTopElement = 0;
486 SDL_SetError ("IOObjectRelease error with parent1."); 512 refCFTopElement =
487 } 513 CFDictionaryGetValue(hidProperties,
488 } 514 CFSTR(kIOHIDElementKey));
489 515 {
490 516 /* refCFTopElement points to an array of element dictionaries */
491 static recDevice *HIDBuildDevice (io_object_t hidDevice) 517 CFRange range = { 0, CFArrayGetCount(refCFTopElement) };
492 { 518 CFArrayApplyFunction(refCFTopElement, range,
493 recDevice *pDevice = (recDevice *) NewPtrClear (sizeof (recDevice)); 519 HIDTopLevelElementHandler, pDevice);
494 if (pDevice) 520 }
495 { 521 }
496 /* get dictionary for HID properties */ 522
497 CFMutableDictionaryRef hidProperties = 0; 523 CFRelease(usbProperties);
498 kern_return_t result = IORegistryEntryCreateCFProperties (hidDevice, &hidProperties, kCFAllocatorDefault, kNilOptions); 524 } else
499 if ((result == KERN_SUCCESS) && hidProperties) 525 SDL_SetError
500 { 526 ("IORegistryEntryCreateCFProperties failed to create usbProperties.");
501 /* create device interface */ 527
502 result = HIDCreateOpenDeviceInterface (hidDevice, pDevice); 528 if (kIOReturnSuccess != IOObjectRelease(parent2))
503 if (kIOReturnSuccess == result) 529 SDL_SetError("IOObjectRelease error with parent2.");
504 { 530 if (kIOReturnSuccess != IOObjectRelease(parent1))
505 HIDGetDeviceInfo (hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */ 531 SDL_SetError("IOObjectRelease error with parent1.");
506 HIDGetCollectionElements (hidProperties, pDevice); 532 }
507 } 533 }
508 else 534
509 { 535
510 DisposePtr((Ptr)pDevice); 536 static recDevice *
511 pDevice = NULL; 537 HIDBuildDevice(io_object_t hidDevice)
512 } 538 {
513 CFRelease (hidProperties); 539 recDevice *pDevice = (recDevice *) NewPtrClear(sizeof(recDevice));
514 } 540 if (pDevice) {
515 else 541 /* get dictionary for HID properties */
516 { 542 CFMutableDictionaryRef hidProperties = 0;
517 DisposePtr((Ptr)pDevice); 543 kern_return_t result =
518 pDevice = NULL; 544 IORegistryEntryCreateCFProperties(hidDevice, &hidProperties,
519 } 545 kCFAllocatorDefault,
520 } 546 kNilOptions);
521 return pDevice; 547 if ((result == KERN_SUCCESS) && hidProperties) {
548 /* create device interface */
549 result = HIDCreateOpenDeviceInterface(hidDevice, pDevice);
550 if (kIOReturnSuccess == result) {
551 HIDGetDeviceInfo(hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */
552 HIDGetCollectionElements(hidProperties, pDevice);
553 } else {
554 DisposePtr((Ptr) pDevice);
555 pDevice = NULL;
556 }
557 CFRelease(hidProperties);
558 } else {
559 DisposePtr((Ptr) pDevice);
560 pDevice = NULL;
561 }
562 }
563 return pDevice;
522 } 564 }
523 565
524 /* disposes of the element list associated with a device and the memory associated with the list 566 /* disposes of the element list associated with a device and the memory associated with the list
525 */ 567 */
526 568
527 static void HIDDisposeElementList (recElement **elementList) 569 static void
528 { 570 HIDDisposeElementList(recElement ** elementList)
529 recElement *pElement = *elementList; 571 {
530 while (pElement) 572 recElement *pElement = *elementList;
531 { 573 while (pElement) {
532 recElement *pElementNext = pElement->pNext; 574 recElement *pElementNext = pElement->pNext;
533 DisposePtr ((Ptr) pElement); 575 DisposePtr((Ptr) pElement);
534 pElement = pElementNext; 576 pElement = pElementNext;
535 } 577 }
536 *elementList = NULL; 578 *elementList = NULL;
537 } 579 }
538 580
539 /* disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL 581 /* disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL
540 * all your device no longer belong to us... (i.e., you do not 'own' the device anymore) 582 * all your device no longer belong to us... (i.e., you do not 'own' the device anymore)
541 */ 583 */
542 584
543 static recDevice *HIDDisposeDevice (recDevice **ppDevice) 585 static recDevice *
544 { 586 HIDDisposeDevice(recDevice ** ppDevice)
545 kern_return_t result = KERN_SUCCESS; 587 {
546 recDevice *pDeviceNext = NULL; 588 kern_return_t result = KERN_SUCCESS;
547 if (*ppDevice) 589 recDevice *pDeviceNext = NULL;
548 { 590 if (*ppDevice) {
549 /* save next device prior to disposing of this device */ 591 /* save next device prior to disposing of this device */
550 pDeviceNext = (*ppDevice)->pNext; 592 pDeviceNext = (*ppDevice)->pNext;
551 593
552 /* free element lists */ 594 /* free element lists */
553 HIDDisposeElementList (&(*ppDevice)->firstAxis); 595 HIDDisposeElementList(&(*ppDevice)->firstAxis);
554 HIDDisposeElementList (&(*ppDevice)->firstButton); 596 HIDDisposeElementList(&(*ppDevice)->firstButton);
555 HIDDisposeElementList (&(*ppDevice)->firstHat); 597 HIDDisposeElementList(&(*ppDevice)->firstHat);
556 598
557 result = HIDCloseReleaseInterface (*ppDevice); /* function sanity checks interface value (now application does not own device) */ 599 result = HIDCloseReleaseInterface(*ppDevice); /* function sanity checks interface value (now application does not own device) */
558 if (kIOReturnSuccess != result) 600 if (kIOReturnSuccess != result)
559 HIDReportErrorNum ("HIDCloseReleaseInterface failed when trying to dipose device.", result); 601 HIDReportErrorNum
560 DisposePtr ((Ptr)*ppDevice); 602 ("HIDCloseReleaseInterface failed when trying to dipose device.",
561 *ppDevice = NULL; 603 result);
562 } 604 DisposePtr((Ptr) * ppDevice);
563 return pDeviceNext; 605 *ppDevice = NULL;
606 }
607 return pDeviceNext;
564 } 608 }
565 609
566 610
567 /* Function to scan the system for joysticks. 611 /* Function to scan the system for joysticks.
568 * Joystick 0 should be the system default joystick. 612 * Joystick 0 should be the system default joystick.
569 * This function should return the number of available joysticks, or -1 613 * This function should return the number of available joysticks, or -1
570 * on an unrecoverable fatal error. 614 * on an unrecoverable fatal error.
571 */ 615 */
572 int SDL_SYS_JoystickInit(void) 616 int
573 { 617 SDL_SYS_JoystickInit(void)
574 IOReturn result = kIOReturnSuccess; 618 {
575 mach_port_t masterPort = 0; 619 IOReturn result = kIOReturnSuccess;
576 io_iterator_t hidObjectIterator = 0; 620 mach_port_t masterPort = 0;
577 CFMutableDictionaryRef hidMatchDictionary = NULL; 621 io_iterator_t hidObjectIterator = 0;
578 recDevice *device, *lastDevice; 622 CFMutableDictionaryRef hidMatchDictionary = NULL;
579 io_object_t ioHIDDeviceObject = 0; 623 recDevice *device, *lastDevice;
580 624 io_object_t ioHIDDeviceObject = 0;
581 SDL_numjoysticks = 0; 625
582 626 SDL_numjoysticks = 0;
583 if (gpDeviceList) 627
584 { 628 if (gpDeviceList) {
585 SDL_SetError("Joystick: Device list already inited."); 629 SDL_SetError("Joystick: Device list already inited.");
586 return -1; 630 return -1;
587 } 631 }
588 632
589 result = IOMasterPort (bootstrap_port, &masterPort); 633 result = IOMasterPort(bootstrap_port, &masterPort);
590 if (kIOReturnSuccess != result) 634 if (kIOReturnSuccess != result) {
591 { 635 SDL_SetError("Joystick: IOMasterPort error with bootstrap_port.");
592 SDL_SetError("Joystick: IOMasterPort error with bootstrap_port."); 636 return -1;
593 return -1; 637 }
594 } 638
595 639 /* Set up a matching dictionary to search I/O Registry by class name for all HID class devices. */
596 /* Set up a matching dictionary to search I/O Registry by class name for all HID class devices. */ 640 hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
597 hidMatchDictionary = IOServiceMatching (kIOHIDDeviceKey); 641 if (hidMatchDictionary) {
598 if (hidMatchDictionary) 642 /* Add key for device type (joystick, in this case) to refine the matching dictionary. */
599 { 643
600 /* Add key for device type (joystick, in this case) to refine the matching dictionary. */ 644 /* NOTE: we now perform this filtering later
601 645 UInt32 usagePage = kHIDPage_GenericDesktop;
602 /* NOTE: we now perform this filtering later 646 UInt32 usage = kHIDUsage_GD_Joystick;
603 UInt32 usagePage = kHIDPage_GenericDesktop; 647 CFNumberRef refUsage = NULL, refUsagePage = NULL;
604 UInt32 usage = kHIDUsage_GD_Joystick; 648
605 CFNumberRef refUsage = NULL, refUsagePage = NULL; 649 refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage);
606 650 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage);
607 refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage); 651 refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage);
608 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage); 652 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage);
609 refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage); 653 */
610 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage); 654 } else {
611 */ 655 SDL_SetError
612 } 656 ("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching.");
613 else 657 return -1;
614 { 658 }
615 SDL_SetError("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching."); 659
616 return -1; 660 /*/ Now search I/O Registry for matching devices. */
617 } 661 result =
618 662 IOServiceGetMatchingServices(masterPort, hidMatchDictionary,
619 /*/ Now search I/O Registry for matching devices. */ 663 &hidObjectIterator);
620 result = IOServiceGetMatchingServices (masterPort, hidMatchDictionary, &hidObjectIterator); 664 /* Check for errors */
621 /* Check for errors */ 665 if (kIOReturnSuccess != result) {
622 if (kIOReturnSuccess != result) 666 SDL_SetError("Joystick: Couldn't create a HID object iterator.");
623 { 667 return -1;
624 SDL_SetError("Joystick: Couldn't create a HID object iterator."); 668 }
625 return -1; 669 if (!hidObjectIterator) { /* there are no joysticks */
626 } 670 gpDeviceList = NULL;
627 if (!hidObjectIterator) /* there are no joysticks */ 671 SDL_numjoysticks = 0;
628 { 672 return 0;
629 gpDeviceList = NULL; 673 }
630 SDL_numjoysticks = 0; 674 /* IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. */
631 return 0; 675
632 } 676 /* build flat linked list of devices from device iterator */
633 /* IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. */ 677
634 678 gpDeviceList = lastDevice = NULL;
635 /* build flat linked list of devices from device iterator */ 679
636 680 while ((ioHIDDeviceObject = IOIteratorNext(hidObjectIterator))) {
637 gpDeviceList = lastDevice = NULL; 681 /* build a device record */
638 682 device = HIDBuildDevice(ioHIDDeviceObject);
639 while ((ioHIDDeviceObject = IOIteratorNext (hidObjectIterator))) 683 if (!device)
640 { 684 continue;
641 /* build a device record */ 685
642 device = HIDBuildDevice (ioHIDDeviceObject); 686 /* dump device object, it is no longer needed */
643 if (!device) 687 result = IOObjectRelease(ioHIDDeviceObject);
644 continue;
645
646 /* dump device object, it is no longer needed */
647 result = IOObjectRelease (ioHIDDeviceObject);
648 /* if (KERN_SUCCESS != result) 688 /* if (KERN_SUCCESS != result)
649 HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result); 689 HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result);
650 */ 690 */
651 691
652 /* Filter device list to non-keyboard/mouse stuff */ 692 /* Filter device list to non-keyboard/mouse stuff */
653 if ( (device->usagePage != kHIDPage_GenericDesktop) || 693 if ((device->usagePage != kHIDPage_GenericDesktop) ||
654 ((device->usage != kHIDUsage_GD_Joystick && 694 ((device->usage != kHIDUsage_GD_Joystick &&
655 device->usage != kHIDUsage_GD_GamePad)) ) { 695 device->usage != kHIDUsage_GD_GamePad))) {
656 696
657 /* release memory for the device */ 697 /* release memory for the device */
658 HIDDisposeDevice (&device); 698 HIDDisposeDevice(&device);
659 DisposePtr((Ptr)device); 699 DisposePtr((Ptr) device);
660 continue; 700 continue;
661 } 701 }
662 702
663 /* Add device to the end of the list */ 703 /* Add device to the end of the list */
664 if (lastDevice) 704 if (lastDevice)
665 lastDevice->pNext = device; 705 lastDevice->pNext = device;
666 else 706 else
667 gpDeviceList = device; 707 gpDeviceList = device;
668 lastDevice = device; 708 lastDevice = device;
669 } 709 }
670 result = IOObjectRelease (hidObjectIterator); /* release the iterator */ 710 result = IOObjectRelease(hidObjectIterator); /* release the iterator */
671 711
672 /* Count the total number of devices we found */ 712 /* Count the total number of devices we found */
673 device = gpDeviceList; 713 device = gpDeviceList;
674 while (device) 714 while (device) {
675 { 715 SDL_numjoysticks++;
676 SDL_numjoysticks++; 716 device = device->pNext;
677 device = device->pNext; 717 }
678 } 718
679 719 return SDL_numjoysticks;
680 return SDL_numjoysticks;
681 } 720 }
682 721
683 /* Function to get the device-dependent name of a joystick */ 722 /* Function to get the device-dependent name of a joystick */
684 const char *SDL_SYS_JoystickName(int index) 723 const char *
685 { 724 SDL_SYS_JoystickName(int index)
686 recDevice *device = gpDeviceList; 725 {
687 726 recDevice *device = gpDeviceList;
688 for (; index > 0; index--) 727
689 device = device->pNext; 728 for (; index > 0; index--)
690 729 device = device->pNext;
691 return device->product; 730
731 return device->product;
692 } 732 }
693 733
694 /* Function to open a joystick for use. 734 /* Function to open a joystick for use.
695 * The joystick to open is specified by the index field of the joystick. 735 * The joystick to open is specified by the index field of the joystick.
696 * This should fill the nbuttons and naxes fields of the joystick structure. 736 * This should fill the nbuttons and naxes fields of the joystick structure.
697 * It returns 0, or -1 if there is an error. 737 * It returns 0, or -1 if there is an error.
698 */ 738 */
699 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) 739 int
700 { 740 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
701 recDevice *device = gpDeviceList; 741 {
702 int index; 742 recDevice *device = gpDeviceList;
703 743 int index;
704 for (index = joystick->index; index > 0; index--) 744
705 device = device->pNext; 745 for (index = joystick->index; index > 0; index--)
706 746 device = device->pNext;
707 joystick->hwdata = device; 747
708 joystick->name = device->product; 748 joystick->hwdata = device;
709 749 joystick->name = device->product;
710 joystick->naxes = device->axes; 750
711 joystick->nhats = device->hats; 751 joystick->naxes = device->axes;
712 joystick->nballs = 0; 752 joystick->nhats = device->hats;
713 joystick->nbuttons = device->buttons; 753 joystick->nballs = 0;
714 754 joystick->nbuttons = device->buttons;
715 return 0; 755
756 return 0;
716 } 757 }
717 758
718 /* Function to update the state of a joystick - called as a device poll. 759 /* Function to update the state of a joystick - called as a device poll.
719 * This function shouldn't update the joystick structure directly, 760 * This function shouldn't update the joystick structure directly,
720 * but instead should call SDL_PrivateJoystick*() to deliver events 761 * but instead should call SDL_PrivateJoystick*() to deliver events
721 * and update joystick device state. 762 * and update joystick device state.
722 */ 763 */
723 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) 764 void
724 { 765 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
725 recDevice *device = joystick->hwdata; 766 {
726 recElement *element; 767 recDevice *device = joystick->hwdata;
727 SInt32 value; 768 recElement *element;
728 int i; 769 SInt32 value;
729 770 int i;
730 if (device->removed) /* device was unplugged; ignore it. */ 771
731 { 772 if (device->removed) { /* device was unplugged; ignore it. */
732 if (device->uncentered) 773 if (device->uncentered) {
733 { 774 device->uncentered = 0;
734 device->uncentered = 0; 775
735 776 /* Tell the app that everything is centered/unpressed... */
736 /* Tell the app that everything is centered/unpressed... */ 777 for (i = 0; i < device->axes; i++)
737 for (i = 0; i < device->axes; i++) 778 SDL_PrivateJoystickAxis(joystick, i, 0);
738 SDL_PrivateJoystickAxis(joystick, i, 0); 779
739 780 for (i = 0; i < device->buttons; i++)
740 for (i = 0; i < device->buttons; i++) 781 SDL_PrivateJoystickButton(joystick, i, 0);
741 SDL_PrivateJoystickButton(joystick, i, 0); 782
742 783 for (i = 0; i < device->hats; i++)
743 for (i = 0; i < device->hats; i++) 784 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
744 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); 785 }
745 } 786
746 787 return;
747 return; 788 }
748 } 789
749 790 element = device->firstAxis;
750 element = device->firstAxis; 791 i = 0;
751 i = 0; 792 while (element) {
752 while (element) 793 value = HIDScaledCalibratedValue(device, element, -32768, 32767);
753 { 794 if (value != joystick->axes[i])
754 value = HIDScaledCalibratedValue(device, element, -32768, 32767); 795 SDL_PrivateJoystickAxis(joystick, i, value);
755 if ( value != joystick->axes[i] ) 796 element = element->pNext;
756 SDL_PrivateJoystickAxis(joystick, i, value); 797 ++i;
757 element = element->pNext; 798 }
758 ++i; 799
759 } 800 element = device->firstButton;
760 801 i = 0;
761 element = device->firstButton; 802 while (element) {
762 i = 0; 803 value = HIDGetElementValue(device, element);
763 while (element) 804 if (value > 1) /* handle pressure-sensitive buttons */
764 {
765 value = HIDGetElementValue(device, element);
766 if (value > 1) /* handle pressure-sensitive buttons */
767 value = 1; 805 value = 1;
768 if ( value != joystick->buttons[i] ) 806 if (value != joystick->buttons[i])
769 SDL_PrivateJoystickButton(joystick, i, value); 807 SDL_PrivateJoystickButton(joystick, i, value);
770 element = element->pNext; 808 element = element->pNext;
771 ++i; 809 ++i;
772 } 810 }
773 811
774 element = device->firstHat; 812 element = device->firstHat;
775 i = 0; 813 i = 0;
776 while (element) 814 while (element) {
777 { 815 Uint8 pos = 0;
778 Uint8 pos = 0; 816
779 817 value = HIDGetElementValue(device, element);
780 value = HIDGetElementValue(device, element); 818 if (element->max == 3) /* 4 position hatswitch - scale up value */
781 if (element->max == 3) /* 4 position hatswitch - scale up value */ 819 value *= 2;
782 value *= 2; 820 else if (element->max != 7) /* Neither a 4 nor 8 positions - fall back to default position (centered) */
783 else if (element->max != 7) /* Neither a 4 nor 8 positions - fall back to default position (centered) */ 821 value = -1;
784 value = -1; 822 switch (value) {
785 switch(value) 823 case 0:
786 { 824 pos = SDL_HAT_UP;
787 case 0: 825 break;
788 pos = SDL_HAT_UP; 826 case 1:
789 break; 827 pos = SDL_HAT_RIGHTUP;
790 case 1: 828 break;
791 pos = SDL_HAT_RIGHTUP; 829 case 2:
792 break; 830 pos = SDL_HAT_RIGHT;
793 case 2: 831 break;
794 pos = SDL_HAT_RIGHT; 832 case 3:
795 break; 833 pos = SDL_HAT_RIGHTDOWN;
796 case 3: 834 break;
797 pos = SDL_HAT_RIGHTDOWN; 835 case 4:
798 break; 836 pos = SDL_HAT_DOWN;
799 case 4: 837 break;
800 pos = SDL_HAT_DOWN; 838 case 5:
801 break; 839 pos = SDL_HAT_LEFTDOWN;
802 case 5: 840 break;
803 pos = SDL_HAT_LEFTDOWN; 841 case 6:
804 break; 842 pos = SDL_HAT_LEFT;
805 case 6: 843 break;
806 pos = SDL_HAT_LEFT; 844 case 7:
807 break; 845 pos = SDL_HAT_LEFTUP;
808 case 7: 846 break;
809 pos = SDL_HAT_LEFTUP; 847 default:
810 break; 848 /* Every other value is mapped to center. We do that because some
811 default: 849 * joysticks use 8 and some 15 for this value, and apparently
812 /* Every other value is mapped to center. We do that because some 850 * there are even more variants out there - so we try to be generous.
813 * joysticks use 8 and some 15 for this value, and apparently 851 */
814 * there are even more variants out there - so we try to be generous. 852 pos = SDL_HAT_CENTERED;
815 */ 853 break;
816 pos = SDL_HAT_CENTERED; 854 }
817 break; 855 if (pos != joystick->hats[i])
818 } 856 SDL_PrivateJoystickHat(joystick, i, pos);
819 if ( pos != joystick->hats[i] ) 857 element = element->pNext;
820 SDL_PrivateJoystickHat(joystick, i, pos); 858 ++i;
821 element = element->pNext; 859 }
822 ++i; 860
823 } 861 return;
824
825 return;
826 } 862 }
827 863
828 /* Function to close a joystick after use */ 864 /* Function to close a joystick after use */
829 void SDL_SYS_JoystickClose(SDL_Joystick *joystick) 865 void
830 { 866 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
831 /* Should we do anything here? */ 867 {
832 return; 868 /* Should we do anything here? */
869 return;
833 } 870 }
834 871
835 /* Function to perform any system-specific joystick related cleanup */ 872 /* Function to perform any system-specific joystick related cleanup */
836 void SDL_SYS_JoystickQuit(void) 873 void
837 { 874 SDL_SYS_JoystickQuit(void)
838 while (NULL != gpDeviceList) 875 {
839 gpDeviceList = HIDDisposeDevice (&gpDeviceList); 876 while (NULL != gpDeviceList)
877 gpDeviceList = HIDDisposeDevice(&gpDeviceList);
840 } 878 }
841 879
842 #endif /* SDL_JOYSTICK_IOKIT */ 880 #endif /* SDL_JOYSTICK_IOKIT */
881 /* vi: set ts=4 sw=4 expandtab: */