Mercurial > sdl-ios-xcode
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: */ |