Mercurial > sdl-ios-xcode
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 (2006-07-10) |
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: */ |