comparison src/joystick/darwin/SDL_sysjoystick.c @ 1662:782fd950bd46 SDL-1.3

Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API. WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid. The code is now run through a consistent indent format: indent -i4 -nut -nsc -br -ce The headers are being converted to automatically generate doxygen documentation.
author Sam Lantinga <slouken@libsdl.org>
date Sun, 28 May 2006 13:04:16 +0000
parents 92947e3a18db
children 4da1ee79c9af
comparison
equal deleted inserted replaced
1661:281d3f4870e5 1662:782fd950bd46
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 =
241 pElement->cookie = (IOHIDElementCookie) number; 257 CFDictionaryGetValue (refElement, CFSTR (kIOHIDElementCookieKey));
242 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMinKey)); 258 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
243 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 259 pElement->cookie = (IOHIDElementCookie) number;
244 pElement->min = number; 260 refType = CFDictionaryGetValue (refElement, CFSTR (kIOHIDElementMinKey));
245 pElement->maxReport = pElement->min; 261 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
246 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMaxKey)); 262 pElement->min = number;
247 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 263 pElement->maxReport = pElement->min;
248 pElement->max = number; 264 refType = CFDictionaryGetValue (refElement, CFSTR (kIOHIDElementMaxKey));
249 pElement->minReport = pElement->max; 265 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
266 pElement->max = number;
267 pElement->minReport = pElement->max;
250 /* 268 /*
251 TODO: maybe should handle the following stuff somehow? 269 TODO: maybe should handle the following stuff somehow?
252 270
253 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey)); 271 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey));
254 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number)) 272 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
273 pElement->preferredState = CFBooleanGetValue (refType); 291 pElement->preferredState = CFBooleanGetValue (refType);
274 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey)); 292 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey));
275 if (refType) 293 if (refType)
276 pElement->nullState = CFBooleanGetValue (refType); 294 pElement->nullState = CFBooleanGetValue (refType);
277 */ 295 */
278 } 296 }
279 297
280 /* examines CF dictionary vlaue in device element hierarchy to determine if it is element of interest or a collection of more elements 298 /* 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 299 * 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 300 * if collection then pass on to deconstruction collection into additional individual elements
283 */ 301 */
284 302
285 static void HIDAddElement (CFTypeRef refElement, recDevice* pDevice) 303 static void
286 { 304 HIDAddElement (CFTypeRef refElement, recDevice * pDevice)
287 recElement* element = NULL; 305 {
288 recElement** headElement = NULL; 306 recElement *element = NULL;
289 long elementType, usagePage, usage; 307 recElement **headElement = NULL;
290 CFTypeRef refElementType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementTypeKey)); 308 long elementType, usagePage, usage;
291 CFTypeRef refUsagePage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsagePageKey)); 309 CFTypeRef refElementType =
292 CFTypeRef refUsage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsageKey)); 310 CFDictionaryGetValue (refElement, CFSTR (kIOHIDElementTypeKey));
293 311 CFTypeRef refUsagePage =
294 312 CFDictionaryGetValue (refElement, CFSTR (kIOHIDElementUsagePageKey));
295 if ((refElementType) && (CFNumberGetValue (refElementType, kCFNumberLongType, &elementType))) 313 CFTypeRef refUsage =
296 { 314 CFDictionaryGetValue (refElement, CFSTR (kIOHIDElementUsageKey));
297 /* look at types of interest */ 315
298 if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) || 316
299 (elementType == kIOHIDElementTypeInput_Axis)) 317 if ((refElementType)
300 { 318 &&
301 if (refUsagePage && CFNumberGetValue (refUsagePage, kCFNumberLongType, &usagePage) && 319 (CFNumberGetValue (refElementType, kCFNumberLongType, &elementType)))
302 refUsage && CFNumberGetValue (refUsage, kCFNumberLongType, &usage)) 320 {
303 { 321 /* look at types of interest */
304 switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */ 322 if ((elementType == kIOHIDElementTypeInput_Misc)
305 { 323 || (elementType == kIOHIDElementTypeInput_Button)
306 case kHIDPage_GenericDesktop: 324 || (elementType == kIOHIDElementTypeInput_Axis)) {
307 { 325 if (refUsagePage
308 switch (usage) /* look at usage to determine function */ 326 && CFNumberGetValue (refUsagePage, kCFNumberLongType,
309 { 327 &usagePage) && refUsage
310 case kHIDUsage_GD_X: 328 && CFNumberGetValue (refUsage, kCFNumberLongType, &usage)) {
311 case kHIDUsage_GD_Y: 329 switch (usagePage) { /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
312 case kHIDUsage_GD_Z: 330 case kHIDPage_GenericDesktop:
313 case kHIDUsage_GD_Rx: 331 {
314 case kHIDUsage_GD_Ry: 332 switch (usage) { /* look at usage to determine function */
315 case kHIDUsage_GD_Rz: 333 case kHIDUsage_GD_X:
316 case kHIDUsage_GD_Slider: 334 case kHIDUsage_GD_Y:
317 case kHIDUsage_GD_Dial: 335 case kHIDUsage_GD_Z:
318 case kHIDUsage_GD_Wheel: 336 case kHIDUsage_GD_Rx:
319 element = (recElement *) NewPtrClear (sizeof (recElement)); 337 case kHIDUsage_GD_Ry:
320 if (element) 338 case kHIDUsage_GD_Rz:
321 { 339 case kHIDUsage_GD_Slider:
322 pDevice->axes++; 340 case kHIDUsage_GD_Dial:
323 headElement = &(pDevice->firstAxis); 341 case kHIDUsage_GD_Wheel:
324 } 342 element = (recElement *)
325 break; 343 NewPtrClear (sizeof (recElement));
326 case kHIDUsage_GD_Hatswitch: 344 if (element) {
327 element = (recElement *) NewPtrClear (sizeof (recElement)); 345 pDevice->axes++;
328 if (element) 346 headElement = &(pDevice->firstAxis);
329 { 347 }
330 pDevice->hats++; 348 break;
331 headElement = &(pDevice->firstHat); 349 case kHIDUsage_GD_Hatswitch:
332 } 350 element = (recElement *)
333 break; 351 NewPtrClear (sizeof (recElement));
334 } 352 if (element) {
335 } 353 pDevice->hats++;
336 break; 354 headElement = &(pDevice->firstHat);
337 case kHIDPage_Button: 355 }
338 element = (recElement *) NewPtrClear (sizeof (recElement)); 356 break;
339 if (element) 357 }
340 { 358 }
341 pDevice->buttons++; 359 break;
342 headElement = &(pDevice->firstButton); 360 case kHIDPage_Button:
343 } 361 element = (recElement *)
344 break; 362 NewPtrClear (sizeof (recElement));
345 default: 363 if (element) {
346 break; 364 pDevice->buttons++;
347 } 365 headElement = &(pDevice->firstButton);
348 } 366 }
349 } 367 break;
350 else if (kIOHIDElementTypeCollection == elementType) 368 default:
351 HIDGetCollectionElements ((CFMutableDictionaryRef) refElement, pDevice); 369 break;
352 } 370 }
353 371 }
354 if (element && headElement) /* add to list */ 372 } else if (kIOHIDElementTypeCollection == elementType)
355 { 373 HIDGetCollectionElements ((CFMutableDictionaryRef) refElement,
356 pDevice->elements++; 374 pDevice);
357 if (NULL == *headElement) 375 }
358 *headElement = element; 376
359 else 377 if (element && headElement) { /* add to list */
360 { 378 pDevice->elements++;
361 recElement *elementPrevious, *elementCurrent; 379 if (NULL == *headElement)
362 elementCurrent = *headElement; 380 *headElement = element;
363 while (elementCurrent) 381 else {
364 { 382 recElement *elementPrevious, *elementCurrent;
365 elementPrevious = elementCurrent; 383 elementCurrent = *headElement;
366 elementCurrent = elementPrevious->pNext; 384 while (elementCurrent) {
367 } 385 elementPrevious = elementCurrent;
368 elementPrevious->pNext = element; 386 elementCurrent = elementPrevious->pNext;
369 } 387 }
370 element->pNext = NULL; 388 elementPrevious->pNext = element;
371 HIDGetElementInfo (refElement, element); 389 }
372 } 390 element->pNext = NULL;
391 HIDGetElementInfo (refElement, element);
392 }
373 } 393 }
374 394
375 /* collects information from each array member in device element list (each array memeber = element) */ 395 /* collects information from each array member in device element list (each array memeber = element) */
376 396
377 static void HIDGetElementsCFArrayHandler (const void * value, void * parameter) 397 static void
378 { 398 HIDGetElementsCFArrayHandler (const void *value, void *parameter)
379 if (CFGetTypeID (value) == CFDictionaryGetTypeID ()) 399 {
380 HIDAddElement ((CFTypeRef) value, (recDevice *) parameter); 400 if (CFGetTypeID (value) == CFDictionaryGetTypeID ())
401 HIDAddElement ((CFTypeRef) value, (recDevice *) parameter);
381 } 402 }
382 403
383 /* handles retrieval of element information from arrays of elements in device IO registry information */ 404 /* handles retrieval of element information from arrays of elements in device IO registry information */
384 405
385 static void HIDGetElements (CFTypeRef refElementCurrent, recDevice *pDevice) 406 static void
386 { 407 HIDGetElements (CFTypeRef refElementCurrent, recDevice * pDevice)
387 CFTypeID type = CFGetTypeID (refElementCurrent); 408 {
388 if (type == CFArrayGetTypeID()) /* if element is an array */ 409 CFTypeID type = CFGetTypeID (refElementCurrent);
389 { 410 if (type == CFArrayGetTypeID ()) { /* if element is an array */
390 CFRange range = {0, CFArrayGetCount (refElementCurrent)}; 411 CFRange range = { 0, CFArrayGetCount (refElementCurrent) };
391 /* CountElementsCFArrayHandler called for each array member */ 412 /* CountElementsCFArrayHandler called for each array member */
392 CFArrayApplyFunction (refElementCurrent, range, HIDGetElementsCFArrayHandler, pDevice); 413 CFArrayApplyFunction (refElementCurrent, range,
393 } 414 HIDGetElementsCFArrayHandler, pDevice);
394 } 415 }
416 }
395 417
396 /* handles extracting element information from element collection CF types 418 /* handles extracting element information from element collection CF types
397 * used from top level element decoding and hierarchy deconstruction to flatten device element list 419 * used from top level element decoding and hierarchy deconstruction to flatten device element list
398 */ 420 */
399 421
400 static void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice) 422 static void
401 { 423 HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties,
402 CFTypeRef refElementTop = CFDictionaryGetValue (deviceProperties, CFSTR(kIOHIDElementKey)); 424 recDevice * pDevice)
403 if (refElementTop) 425 {
404 HIDGetElements (refElementTop, pDevice); 426 CFTypeRef refElementTop =
427 CFDictionaryGetValue (deviceProperties, CFSTR (kIOHIDElementKey));
428 if (refElementTop)
429 HIDGetElements (refElementTop, pDevice);
405 } 430 }
406 431
407 /* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */ 432 /* use top level element usage page and usage to discern device usage page and usage setting appropriate vlaues in device record */
408 433
409 static void HIDTopLevelElementHandler (const void * value, void * parameter) 434 static void
410 { 435 HIDTopLevelElementHandler (const void *value, void *parameter)
411 CFTypeRef refCF = 0; 436 {
412 if (CFGetTypeID (value) != CFDictionaryGetTypeID ()) 437 CFTypeRef refCF = 0;
413 return; 438 if (CFGetTypeID (value) != CFDictionaryGetTypeID ())
414 refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsagePageKey)); 439 return;
415 if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage)) 440 refCF = CFDictionaryGetValue (value, CFSTR (kIOHIDElementUsagePageKey));
416 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage."); 441 if (!CFNumberGetValue
417 refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsageKey)); 442 (refCF, kCFNumberLongType, &((recDevice *) parameter)->usagePage))
418 if (!CFNumberGetValue (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage)) 443 SDL_SetError
419 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage."); 444 ("CFNumberGetValue error retrieving pDevice->usagePage.");
445 refCF = CFDictionaryGetValue (value, CFSTR (kIOHIDElementUsageKey));
446 if (!CFNumberGetValue
447 (refCF, kCFNumberLongType, &((recDevice *) parameter)->usage))
448 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage.");
420 } 449 }
421 450
422 /* extracts device info from CF dictionary records in IO registry */ 451 /* extracts device info from CF dictionary records in IO registry */
423 452
424 static void HIDGetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, recDevice *pDevice) 453 static void
425 { 454 HIDGetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties,
426 CFMutableDictionaryRef usbProperties = 0; 455 recDevice * pDevice)
427 io_registry_entry_t parent1, parent2; 456 {
428 457 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 458 io_registry_entry_t parent1, parent2;
430 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties 459
431 */ 460 /* 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)) && 461 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
433 (KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) && 462 */
434 (KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) 463 if ((KERN_SUCCESS ==
435 { 464 IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1))
436 if (usbProperties) 465 && (KERN_SUCCESS ==
437 { 466 IORegistryEntryGetParentEntry (parent1, kIOServicePlane,
438 CFTypeRef refCF = 0; 467 &parent2))
439 /* get device info 468 && (KERN_SUCCESS ==
440 * try hid dictionary first, if fail then go to usb dictionary 469 IORegistryEntryCreateCFProperties (parent2, &usbProperties,
441 */ 470 kCFAllocatorDefault,
442 471 kNilOptions))) {
443 472 if (usbProperties) {
444 /* get product name */ 473 CFTypeRef refCF = 0;
445 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey)); 474 /* get device info
446 if (!refCF) 475 * try hid dictionary first, if fail then go to usb dictionary
447 refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name")); 476 */
448 if (refCF) 477
449 { 478
450 if (!CFStringGetCString (refCF, pDevice->product, 256, CFStringGetSystemEncoding ())) 479 /* get product name */
451 SDL_SetError ("CFStringGetCString error retrieving pDevice->product."); 480 refCF =
452 } 481 CFDictionaryGetValue (hidProperties,
453 482 CFSTR (kIOHIDProductKey));
454 /* get usage page and usage */ 483 if (!refCF)
455 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); 484 refCF =
456 if (refCF) 485 CFDictionaryGetValue (usbProperties,
457 { 486 CFSTR ("USB Product Name"));
458 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage)) 487 if (refCF) {
459 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usagePage."); 488 if (!CFStringGetCString
460 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); 489 (refCF, pDevice->product, 256,
461 if (refCF) 490 CFStringGetSystemEncoding ()))
462 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage)) 491 SDL_SetError
463 SDL_SetError ("CFNumberGetValue error retrieving pDevice->usage."); 492 ("CFStringGetCString error retrieving pDevice->product.");
464 } 493 }
465 494
466 if (NULL == refCF) /* get top level element HID usage page or usage */ 495 /* get usage page and usage */
467 { 496 refCF =
468 /* use top level element instead */ 497 CFDictionaryGetValue (hidProperties,
469 CFTypeRef refCFTopElement = 0; 498 CFSTR (kIOHIDPrimaryUsagePageKey));
470 refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey)); 499 if (refCF) {
471 { 500 if (!CFNumberGetValue
472 /* refCFTopElement points to an array of element dictionaries */ 501 (refCF, kCFNumberLongType, &pDevice->usagePage))
473 CFRange range = {0, CFArrayGetCount (refCFTopElement)}; 502 SDL_SetError
474 CFArrayApplyFunction (refCFTopElement, range, HIDTopLevelElementHandler, pDevice); 503 ("CFNumberGetValue error retrieving pDevice->usagePage.");
475 } 504 refCF =
476 } 505 CFDictionaryGetValue (hidProperties,
477 506 CFSTR (kIOHIDPrimaryUsageKey));
478 CFRelease (usbProperties); 507 if (refCF)
479 } 508 if (!CFNumberGetValue
480 else 509 (refCF, kCFNumberLongType, &pDevice->usage))
481 SDL_SetError ("IORegistryEntryCreateCFProperties failed to create usbProperties."); 510 SDL_SetError
482 511 ("CFNumberGetValue error retrieving pDevice->usage.");
483 if (kIOReturnSuccess != IOObjectRelease (parent2)) 512 }
484 SDL_SetError ("IOObjectRelease error with parent2."); 513
485 if (kIOReturnSuccess != IOObjectRelease (parent1)) 514 if (NULL == refCF) { /* get top level element HID usage page or usage */
486 SDL_SetError ("IOObjectRelease error with parent1."); 515 /* use top level element instead */
487 } 516 CFTypeRef refCFTopElement = 0;
488 } 517 refCFTopElement =
489 518 CFDictionaryGetValue (hidProperties,
490 519 CFSTR (kIOHIDElementKey));
491 static recDevice *HIDBuildDevice (io_object_t hidDevice) 520 {
492 { 521 /* refCFTopElement points to an array of element dictionaries */
493 recDevice *pDevice = (recDevice *) NewPtrClear (sizeof (recDevice)); 522 CFRange range = { 0, CFArrayGetCount (refCFTopElement) };
494 if (pDevice) 523 CFArrayApplyFunction (refCFTopElement, range,
495 { 524 HIDTopLevelElementHandler, pDevice);
496 /* get dictionary for HID properties */ 525 }
497 CFMutableDictionaryRef hidProperties = 0; 526 }
498 kern_return_t result = IORegistryEntryCreateCFProperties (hidDevice, &hidProperties, kCFAllocatorDefault, kNilOptions); 527
499 if ((result == KERN_SUCCESS) && hidProperties) 528 CFRelease (usbProperties);
500 { 529 } else
501 /* create device interface */ 530 SDL_SetError
502 result = HIDCreateOpenDeviceInterface (hidDevice, pDevice); 531 ("IORegistryEntryCreateCFProperties failed to create usbProperties.");
503 if (kIOReturnSuccess == result) 532
504 { 533 if (kIOReturnSuccess != IOObjectRelease (parent2))
505 HIDGetDeviceInfo (hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */ 534 SDL_SetError ("IOObjectRelease error with parent2.");
506 HIDGetCollectionElements (hidProperties, pDevice); 535 if (kIOReturnSuccess != IOObjectRelease (parent1))
507 } 536 SDL_SetError ("IOObjectRelease error with parent1.");
508 else 537 }
509 { 538 }
510 DisposePtr((Ptr)pDevice); 539
511 pDevice = NULL; 540
512 } 541 static recDevice *
513 CFRelease (hidProperties); 542 HIDBuildDevice (io_object_t hidDevice)
514 } 543 {
515 else 544 recDevice *pDevice = (recDevice *) NewPtrClear (sizeof (recDevice));
516 { 545 if (pDevice) {
517 DisposePtr((Ptr)pDevice); 546 /* get dictionary for HID properties */
518 pDevice = NULL; 547 CFMutableDictionaryRef hidProperties = 0;
519 } 548 kern_return_t result =
520 } 549 IORegistryEntryCreateCFProperties (hidDevice, &hidProperties,
521 return pDevice; 550 kCFAllocatorDefault,
551 kNilOptions);
552 if ((result == KERN_SUCCESS) && hidProperties) {
553 /* create device interface */
554 result = HIDCreateOpenDeviceInterface (hidDevice, pDevice);
555 if (kIOReturnSuccess == result) {
556 HIDGetDeviceInfo (hidDevice, hidProperties, pDevice); /* hidDevice used to find parents in registry tree */
557 HIDGetCollectionElements (hidProperties, pDevice);
558 } else {
559 DisposePtr ((Ptr) pDevice);
560 pDevice = NULL;
561 }
562 CFRelease (hidProperties);
563 } else {
564 DisposePtr ((Ptr) pDevice);
565 pDevice = NULL;
566 }
567 }
568 return pDevice;
522 } 569 }
523 570
524 /* disposes of the element list associated with a device and the memory associated with the list 571 /* disposes of the element list associated with a device and the memory associated with the list
525 */ 572 */
526 573
527 static void HIDDisposeElementList (recElement **elementList) 574 static void
528 { 575 HIDDisposeElementList (recElement ** elementList)
529 recElement *pElement = *elementList; 576 {
530 while (pElement) 577 recElement *pElement = *elementList;
531 { 578 while (pElement) {
532 recElement *pElementNext = pElement->pNext; 579 recElement *pElementNext = pElement->pNext;
533 DisposePtr ((Ptr) pElement); 580 DisposePtr ((Ptr) pElement);
534 pElement = pElementNext; 581 pElement = pElementNext;
535 } 582 }
536 *elementList = NULL; 583 *elementList = NULL;
537 } 584 }
538 585
539 /* disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL 586 /* 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) 587 * all your device no longer belong to us... (i.e., you do not 'own' the device anymore)
541 */ 588 */
542 589
543 static recDevice *HIDDisposeDevice (recDevice **ppDevice) 590 static recDevice *
544 { 591 HIDDisposeDevice (recDevice ** ppDevice)
545 kern_return_t result = KERN_SUCCESS; 592 {
546 recDevice *pDeviceNext = NULL; 593 kern_return_t result = KERN_SUCCESS;
547 if (*ppDevice) 594 recDevice *pDeviceNext = NULL;
548 { 595 if (*ppDevice) {
549 /* save next device prior to disposing of this device */ 596 /* save next device prior to disposing of this device */
550 pDeviceNext = (*ppDevice)->pNext; 597 pDeviceNext = (*ppDevice)->pNext;
551 598
552 /* free element lists */ 599 /* free element lists */
553 HIDDisposeElementList (&(*ppDevice)->firstAxis); 600 HIDDisposeElementList (&(*ppDevice)->firstAxis);
554 HIDDisposeElementList (&(*ppDevice)->firstButton); 601 HIDDisposeElementList (&(*ppDevice)->firstButton);
555 HIDDisposeElementList (&(*ppDevice)->firstHat); 602 HIDDisposeElementList (&(*ppDevice)->firstHat);
556 603
557 result = HIDCloseReleaseInterface (*ppDevice); /* function sanity checks interface value (now application does not own device) */ 604 result = HIDCloseReleaseInterface (*ppDevice); /* function sanity checks interface value (now application does not own device) */
558 if (kIOReturnSuccess != result) 605 if (kIOReturnSuccess != result)
559 HIDReportErrorNum ("HIDCloseReleaseInterface failed when trying to dipose device.", result); 606 HIDReportErrorNum
560 DisposePtr ((Ptr)*ppDevice); 607 ("HIDCloseReleaseInterface failed when trying to dipose device.",
561 *ppDevice = NULL; 608 result);
562 } 609 DisposePtr ((Ptr) * ppDevice);
563 return pDeviceNext; 610 *ppDevice = NULL;
611 }
612 return pDeviceNext;
564 } 613 }
565 614
566 615
567 /* Function to scan the system for joysticks. 616 /* Function to scan the system for joysticks.
568 * Joystick 0 should be the system default joystick. 617 * Joystick 0 should be the system default joystick.
569 * This function should return the number of available joysticks, or -1 618 * This function should return the number of available joysticks, or -1
570 * on an unrecoverable fatal error. 619 * on an unrecoverable fatal error.
571 */ 620 */
572 int SDL_SYS_JoystickInit(void) 621 int
573 { 622 SDL_SYS_JoystickInit (void)
574 IOReturn result = kIOReturnSuccess; 623 {
575 mach_port_t masterPort = 0; 624 IOReturn result = kIOReturnSuccess;
576 io_iterator_t hidObjectIterator = 0; 625 mach_port_t masterPort = 0;
577 CFMutableDictionaryRef hidMatchDictionary = NULL; 626 io_iterator_t hidObjectIterator = 0;
578 recDevice *device, *lastDevice; 627 CFMutableDictionaryRef hidMatchDictionary = NULL;
579 io_object_t ioHIDDeviceObject = 0; 628 recDevice *device, *lastDevice;
580 629 io_object_t ioHIDDeviceObject = 0;
581 SDL_numjoysticks = 0; 630
582 631 SDL_numjoysticks = 0;
583 if (gpDeviceList) 632
584 { 633 if (gpDeviceList) {
585 SDL_SetError("Joystick: Device list already inited."); 634 SDL_SetError ("Joystick: Device list already inited.");
586 return -1; 635 return -1;
587 } 636 }
588 637
589 result = IOMasterPort (bootstrap_port, &masterPort); 638 result = IOMasterPort (bootstrap_port, &masterPort);
590 if (kIOReturnSuccess != result) 639 if (kIOReturnSuccess != result) {
591 { 640 SDL_SetError ("Joystick: IOMasterPort error with bootstrap_port.");
592 SDL_SetError("Joystick: IOMasterPort error with bootstrap_port."); 641 return -1;
593 return -1; 642 }
594 } 643
595 644 /* 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. */ 645 hidMatchDictionary = IOServiceMatching (kIOHIDDeviceKey);
597 hidMatchDictionary = IOServiceMatching (kIOHIDDeviceKey); 646 if (hidMatchDictionary) {
598 if (hidMatchDictionary) 647 /* Add key for device type (joystick, in this case) to refine the matching dictionary. */
599 { 648
600 /* Add key for device type (joystick, in this case) to refine the matching dictionary. */ 649 /* NOTE: we now perform this filtering later
601 650 UInt32 usagePage = kHIDPage_GenericDesktop;
602 /* NOTE: we now perform this filtering later 651 UInt32 usage = kHIDUsage_GD_Joystick;
603 UInt32 usagePage = kHIDPage_GenericDesktop; 652 CFNumberRef refUsage = NULL, refUsagePage = NULL;
604 UInt32 usage = kHIDUsage_GD_Joystick; 653
605 CFNumberRef refUsage = NULL, refUsagePage = NULL; 654 refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage);
606 655 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage);
607 refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usage); 656 refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage);
608 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage); 657 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage);
609 refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &usagePage); 658 */
610 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage); 659 } else {
611 */ 660 SDL_SetError
612 } 661 ("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching.");
613 else 662 return -1;
614 { 663 }
615 SDL_SetError("Joystick: Failed to get HID CFMutableDictionaryRef via IOServiceMatching."); 664
616 return -1; 665 /*/ Now search I/O Registry for matching devices. */
617 } 666 result =
618 667 IOServiceGetMatchingServices (masterPort, hidMatchDictionary,
619 /*/ Now search I/O Registry for matching devices. */ 668 &hidObjectIterator);
620 result = IOServiceGetMatchingServices (masterPort, hidMatchDictionary, &hidObjectIterator); 669 /* Check for errors */
621 /* Check for errors */ 670 if (kIOReturnSuccess != result) {
622 if (kIOReturnSuccess != result) 671 SDL_SetError ("Joystick: Couldn't create a HID object iterator.");
623 { 672 return -1;
624 SDL_SetError("Joystick: Couldn't create a HID object iterator."); 673 }
625 return -1; 674 if (!hidObjectIterator) { /* there are no joysticks */
626 } 675 gpDeviceList = NULL;
627 if (!hidObjectIterator) /* there are no joysticks */ 676 SDL_numjoysticks = 0;
628 { 677 return 0;
629 gpDeviceList = NULL; 678 }
630 SDL_numjoysticks = 0; 679 /* IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref. */
631 return 0; 680
632 } 681 /* 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. */ 682
634 683 gpDeviceList = lastDevice = NULL;
635 /* build flat linked list of devices from device iterator */ 684
636 685 while ((ioHIDDeviceObject = IOIteratorNext (hidObjectIterator))) {
637 gpDeviceList = lastDevice = NULL; 686 /* build a device record */
638 687 device = HIDBuildDevice (ioHIDDeviceObject);
639 while ((ioHIDDeviceObject = IOIteratorNext (hidObjectIterator))) 688 if (!device)
640 { 689 continue;
641 /* build a device record */ 690
642 device = HIDBuildDevice (ioHIDDeviceObject); 691 /* dump device object, it is no longer needed */
643 if (!device) 692 result = IOObjectRelease (ioHIDDeviceObject);
644 continue;
645
646 /* dump device object, it is no longer needed */
647 result = IOObjectRelease (ioHIDDeviceObject);
648 /* if (KERN_SUCCESS != result) 693 /* if (KERN_SUCCESS != result)
649 HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result); 694 HIDReportErrorNum ("IOObjectRelease error with ioHIDDeviceObject.", result);
650 */ 695 */
651 696
652 /* Filter device list to non-keyboard/mouse stuff */ 697 /* Filter device list to non-keyboard/mouse stuff */
653 if ( (device->usagePage != kHIDPage_GenericDesktop) || 698 if ((device->usagePage != kHIDPage_GenericDesktop) ||
654 ((device->usage != kHIDUsage_GD_Joystick && 699 ((device->usage != kHIDUsage_GD_Joystick &&
655 device->usage != kHIDUsage_GD_GamePad)) ) { 700 device->usage != kHIDUsage_GD_GamePad))) {
656 701
657 /* release memory for the device */ 702 /* release memory for the device */
658 HIDDisposeDevice (&device); 703 HIDDisposeDevice (&device);
659 DisposePtr((Ptr)device); 704 DisposePtr ((Ptr) device);
660 continue; 705 continue;
661 } 706 }
662 707
663 /* Add device to the end of the list */ 708 /* Add device to the end of the list */
664 if (lastDevice) 709 if (lastDevice)
665 lastDevice->pNext = device; 710 lastDevice->pNext = device;
666 else 711 else
667 gpDeviceList = device; 712 gpDeviceList = device;
668 lastDevice = device; 713 lastDevice = device;
669 } 714 }
670 result = IOObjectRelease (hidObjectIterator); /* release the iterator */ 715 result = IOObjectRelease (hidObjectIterator); /* release the iterator */
671 716
672 /* Count the total number of devices we found */ 717 /* Count the total number of devices we found */
673 device = gpDeviceList; 718 device = gpDeviceList;
674 while (device) 719 while (device) {
675 { 720 SDL_numjoysticks++;
676 SDL_numjoysticks++; 721 device = device->pNext;
677 device = device->pNext; 722 }
678 } 723
679 724 return SDL_numjoysticks;
680 return SDL_numjoysticks;
681 } 725 }
682 726
683 /* Function to get the device-dependent name of a joystick */ 727 /* Function to get the device-dependent name of a joystick */
684 const char *SDL_SYS_JoystickName(int index) 728 const char *
685 { 729 SDL_SYS_JoystickName (int index)
686 recDevice *device = gpDeviceList; 730 {
687 731 recDevice *device = gpDeviceList;
688 for (; index > 0; index--) 732
689 device = device->pNext; 733 for (; index > 0; index--)
690 734 device = device->pNext;
691 return device->product; 735
736 return device->product;
692 } 737 }
693 738
694 /* Function to open a joystick for use. 739 /* Function to open a joystick for use.
695 * The joystick to open is specified by the index field of the joystick. 740 * 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. 741 * This should fill the nbuttons and naxes fields of the joystick structure.
697 * It returns 0, or -1 if there is an error. 742 * It returns 0, or -1 if there is an error.
698 */ 743 */
699 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick) 744 int
700 { 745 SDL_SYS_JoystickOpen (SDL_Joystick * joystick)
701 recDevice *device = gpDeviceList; 746 {
702 int index; 747 recDevice *device = gpDeviceList;
703 748 int index;
704 for (index = joystick->index; index > 0; index--) 749
705 device = device->pNext; 750 for (index = joystick->index; index > 0; index--)
706 751 device = device->pNext;
707 joystick->hwdata = device; 752
708 joystick->name = device->product; 753 joystick->hwdata = device;
709 754 joystick->name = device->product;
710 joystick->naxes = device->axes; 755
711 joystick->nhats = device->hats; 756 joystick->naxes = device->axes;
712 joystick->nballs = 0; 757 joystick->nhats = device->hats;
713 joystick->nbuttons = device->buttons; 758 joystick->nballs = 0;
714 759 joystick->nbuttons = device->buttons;
715 return 0; 760
761 return 0;
716 } 762 }
717 763
718 /* Function to update the state of a joystick - called as a device poll. 764 /* Function to update the state of a joystick - called as a device poll.
719 * This function shouldn't update the joystick structure directly, 765 * This function shouldn't update the joystick structure directly,
720 * but instead should call SDL_PrivateJoystick*() to deliver events 766 * but instead should call SDL_PrivateJoystick*() to deliver events
721 * and update joystick device state. 767 * and update joystick device state.
722 */ 768 */
723 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) 769 void
724 { 770 SDL_SYS_JoystickUpdate (SDL_Joystick * joystick)
725 recDevice *device = joystick->hwdata; 771 {
726 recElement *element; 772 recDevice *device = joystick->hwdata;
727 SInt32 value; 773 recElement *element;
728 int i; 774 SInt32 value;
729 775 int i;
730 if (device->removed) /* device was unplugged; ignore it. */ 776
731 { 777 if (device->removed) { /* device was unplugged; ignore it. */
732 if (device->uncentered) 778 if (device->uncentered) {
733 { 779 device->uncentered = 0;
734 device->uncentered = 0; 780
735 781 /* Tell the app that everything is centered/unpressed... */
736 /* Tell the app that everything is centered/unpressed... */ 782 for (i = 0; i < device->axes; i++)
737 for (i = 0; i < device->axes; i++) 783 SDL_PrivateJoystickAxis (joystick, i, 0);
738 SDL_PrivateJoystickAxis(joystick, i, 0); 784
739 785 for (i = 0; i < device->buttons; i++)
740 for (i = 0; i < device->buttons; i++) 786 SDL_PrivateJoystickButton (joystick, i, 0);
741 SDL_PrivateJoystickButton(joystick, i, 0); 787
742 788 for (i = 0; i < device->hats; i++)
743 for (i = 0; i < device->hats; i++) 789 SDL_PrivateJoystickHat (joystick, i, SDL_HAT_CENTERED);
744 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); 790 }
745 } 791
746 792 return;
747 return; 793 }
748 } 794
749 795 element = device->firstAxis;
750 element = device->firstAxis; 796 i = 0;
751 i = 0; 797 while (element) {
752 while (element) 798 value = HIDScaledCalibratedValue (device, element, -32768, 32767);
753 { 799 if (value != joystick->axes[i])
754 value = HIDScaledCalibratedValue(device, element, -32768, 32767); 800 SDL_PrivateJoystickAxis (joystick, i, value);
755 if ( value != joystick->axes[i] ) 801 element = element->pNext;
756 SDL_PrivateJoystickAxis(joystick, i, value); 802 ++i;
757 element = element->pNext; 803 }
758 ++i; 804
759 } 805 element = device->firstButton;
760 806 i = 0;
761 element = device->firstButton; 807 while (element) {
762 i = 0; 808 value = HIDGetElementValue (device, element);
763 while (element) 809 if (value > 1) /* handle pressure-sensitive buttons */
764 {
765 value = HIDGetElementValue(device, element);
766 if (value > 1) /* handle pressure-sensitive buttons */
767 value = 1; 810 value = 1;
768 if ( value != joystick->buttons[i] ) 811 if (value != joystick->buttons[i])
769 SDL_PrivateJoystickButton(joystick, i, value); 812 SDL_PrivateJoystickButton (joystick, i, value);
770 element = element->pNext; 813 element = element->pNext;
771 ++i; 814 ++i;
772 } 815 }
773 816
774 element = device->firstHat; 817 element = device->firstHat;
775 i = 0; 818 i = 0;
776 while (element) 819 while (element) {
777 { 820 Uint8 pos = 0;
778 Uint8 pos = 0; 821
779 822 value = HIDGetElementValue (device, element);
780 value = HIDGetElementValue(device, element); 823 if (element->max == 3) /* 4 position hatswitch - scale up value */
781 if (element->max == 3) /* 4 position hatswitch - scale up value */ 824 value *= 2;
782 value *= 2; 825 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) */ 826 value = -1;
784 value = -1; 827 switch (value) {
785 switch(value) 828 case 0:
786 { 829 pos = SDL_HAT_UP;
787 case 0: 830 break;
788 pos = SDL_HAT_UP; 831 case 1:
789 break; 832 pos = SDL_HAT_RIGHTUP;
790 case 1: 833 break;
791 pos = SDL_HAT_RIGHTUP; 834 case 2:
792 break; 835 pos = SDL_HAT_RIGHT;
793 case 2: 836 break;
794 pos = SDL_HAT_RIGHT; 837 case 3:
795 break; 838 pos = SDL_HAT_RIGHTDOWN;
796 case 3: 839 break;
797 pos = SDL_HAT_RIGHTDOWN; 840 case 4:
798 break; 841 pos = SDL_HAT_DOWN;
799 case 4: 842 break;
800 pos = SDL_HAT_DOWN; 843 case 5:
801 break; 844 pos = SDL_HAT_LEFTDOWN;
802 case 5: 845 break;
803 pos = SDL_HAT_LEFTDOWN; 846 case 6:
804 break; 847 pos = SDL_HAT_LEFT;
805 case 6: 848 break;
806 pos = SDL_HAT_LEFT; 849 case 7:
807 break; 850 pos = SDL_HAT_LEFTUP;
808 case 7: 851 break;
809 pos = SDL_HAT_LEFTUP; 852 default:
810 break; 853 /* Every other value is mapped to center. We do that because some
811 default: 854 * joysticks use 8 and some 15 for this value, and apparently
812 /* Every other value is mapped to center. We do that because some 855 * 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 856 */
814 * there are even more variants out there - so we try to be generous. 857 pos = SDL_HAT_CENTERED;
815 */ 858 break;
816 pos = SDL_HAT_CENTERED; 859 }
817 break; 860 if (pos != joystick->hats[i])
818 } 861 SDL_PrivateJoystickHat (joystick, i, pos);
819 if ( pos != joystick->hats[i] ) 862 element = element->pNext;
820 SDL_PrivateJoystickHat(joystick, i, pos); 863 ++i;
821 element = element->pNext; 864 }
822 ++i; 865
823 } 866 return;
824
825 return;
826 } 867 }
827 868
828 /* Function to close a joystick after use */ 869 /* Function to close a joystick after use */
829 void SDL_SYS_JoystickClose(SDL_Joystick *joystick) 870 void
830 { 871 SDL_SYS_JoystickClose (SDL_Joystick * joystick)
831 /* Should we do anything here? */ 872 {
832 return; 873 /* Should we do anything here? */
874 return;
833 } 875 }
834 876
835 /* Function to perform any system-specific joystick related cleanup */ 877 /* Function to perform any system-specific joystick related cleanup */
836 void SDL_SYS_JoystickQuit(void) 878 void
837 { 879 SDL_SYS_JoystickQuit (void)
838 while (NULL != gpDeviceList) 880 {
839 gpDeviceList = HIDDisposeDevice (&gpDeviceList); 881 while (NULL != gpDeviceList)
882 gpDeviceList = HIDDisposeDevice (&gpDeviceList);
840 } 883 }
841 884
842 #endif /* SDL_JOYSTICK_IOKIT */ 885 #endif /* SDL_JOYSTICK_IOKIT */
886 /* vi: set ts=4 sw=4 expandtab: */