Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangPrimSource / HID_Utilities_10_4 / HID_Utilities.c
blob44873546830d8b6d43072a6f80701add6d7b5b16
1 /*
2 File: HID_Utilities.c
4 Contains: Implementation of HID Utilities
6 DRI: George Warner
8 Copyright: Copyright © 2002 Apple Computer, Inc., All Rights Reserved
10 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
11 ("Apple") in consideration of your agreement to the following terms, and your
12 use, installation, modification or redistribution of this Apple software
13 constitutes acceptance of these terms. If you do not agree with these terms,
14 please do not use, install, modify or redistribute this Apple software.
16 In consideration of your agreement to abide by the following terms, and subject
17 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
18 copyrights in this original Apple software (the "Apple Software"), to use,
19 reproduce, modify and redistribute the Apple Software, with or without
20 modifications, in source and/or binary forms; provided that if you redistribute
21 the Apple Software in its entirety and without modifications, you must retain
22 this notice and the following text and disclaimers in all such redistributions of
23 the Apple Software. Neither the name, trademarks, service marks or logos of
24 Apple Computer, Inc. may be used to endorse or promote products derived from the
25 Apple Software without specific prior written permission from Apple. Except as
26 expressly stated in this notice, no other rights or licenses, express or implied,
27 are granted by Apple herein, including but not limited to any patent rights that
28 may be infringed by your derivative works or by other works in which the Apple
29 Software may be incorporated.
31 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
32 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
33 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
35 COMBINATION WITH YOUR PRODUCTS.
37 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
38 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
39 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
41 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
42 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
43 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 #ifdef SC_DARWIN
46 #include "HID_Utilities_Internal.h"
47 #include "HID_Utilities_External.h"
49 #include <IOKit/IOCFPlugIn.h>
50 #include <IOKit/IOKitLib.h>
51 #include <IOKit/IOMessage.h>
52 #include <IOKit/hid/IOHIDUsageTables.h>
54 //================================================================================================
55 #define USE_NOTIFICATIONS 1
56 //================================================================================================
57 // local (static) functions
58 //================================================================================================
59 static void hid_GetCollectionElements (CFMutableDictionaryRef deviceProperties, pRecElement *ppCurrentCollection);
60 static pRecDevice hid_DisposeDevice (pRecDevice ppDevice);
61 //================================================================================================
62 // globals
63 //================================================================================================
64 #if USE_NOTIFICATIONS
65 static IONotificationPortRef gNotifyPort;
66 static io_iterator_t gAddedIter;
67 static CFRunLoopRef gRunLoop;
68 #endif USE_NOTIFICATIONS
70 // for element retrieval
71 static pRecDevice gCurrentGetDevice = NULL;
72 static Boolean gAddAsChild = false;
73 static int gDepth = false;
75 static pRecDevice gpDeviceList = NULL;
76 static UInt32 gNumDevices = 0;
78 #pragma mark private functions
79 // ==================================
80 // private functions
82 static UInt32 hid_CountCurrentDevices (void);
84 // extracts actual specific element information from each element CF dictionary entry
85 static void hid_GetElementInfo (CFTypeRef refElement, pRecElement pElement)
87 long number;
88 CFTypeRef refType;
89 // type, usagePage, usage already stored
90 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementCookieKey));
91 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
92 pElement->cookie = (IOHIDElementCookie) number;
93 else
94 pElement->cookie = (IOHIDElementCookie) 0;
96 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMinKey));
97 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
98 pElement->min = number;
99 else
100 pElement->min = 0;
102 pElement->calMax = pElement->min;
103 pElement->userMin = kDefaultUserMin;
105 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementMaxKey));
106 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
107 pElement->max = number;
108 else
109 pElement->max = 0;
111 pElement->calMin = pElement->max;
112 pElement->userMax = kDefaultUserMax;
114 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMinKey));
115 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
116 pElement->scaledMin = number;
117 else
118 pElement->scaledMin = 0;
120 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementScaledMaxKey));
121 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
122 pElement->scaledMax = number;
123 else
124 pElement->scaledMax = 0;
126 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementSizeKey));
127 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
128 pElement->size = number;
129 else
130 pElement->size = 0;
132 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsRelativeKey));
133 if (refType)
134 pElement->relative = CFBooleanGetValue (refType);
135 else
136 pElement->relative = 0;
138 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsWrappingKey));
139 if (refType)
140 pElement->wrapping = CFBooleanGetValue (refType);
141 else
142 pElement->wrapping = false;
144 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementIsNonLinearKey));
145 if (refType)
146 pElement->nonLinear = CFBooleanGetValue (refType);
147 else
148 pElement->wrapping = false;
150 #ifdef kIOHIDElementHasPreferredStateKey
151 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasPreferredStateKey));
152 #else // Mac OS X 10.0 has spelling error
153 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasPreferedStateKey));
154 #endif
155 if (refType)
156 pElement->preferredState = CFBooleanGetValue (refType);
157 else
158 pElement->preferredState = false;
160 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementHasNullStateKey));
161 if (refType)
162 pElement->nullState = CFBooleanGetValue (refType);
163 else
164 pElement->nullState = false;
166 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUnitKey));
167 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
168 pElement->units = number;
169 else
170 pElement->units = 0;
172 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUnitExponentKey));
173 if (refType && CFNumberGetValue (refType, kCFNumberLongType, &number))
174 pElement->unitExp = number;
175 else
176 pElement->unitExp = 0;
178 refType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementNameKey));
179 if (refType)
180 if (!CFStringGetCString (refType, pElement->name, 256, CFStringGetSystemEncoding ()))
181 HIDReportError ("CFStringGetCString error retrieving pElement->name.");
182 if (!*pElement->name)
184 // set name from vendor id, product id & usage info look up
185 if (!HIDGetElementNameFromVendorProductUsage (gCurrentGetDevice->vendorID, gCurrentGetDevice->productID, pElement->usagePage, pElement->usage, pElement->name))
187 // set name from vendor id/product id look up
188 HIDGetElementNameFromVendorProductCookie (gCurrentGetDevice->vendorID, gCurrentGetDevice->productID, (long) pElement->cookie, pElement->name);
189 if (!*pElement->name) { // if no name
190 HIDGetUsageName (pElement->usagePage, pElement->usage, pElement->name);
191 if (!*pElement->name) // if not usage
192 sprintf (pElement->name, "Element");
198 // ---------------------------------
199 // examines CF dictionary vlaue in device element hierarchy to determine if it is element of interest or a collection of more elements
200 // if element of interest allocate storage, add to list and retrieve element specific info
201 // if collection then pass on to deconstruction collection into additional individual elements
203 static void hid_AddElement (CFTypeRef refElement, pRecElement * ppElementCurrent)
205 pRecDevice pDevice = gCurrentGetDevice;
206 pRecElement pElement = NULL;
207 long elementType, usagePage, usage;
208 CFTypeRef refElementType = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementTypeKey));
209 CFTypeRef refUsagePage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsagePageKey));
210 CFTypeRef refUsage = CFDictionaryGetValue (refElement, CFSTR(kIOHIDElementUsageKey));
212 if (refElementType)
213 CFNumberGetValue (refElementType, kCFNumberLongType, &elementType);
214 if (refUsagePage)
215 CFNumberGetValue (refUsagePage, kCFNumberLongType, &usagePage);
216 if (refUsage)
217 CFNumberGetValue (refUsage, kCFNumberLongType, &usage);
219 if (NULL == pDevice)
220 return;
222 if (elementType)
224 // look at types of interest
225 if (elementType != kIOHIDElementTypeCollection)
227 if (usagePage && usage) // if valid usage and page
229 switch (usagePage) // only interested in kHIDPage_GenericDesktop and kHIDPage_Button
231 case kHIDPage_GenericDesktop:
233 switch (usage) // look at usage to determine function
235 case kHIDUsage_GD_X:
236 case kHIDUsage_GD_Y:
237 case kHIDUsage_GD_Z:
238 case kHIDUsage_GD_Rx:
239 case kHIDUsage_GD_Ry:
240 case kHIDUsage_GD_Rz:
241 pElement = (pRecElement) malloc (sizeof (recElement));
242 if (pElement) pDevice->axis++;
243 break;
244 case kHIDUsage_GD_Slider:
245 pElement = (pRecElement) malloc (sizeof (recElement));
246 if (pElement) pDevice->sliders++;
247 break;
248 case kHIDUsage_GD_Dial:
249 pElement = (pRecElement) malloc (sizeof (recElement));
250 if (pElement) pDevice->dials++;
251 break;
252 case kHIDUsage_GD_Wheel:
253 pElement = (pRecElement) malloc (sizeof (recElement));
254 if (pElement) pDevice->wheels++;
255 break;
256 case kHIDUsage_GD_Hatswitch:
257 pElement = (pRecElement) malloc (sizeof (recElement));
258 if (pElement) pDevice->hats++;
259 break;
260 default:
261 pElement = (pRecElement) malloc (sizeof (recElement));
262 break;
265 break;
266 case kHIDPage_Button:
267 pElement = (pRecElement) malloc (sizeof (recElement));
268 if (pElement) pDevice->buttons++;
269 break;
270 default:
271 // just add a generic element
272 pElement = (pRecElement) malloc (sizeof (recElement));
273 break;
276 #if 0
277 else
278 HIDReportError ("CFNumberGetValue error when getting value for refUsage or refUsagePage.");
279 #endif 0
281 else // collection
282 pElement = (pRecElement) malloc (sizeof (recElement));
284 else
285 HIDReportError ("CFNumberGetValue error when getting value for refElementType.");
287 if (pElement) // add to list
289 // this code builds a binary tree based on the collection hierarchy of inherent in the device element layout
290 // it preserves the structure of the lements as collections have children and elements are siblings to each other
292 // clear record
293 bzero(pElement,sizeof(recElement));
295 // get element info
296 pElement->type = elementType;
297 pElement->usagePage = usagePage;
298 pElement->usage = usage;
299 pElement->depth = 0; // assume root object
300 hid_GetElementInfo (refElement, pElement);
302 // count elements
303 pDevice->totalElements++;
305 switch (pElement->type)
307 case kIOHIDElementTypeInput_Misc:
308 case kIOHIDElementTypeInput_Button:
309 case kIOHIDElementTypeInput_Axis:
310 case kIOHIDElementTypeInput_ScanCodes:
311 pDevice->inputs++;
312 break;
313 case kIOHIDElementTypeOutput:
314 pDevice->outputs++;
315 break;
316 case kIOHIDElementTypeFeature:
317 pDevice->features++;
318 break;
319 case kIOHIDElementTypeCollection:
320 pDevice->collections++;
321 break;
322 default:
323 HIDReportErrorNum ("Unknown element type : ", pElement->type);
326 if (NULL == *ppElementCurrent) // if at list head
328 pDevice->pListElements = pElement; // add current element
329 *ppElementCurrent = pElement; // set current element to element we just added
331 else // have exsiting structure
333 if (gAddAsChild) // if the previous element was a collection, let's add this as a child of the previous
335 // this iteration should not be needed but there maybe some untested degenerate case which this code will ensure works
336 while ((*ppElementCurrent)->pChild) // step down tree until free child node found
337 *ppElementCurrent = (*ppElementCurrent)->pChild;
338 (*ppElementCurrent)->pChild = pElement; // insert there
339 pElement->depth = (*ppElementCurrent)->depth + 1;
341 else // add as sibling
343 // this iteration should not be needed but there maybe some untested degenerate case which this code will ensure works
344 while ((*ppElementCurrent)->pSibling) // step down tree until free sibling node found
345 *ppElementCurrent = (*ppElementCurrent)->pSibling;
346 (*ppElementCurrent)->pSibling = pElement; // insert there
347 pElement->depth = (*ppElementCurrent)->depth;
349 pElement->pPrevious = *ppElementCurrent; // point to previous
350 *ppElementCurrent = pElement; // set current to our collection
353 if (elementType == kIOHIDElementTypeCollection) // if this element is a collection of other elements
355 gAddAsChild = true; // add next set as children to this element
356 gDepth++;
357 hid_GetCollectionElements ((CFMutableDictionaryRef) refElement, &pElement); // recursively process the collection
358 gDepth--;
360 gAddAsChild = false; // add next as this elements sibling (when return from a collection or with non-collections)
362 #if 0
363 else
364 HIDReportError ("hid_AddElement - no element added.");
365 #endif
368 // ---------------------------------
369 // collects information from each array member in device element list (each array memeber = element)
371 static void hid_GetElementsCFArrayHandler (const void * value, void * parameter)
373 if (CFGetTypeID (value) == CFDictionaryGetTypeID ())
374 hid_AddElement ((CFTypeRef) value, (pRecElement *) parameter);
377 // ---------------------------------
378 // handles retrieval of element information from arrays of elements in device IO registry information
380 static void hid_GetElements (CFTypeRef refElementCurrent, pRecElement *ppCurrentElement)
382 CFTypeID type = CFGetTypeID (refElementCurrent);
383 if (type == CFArrayGetTypeID()) // if element is an array
385 CFRange range = {0, CFArrayGetCount (refElementCurrent)};
386 // CountElementsCFArrayHandler called for each array member
387 CFArrayApplyFunction (refElementCurrent, range, hid_GetElementsCFArrayHandler, ppCurrentElement);
391 // ---------------------------------
392 // handles extracting element information from element collection CF types
393 // used from top level element decoding and hierarchy deconstruction to flatten device element list
395 static void hid_GetCollectionElements (CFMutableDictionaryRef deviceProperties, pRecElement *ppCurrentCollection)
397 CFTypeRef refElementTop = CFDictionaryGetValue (deviceProperties, CFSTR(kIOHIDElementKey));
398 if (refElementTop)
399 hid_GetElements (refElementTop, ppCurrentCollection);
400 else
401 HIDReportError ("hid_GetCollectionElements: CFDictionaryGetValue error when creating CFTypeRef for kIOHIDElementKey.");
404 // ---------------------------------
405 // use top level element usage page and usage to discern device usage page and usage setting appropriate values in device record
407 static void hid_TopLevelElementHandler (const void * value, void * parameter)
409 CFTypeRef refCF = 0;
410 if ((NULL == value) || (NULL == parameter))
411 return; // (kIOReturnBadArgument)
412 if (CFGetTypeID (value) != CFDictionaryGetTypeID ())
413 return; // (kIOReturnBadArgument)
414 refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsagePageKey));
415 if (!CFNumberGetValue (refCF, kCFNumberLongType, &((pRecDevice) parameter)->usagePage))
416 HIDReportError ("CFNumberGetValue error retrieving pDevice->usagePage.");
417 refCF = CFDictionaryGetValue (value, CFSTR(kIOHIDElementUsageKey));
418 if (!CFNumberGetValue (refCF, kCFNumberLongType, &((pRecDevice) parameter)->usage))
419 HIDReportError ("CFNumberGetValue error retrieving pDevice->usage.");
422 // ---------------------------------
423 // extracts device info from CF dictionary records in IO registry
425 static void hid_GetDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, pRecDevice pDevice)
427 CFMutableDictionaryRef usbProperties = 0;
428 io_registry_entry_t parent1, parent2;
430 // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
431 // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
432 if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) &&
433 (KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) &&
434 (KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions)))
436 if (usbProperties)
438 CFTypeRef refCF = 0;
439 // get device info
440 // try hid dictionary first, if fail then go to usb dictionary
442 // get transport
443 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDTransportKey));
444 if (refCF)
446 if (!CFStringGetCString (refCF, pDevice->transport, 256, CFStringGetSystemEncoding ()))
447 HIDReportError ("CFStringGetCString error retrieving pDevice->transport.");
450 // get vendorID
451 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDVendorIDKey));
452 if (!refCF)
453 refCF = CFDictionaryGetValue (usbProperties, CFSTR("idVendor"));
454 if (refCF)
456 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->vendorID))
457 HIDReportError ("CFNumberGetValue error retrieving pDevice->vendorID.");
460 // get product ID
461 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductIDKey));
462 if (!refCF)
463 refCF = CFDictionaryGetValue (usbProperties, CFSTR("idProduct"));
464 if (refCF)
466 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->productID))
467 HIDReportError ("CFNumberGetValue error retrieving pDevice->productID.");
470 // get product version
471 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDVersionNumberKey));
472 if (refCF)
474 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->version))
475 HIDReportError ("CFNumberGetValue error retrieving pDevice->version.");
478 // get manufacturer name
479 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDManufacturerKey));
480 if (!refCF)
481 refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Vendor Name"));
482 if (refCF)
484 if (!CFStringGetCString (refCF, pDevice->manufacturer, 256, CFStringGetSystemEncoding ()))
485 HIDReportError ("CFStringGetCString error retrieving pDevice->manufacturer.");
488 // get product name
489 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey));
490 if (!refCF)
491 refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name"));
492 if (refCF)
494 if (!CFStringGetCString (refCF, pDevice->product, 256, CFStringGetSystemEncoding ()))
495 HIDReportError ("CFStringGetCString error retrieving pDevice->product.");
498 // get serial
499 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDSerialNumberKey));
500 if (refCF)
502 if (!CFStringGetCString (refCF, pDevice->serial, 256, CFStringGetSystemEncoding ()))
503 HIDReportError ("CFStringGetCString error retrieving pDevice->serial.");
506 // get location ID
507 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDLocationIDKey));
508 if (!refCF)
509 refCF = CFDictionaryGetValue (usbProperties, CFSTR("locationID"));
510 if (refCF)
512 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->locID))
513 HIDReportError ("CFNumberGetValue error retrieving pDevice->locID.");
516 // get usage page and usage
517 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey));
518 if (refCF)
520 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usagePage))
521 HIDReportError ("CFNumberGetValue error retrieving pDevice->usagePage.");
522 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey));
523 if (refCF)
524 if (!CFNumberGetValue (refCF, kCFNumberLongType, &pDevice->usage))
525 HIDReportError ("CFNumberGetValue error retrieving pDevice->usage.");
527 if (NULL == refCF) // get top level element HID usage page or usage
529 // use top level element instead
530 CFTypeRef refCFTopElement = 0;
531 refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey));
533 // refCFTopElement points to an array of element dictionaries
534 CFRange range = {0, CFArrayGetCount (refCFTopElement)};
535 CFArrayApplyFunction (refCFTopElement, range, hid_TopLevelElementHandler, NULL);
539 else
540 HIDReportError ("IORegistryEntryCreateCFProperties failed to create usbProperties.");
542 CFRelease (usbProperties);
543 if (kIOReturnSuccess != IOObjectRelease (parent2))
544 HIDReportError ("IOObjectRelease error with parent2.");
545 if (kIOReturnSuccess != IOObjectRelease (parent1))
546 HIDReportError ("IOObjectRelease error with parent1.");
550 // ---------------------------------
551 // adds device to linked list of devices passed in (handles NULL lists properly)
552 // (returns where you just stored it)
553 static pRecDevice* hid_AddDevice (pRecDevice *ppListDeviceHead, pRecDevice pNewDevice)
555 pRecDevice* result = NULL;
557 if (NULL == *ppListDeviceHead)
558 result = ppListDeviceHead;
559 else
561 pRecDevice pDevicePrevious = NULL, pDevice = *ppListDeviceHead;
562 while (pDevice)
564 pDevicePrevious = pDevice;
565 pDevice = pDevicePrevious->pNext;
567 result = &pDevicePrevious->pNext;
569 pNewDevice->pNext = NULL;
571 *result = pNewDevice;
573 return result;
576 // ---------------------------------
577 // given a IO device object build a flat device record including device info and elements
579 static pRecDevice hid_BuildDevice (io_object_t hidDevice)
581 pRecDevice pDevice = (pRecDevice) malloc (sizeof (recDevice));
583 if (NULL != pDevice)
585 // get dictionary for HID properties
586 CFMutableDictionaryRef hidProperties = 0;
587 kern_return_t result = IORegistryEntryCreateCFProperties (hidDevice, &hidProperties, kCFAllocatorDefault, kNilOptions);
589 // clear record
590 bzero(pDevice, sizeof(recDevice));
592 if ((result == KERN_SUCCESS) && (NULL != hidProperties))
594 pRecElement pCurrentElement = NULL;
595 // create device interface
596 result = HIDCreateOpenDeviceInterface (hidDevice, pDevice);
597 if (kIOReturnSuccess != result)
598 HIDReportErrorNum ("HIDCreateOpenDeviceInterface failed.", result);
599 hid_GetDeviceInfo (hidDevice, hidProperties, pDevice); // hidDevice used to find parents in registry tree
600 // set current device for use in getting elements
601 gCurrentGetDevice = pDevice;
602 // Add all elements
603 hid_GetCollectionElements (hidProperties, &pCurrentElement);
604 gCurrentGetDevice = NULL;
605 CFRelease (hidProperties);
607 else
608 HIDReportErrorNum ("IORegistryEntryCreateCFProperties error when creating deviceProperties.", result);
610 else
611 HIDReportError ("malloc error when allocating pRecDevice.");
612 return pDevice;
615 #if USE_NOTIFICATIONS
616 //================================================================================================
618 // hid_DeviceNotification
620 // This routine will get called whenever any kIOGeneralInterest notification happens. We are
621 // interested in the kIOMessageServiceIsTerminated message so that's what we look for. Other
622 // messages are defined in IOMessage.h.
624 //================================================================================================
626 static void hid_DeviceNotification( void *refCon,
627 io_service_t service,
628 natural_t messageType,
629 void *messageArgument )
631 pRecDevice pDevice = (pRecDevice) refCon;
633 if (messageType == kIOMessageServiceIsTerminated)
635 printf("Device 0x%08x \"%s\"removed.\n", service, pDevice->product);
637 // Free the data we're no longer using now that the device is going away
638 hid_DisposeDevice (pDevice);
641 #else
643 static void hid_RemovalCallbackFunction(void * target, IOReturn result, void * refcon, void * sender)
645 hid_DisposeDevice ((pRecDevice) target);
648 #endif USE_NOTIFICATIONS
650 //================================================================================================
652 // hid_AddDevices
654 // This routine is the callback for our IOServiceAddMatchingNotification. When we get called
655 // we will look at all the devices that were added and we will:
657 // 1. Create some private data to relate to each device.
658 // 2. Submit an IOServiceAddInterestNotification of type kIOGeneralInterest for this device,
659 // using the refCon field to store a pointer to our data. When we get called with
660 // this interest notification, we can grab the refCon and access our private data.
662 //================================================================================================
664 // ---------------------------------
665 // given a IO device iterator, iterate it and add all its devices
667 static void hid_AddDevices (void *refCon, io_iterator_t iterator)
669 // NOTE: refcon passed in is used to point to the device list head
670 pRecDevice* pListDeviceHead = (pRecDevice*) refCon;
671 IOReturn result = kIOReturnSuccess;
672 io_object_t ioHIDDeviceObject = 0;
674 while (ioHIDDeviceObject = IOIteratorNext (iterator))
676 pRecDevice* pNewDeviceAt = NULL;
677 pRecDevice pNewDevice = hid_BuildDevice (ioHIDDeviceObject);
678 if (pNewDevice)
680 #if 0 // set true for verbose output
681 printf("\nhid_AddDevices: pNewDevice = {t: \"%s\", v: %ld, p: %ld, v: %ld, m: \"%s\", " \
682 "p: \"%s\", l: %ld, u: %4.4lX:%4.4lX, #e: %ld, #f: %ld, #i: %ld, #o: %ld, " \
683 "#c: %ld, #a: %ld, #b: %ld, #h: %ld, #s: %ld, #d: %ld, #w: %ld}.",
684 pNewDevice->transport,
685 pNewDevice->vendorID,
686 pNewDevice->productID,
687 pNewDevice->version,
688 pNewDevice->manufacturer,
689 pNewDevice->product,
690 pNewDevice->locID,
691 pNewDevice->usagePage,
692 pNewDevice->usage,
693 pNewDevice->totalElements,
694 pNewDevice->features,
695 pNewDevice->inputs,
696 pNewDevice->outputs,
697 pNewDevice->collections,
698 pNewDevice->axis,
699 pNewDevice->buttons,
700 pNewDevice->hats,
701 pNewDevice->sliders,
702 pNewDevice->dials,
703 pNewDevice->wheels
705 fflush(stdout);
706 #elif 0 // otherwise output brief description
707 printf("\nhid_AddDevices: pNewDevice = {m: \"%s\" p: \"%s\", vid: %ld, pid: %ld, loc: %8.8lX, usage: %4.4lX:%4.4lX}.",
708 pNewDevice->manufacturer,
709 pNewDevice->product,
710 pNewDevice->vendorID,
711 pNewDevice->productID,
712 pNewDevice->locID,
713 pNewDevice->usagePage,
714 pNewDevice->usage
716 fflush(stdout);
717 #endif
718 pNewDeviceAt = hid_AddDevice (pListDeviceHead, pNewDevice);
721 #if USE_NOTIFICATIONS
722 // Register for an interest notification of this device being removed. Use a reference to our
723 // private data as the refCon which will be passed to the notification callback.
724 result = IOServiceAddInterestNotification( gNotifyPort, // notifyPort
725 ioHIDDeviceObject, // service
726 kIOGeneralInterest, // interestType
727 hid_DeviceNotification, // callback
728 pNewDevice, // refCon
729 (io_object_t*) &pNewDevice->notification); // notification
730 if (KERN_SUCCESS != result)
731 HIDReportErrorNum ("hid_AddDevices: IOServiceAddInterestNotification error: x0%8.8lX.", result);
732 #else
733 result = (*(IOHIDDeviceInterface**)pNewDevice->interface)->setRemovalCallback (pNewDevice->interface, hid_RemovalCallbackFunction,pNewDeviceAt,0);
734 #endif USE_NOTIFICATIONS
736 // release the device object, it is no longer needed
737 result = IOObjectRelease (ioHIDDeviceObject);
738 if (KERN_SUCCESS != result)
739 HIDReportErrorNum ("hid_AddDevices: IOObjectRelease error with ioHIDDeviceObject.", result);
743 // ---------------------------------
744 // disposes of the element list associated with a device and the memory associated with the list
745 // uses depthwise recursion to dispose both collections and elements.
747 static void hid_DisposeDeviceElements (pRecElement pElement)
749 if (pElement)
751 if (pElement->pChild)
752 hid_DisposeDeviceElements (pElement->pChild);
753 if (pElement->pSibling)
754 hid_DisposeDeviceElements (pElement->pSibling);
755 free (pElement);
759 // ---------------------------------
760 // disposes of a single device, closing and releaseing interface, freeing memory fro device and elements, setting device pointer to NULL
761 // all your device no longer belong to us... (i.e., you do not 'own' the device anymore)
763 static pRecDevice hid_DisposeDevice (pRecDevice pDevice)
765 kern_return_t result = KERN_SUCCESS;
766 pRecDevice pDeviceNext = NULL;
768 if (HIDIsValidDevice(pDevice))
770 // save next device prior to disposing of this device
771 pDeviceNext = pDevice->pNext;
773 result = HIDDequeueDevice (pDevice);
774 #if 0
775 if (kIOReturnSuccess != result)
776 HIDReportErrorNum ("hid_DisposeDevice: HIDDequeueDevice error: 0x%8.8X.", result);
777 #endif 1
779 hid_DisposeDeviceElements (pDevice->pListElements);
780 pDevice->pListElements = NULL;
782 result = HIDCloseReleaseInterface (pDevice); // function sanity checks interface value (now application does not own device)
783 if (kIOReturnSuccess != result)
784 HIDReportErrorNum ("hid_DisposeDevice: HIDCloseReleaseInterface error: 0x%8.8X.", result);
786 #if USE_NOTIFICATIONS
787 if (pDevice->interface)
789 // replace (*pDevice->interface)->Release(pDevice->interface);
790 result = IODestroyPlugInInterface (pDevice->interface);
791 if (kIOReturnSuccess != result)
792 HIDReportErrorNum ("hid_DisposeDevice: IODestroyPlugInInterface error: 0x%8.8X.", result);
795 if (pDevice->notification)
797 result = IOObjectRelease((io_object_t) pDevice->notification);
798 if (kIOReturnSuccess != result)
799 HIDReportErrorNum ("hid_DisposeDevice: IOObjectRelease error: 0x%8.8X.", result);
801 #endif USE_NOTIFICATIONS
803 // remove this device from the device list
804 if (gpDeviceList == pDevice) // head of list?
805 gpDeviceList = pDeviceNext;
806 else
808 pRecDevice pDeviceTemp = pDeviceNext = gpDeviceList; // we're going to return this if we don't find ourselfs in the list
809 while (pDeviceTemp)
811 if (pDeviceTemp->pNext == pDevice) // found us!
813 // take us out of linked list
814 pDeviceTemp->pNext = pDeviceNext = pDevice->pNext;
815 break;
817 pDeviceTemp = pDeviceTemp->pNext;
820 free (pDevice);
823 // update device count
824 gNumDevices = hid_CountCurrentDevices ();
826 return pDeviceNext;
829 // ---------------------------------
830 // count number of devices in global device list (gpDeviceList)
831 static UInt32 hid_CountCurrentDevices (void)
833 pRecDevice pDevice = gpDeviceList;
834 UInt32 devices = 0;
835 while (pDevice)
837 devices++;
838 pDevice = pDevice->pNext;
840 return devices;
843 // ---------------------------------
844 // matches type masks passed in to actual element types (which are not set up to be used as a mask
845 static Boolean hid_MatchElementTypeMask (IOHIDElementType type, HIDElementTypeMask typeMask)
847 if (typeMask & kHIDElementTypeInput)
848 if ((type == kIOHIDElementTypeInput_Misc) || (type == kIOHIDElementTypeInput_Button) || (type == kIOHIDElementTypeInput_Axis) || (type == kIOHIDElementTypeInput_ScanCodes))
849 return true;
850 if (typeMask & kHIDElementTypeOutput)
851 if (type == kIOHIDElementTypeOutput)
852 return true;
853 if (typeMask & kHIDElementTypeFeature)
854 if (type == kIOHIDElementTypeFeature)
855 return true;
856 if (typeMask & kHIDElementTypeCollection)
857 if (type == kIOHIDElementTypeCollection)
858 return true;
859 return false;
862 // ---------------------------------
864 static pRecElement hid_GetDeviceElement (pRecElement pElement, HIDElementTypeMask typeMask)
866 // we are asking for this element
867 if (NULL != pElement)
869 if (hid_MatchElementTypeMask (pElement->type, typeMask)) // if the type match what we are looking for
870 return pElement; // return the element
871 else
872 return HIDGetNextDeviceElement (pElement, typeMask); // else get the next one
874 return NULL;
877 #define FAKE_IT 0 // set true for debugging; returns the usage & usage page as numbers
879 // ---------------------------------
880 // Load the usage strings from the <HID_usage_strings.plist> resource (XML) file into a CFPropertyListRef
881 static CFPropertyListRef xml_load_usage_strings(void)
883 CFPropertyListRef tCFPropertyListRef = NULL;
884 CFURLRef resFileCFURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("HID_usage_strings"), CFSTR("plist"), NULL);
886 if (NULL != resFileCFURLRef)
888 CFDataRef resCFDataRef;
890 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, resFileCFURLRef, &resCFDataRef, nil, nil, nil))
892 if (NULL != resCFDataRef)
894 CFStringRef errorString;
896 tCFPropertyListRef = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, resCFDataRef, kCFPropertyListImmutable, &errorString);
897 if (NULL == tCFPropertyListRef)
898 CFShow(errorString);
899 CFRelease(resCFDataRef);
902 CFRelease(resFileCFURLRef);
904 return tCFPropertyListRef;
907 // ---------------------------------
908 // Find a usage string in the <HID_usage_strings.plist> resource (XML) file
910 static Boolean xml_GetUsageName(const long valueUsagePage, const long valueUsage, char* pCstr)
912 static CFPropertyListRef tCFPropertyListRef = NULL;
913 Boolean results = false;
915 if (NULL == tCFPropertyListRef)
916 tCFPropertyListRef = xml_load_usage_strings();
917 if (NULL != tCFPropertyListRef)
919 if (CFDictionaryGetTypeID() == CFGetTypeID(tCFPropertyListRef))
921 CFDictionaryRef pageCFDictionaryRef;
922 CFStringRef pageKeyCFStringRef;
923 pageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%4.4lX"), valueUsagePage);
925 if (CFDictionaryGetValueIfPresent(tCFPropertyListRef, pageKeyCFStringRef, (const void**) &pageCFDictionaryRef))
927 CFStringRef pageCFStringRef;
929 if (CFDictionaryGetValueIfPresent(pageCFDictionaryRef, CFSTR("Name"), (const void**) &pageCFStringRef))
931 //CFShow(pageCFStringRef);
935 CFStringRef fullCFStringRef = NULL;
936 CFStringRef usageKeyCFStringRef;
937 CFStringRef usageCFStringRef;
939 usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%4.4lX"), valueUsage);
941 if (CFDictionaryGetValueIfPresent(pageCFDictionaryRef, usageKeyCFStringRef, (const void**) &usageCFStringRef))
943 fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@"),
944 pageCFStringRef, usageCFStringRef);
945 // CFShow(usageCFStringRef);
947 #if FAKE_IT
948 else
950 fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ #%@"),
951 pageCFStringRef, usageKeyCFStringRef);
953 #endif
954 if (fullCFStringRef)
956 // CFShow(fullCFStringRef);
957 results = CFStringGetCString(
958 fullCFStringRef, pCstr, CFStringGetLength(fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingMacRoman);
959 CFRelease(fullCFStringRef);
961 CFRelease(usageKeyCFStringRef);
964 CFRelease(pageKeyCFStringRef);
966 //++CFRelease(tCFPropertyListRef); // Leak this!
968 return results;
971 #pragma mark public functions
972 // =================================
973 // public functions
975 // ---------------------------------
976 // Create and open an interface to device, required prior to extracting values or building queues
977 // Note: appliction now owns the device and must close and release it prior to exiting
979 unsigned long HIDCreateOpenDeviceInterface (UInt32 hidDevice, pRecDevice pDevice)
981 IOReturn result = kIOReturnSuccess;
982 HRESULT plugInResult = S_OK;
983 SInt32 score = 0;
984 IOCFPlugInInterface ** ppPlugInInterface = NULL;
986 if (NULL == pDevice->interface)
988 result = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID,
989 kIOCFPlugInInterfaceID, &ppPlugInInterface, &score);
990 if (kIOReturnSuccess == result)
992 // Call a method of the intermediate plug-in to create the device interface
993 plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface,
994 CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &(pDevice->interface));
995 if (S_OK != plugInResult)
996 HIDReportErrorNum ("CouldnÕt query HID class device interface from plugInInterface", plugInResult);
997 IODestroyPlugInInterface (ppPlugInInterface); // replace (*ppPlugInInterface)->Release (ppPlugInInterface)
999 else
1000 HIDReportErrorNum ("Failed to create **plugInInterface via IOCreatePlugInInterfaceForService.", result);
1002 if (NULL != pDevice->interface)
1004 result = (*(IOHIDDeviceInterface**)pDevice->interface)->open (pDevice->interface, 0);
1005 if (kIOReturnSuccess != result)
1006 HIDReportErrorNum ("Failed to open pDevice->interface via open.", result);
1008 return result;
1011 // ---------------------------------
1012 // builds list of device with elements (allocates memory and captures devices)
1013 // list is allcoated internally within HID Utilites and can be accessed via accessor functions
1014 // structures within list are considered flat and user accessable, but not user modifiable
1015 // can be called again to rebuild list to account for new devices (will do the right thing in case of disposing existing list)
1016 // returns true if succesful
1018 Boolean HIDBuildDeviceList (UInt32 usagePage, UInt32 usage)
1020 IOReturn result = kIOReturnSuccess;
1021 mach_port_t masterPort = 0;
1023 if (NULL != gpDeviceList)
1024 HIDReleaseDeviceList ();
1026 result = IOMasterPort (bootstrap_port, &masterPort);
1027 if (kIOReturnSuccess != result)
1028 HIDReportErrorNum ("IOMasterPort error with bootstrap_port.", result);
1029 else
1031 CFMutableDictionaryRef hidMatchDictionary = NULL;
1033 // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error.
1035 CFNumberRef refUsage = NULL, refUsagePage = NULL;
1037 // Set up a matching dictionary to search I/O Registry by class name for all HID class devices.
1038 hidMatchDictionary = IOServiceMatching (kIOHIDDeviceKey);
1039 if (NULL != hidMatchDictionary)
1041 if (usagePage)
1043 // Add key for device type (joystick, in this case) to refine the matching dictionary.
1044 refUsagePage = CFNumberCreate (kCFAllocatorDefault, kCFNumberLongType, &usagePage);
1045 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsagePageKey), refUsagePage);
1046 CFRelease (refUsagePage);
1047 if (usage)
1049 refUsage = CFNumberCreate (kCFAllocatorDefault, kCFNumberLongType, &usage);
1050 CFDictionarySetValue (hidMatchDictionary, CFSTR (kIOHIDPrimaryUsageKey), refUsage);
1051 CFRelease (refUsage);
1054 CFRetain(hidMatchDictionary);
1056 else
1057 HIDReportError ("Failed to get HID CFMutableDictionaryRef via IOServiceMatching.");
1060 #if USE_NOTIFICATIONS
1061 // Create a notification port and add its run loop event source to our run loop
1062 // This is how async notifications get set up.
1064 CFRunLoopSourceRef runLoopSource;
1066 gNotifyPort = IONotificationPortCreate(masterPort);
1067 runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
1069 gRunLoop = CFRunLoopGetCurrent();
1070 CFRunLoopAddSource(gRunLoop, runLoopSource, kCFRunLoopDefaultMode);
1072 // Now set up a notification to be called when a device is first matched by I/O Kit.
1073 result = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
1074 kIOFirstMatchNotification, // notificationType
1075 hidMatchDictionary, // matching
1076 hid_AddDevices, // callback
1077 &gpDeviceList, // refCon
1078 &gAddedIter // notification
1081 // call it now to add all existing devices
1082 hid_AddDevices(&gpDeviceList,gAddedIter);
1084 #else
1086 io_iterator_t hidObjectIterator = NULL;
1088 // Now search I/O Registry for matching devices.
1089 result = IOServiceGetMatchingServices (masterPort, hidMatchDictionary, &hidObjectIterator);
1090 if (kIOReturnSuccess != result)
1091 HIDReportErrorNum ("Failed to create IO object iterator, error:", result);
1092 else if (NULL == hidObjectIterator) // likely no HID devices which matched selection criteria are connected
1093 HIDReportError ("Warning: Could not find any matching devices, thus iterator creation failed.");
1095 if (NULL != hidObjectIterator)
1097 hid_AddDevices(&gpDeviceList,hidObjectIterator);
1099 result = IOObjectRelease (hidObjectIterator); // release the iterator
1100 if (kIOReturnSuccess != result)
1101 HIDReportErrorNum ("IOObjectRelease error with hidObjectIterator.", result);
1103 gNumDevices = hid_CountCurrentDevices ();
1104 return true;
1107 #endif USE_NOTIFICATIONS
1108 // IOServiceGetMatchingServices consumes a reference to the dictionary, so we don't need to release the dictionary ref.
1109 hidMatchDictionary = NULL;
1111 return false;
1114 // ---------------------------------
1115 // release list built by above function
1116 // MUST be called prior to application exit to properly release devices
1117 // if not called (or app crashes) devices can be recovered by pluging into different location in USB chain
1119 void HIDReleaseDeviceList (void)
1121 while (NULL != gpDeviceList)
1122 gpDeviceList = hid_DisposeDevice (gpDeviceList); // dispose current device return next device will set gpDeviceList to NULL
1123 gNumDevices = 0;
1126 // ---------------------------------
1127 // does a device list exist
1129 Boolean HIDHaveDeviceList (void)
1131 if (NULL != gpDeviceList)
1132 return true;
1133 return false;
1136 // ---------------------------------
1137 // how many HID devices have been found
1138 // returns 0 if no device list exist
1140 UInt32 HIDCountDevices (void)
1142 gNumDevices = hid_CountCurrentDevices ();
1144 return gNumDevices;
1147 // ---------------------------------
1148 // how many elements does a specific device have
1149 // returns 0 if device is invlaid or NULL
1151 UInt32 HIDCountDeviceElements (pRecDevice pDevice, HIDElementTypeMask typeMask)
1153 long count = 0;
1154 if (HIDIsValidDevice(pDevice))
1156 if (typeMask & kHIDElementTypeInput)
1157 count += pDevice->inputs;
1158 if (typeMask & kHIDElementTypeOutput)
1159 count += pDevice->outputs;
1160 if (typeMask & kHIDElementTypeFeature)
1161 count += pDevice->features;
1162 if (typeMask & kHIDElementTypeCollection)
1163 count += pDevice->collections;
1165 return count;
1168 // ---------------------------------
1169 // get the first device in the device list
1170 // returns NULL if no list exists
1172 pRecDevice HIDGetFirstDevice (void)
1174 return gpDeviceList;
1177 // ---------------------------------
1178 // get next device in list given current device as parameter
1179 // returns NULL if end of list
1181 pRecDevice HIDGetNextDevice (pRecDevice pDevice)
1183 if (NULL != pDevice)
1184 return pDevice->pNext;
1185 else
1186 return NULL;
1189 // ---------------------------------
1190 // get the first element of device passed in as parameter
1191 // returns NULL if no list exists or device does not exists or is NULL
1192 pRecElement HIDGetFirstDeviceElement (pRecDevice pDevice, HIDElementTypeMask typeMask)
1194 if (HIDIsValidDevice(pDevice))
1196 if (hid_MatchElementTypeMask (pDevice->pListElements->type, typeMask)) // ensure first type matches
1197 return pDevice->pListElements;
1198 else
1199 return HIDGetNextDeviceElement (pDevice->pListElements, typeMask);
1201 else
1202 return NULL;
1205 // ---------------------------------
1206 // get next element of given device in list given current element as parameter
1207 // will walk down each collection then to next element or collection (depthwise traverse)
1208 // returns NULL if end of list
1209 // uses mask of HIDElementTypeMask to restrict element found
1210 // use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality
1211 pRecElement HIDGetNextDeviceElement (pRecElement pElement, HIDElementTypeMask typeMask)
1213 // should only have elements passed in (though someone could mix calls and pass us a collection)
1214 // collection means return the next child or sibling (in that order)
1215 // element means returnt he next sibling (as elements can't have children
1216 if (NULL != pElement)
1218 if (pElement->pChild)
1220 if (pElement->type != kIOHIDElementTypeCollection)
1221 HIDReportError ("Malformed element list: found child of element.");
1222 else
1223 return hid_GetDeviceElement (pElement->pChild, typeMask); // return the child of this element
1225 else if (pElement->pSibling)
1227 return hid_GetDeviceElement (pElement->pSibling, typeMask); //return the sibling of this element
1229 else // at end back up correctly
1231 pRecElement pPreviousElement = NULL;
1232 // malformed device ending in collection
1233 if (pElement->type == kIOHIDElementTypeCollection)
1234 HIDReportError ("Malformed device: found collection at end of element chain.");
1235 // walk back up tree to element prior to first collection ecountered and take next element
1236 while (NULL != pElement->pPrevious)
1238 pPreviousElement = pElement;
1239 pElement = pElement->pPrevious; // look at previous element
1240 // if we have a collection and the previous element is the branch element (should have both a colection and next element attached to it)
1241 // if we found a collection, which we are not at the sibling level that actually does have siblings
1242 if (((pElement->type == kIOHIDElementTypeCollection) && (pPreviousElement != pElement->pSibling) && pElement->pSibling) ||
1243 // or if we are at the top
1244 (NULL == pElement->pPrevious)) // at top of tree
1245 break;
1247 if (NULL == pElement->pPrevious)
1248 return NULL; // got to top of list with only a collection as the first element
1249 // now we must have been down the child route so go down the sibling route
1250 pElement = pElement->pSibling; // element of interest
1251 return hid_GetDeviceElement (pElement, typeMask); // otherwise return this element
1254 return NULL;
1257 // ---------------------------------
1258 // get previous element of given device in list given current element as parameter
1259 // this wlaks directly up the tree to the top element and does not search at each level
1260 // returns NULL if beginning of list
1261 // uses mask of HIDElementTypeMask to restrict element found
1262 // use kHIDElementTypeIO to get non-collection elements
1263 pRecElement HIDGetPreviousDeviceElement (pRecElement pElement, HIDElementTypeMask typeMask)
1265 pRecElement pPreviousElement = pElement->pPrevious;
1266 // walk back up tree to element prior
1267 while (pPreviousElement && !hid_MatchElementTypeMask (pPreviousElement->type, typeMask))
1269 pElement = pPreviousElement; // look at previous element
1270 pPreviousElement = pElement->pPrevious;
1272 return pPreviousElement; // return this element
1275 // ---------------------------------
1276 // returns C string type name given a type enumeration passed in as parameter (see IOHIDKeys.h)
1277 // returns "Unknown Type" for invalid types
1279 void HIDGetTypeName (IOHIDElementType theType, char * cstrName)
1281 switch (theType)
1283 case kIOHIDElementTypeInput_Misc:
1284 sprintf(cstrName, "Miscellaneous Input");
1285 break;
1286 case kIOHIDElementTypeInput_Button:
1287 sprintf(cstrName, "Button Input");
1288 break;
1289 case kIOHIDElementTypeInput_Axis:
1290 sprintf(cstrName, "Axis Input");
1291 break;
1292 case kIOHIDElementTypeInput_ScanCodes:
1293 sprintf(cstrName, "Scan Code Input");
1294 break;
1295 case kIOHIDElementTypeOutput:
1296 sprintf(cstrName, "Output");
1297 break;
1298 case kIOHIDElementTypeFeature:
1299 sprintf(cstrName, "Feature");
1300 break;
1301 case kIOHIDElementTypeCollection:
1302 sprintf(cstrName, "Collection");
1303 break;
1304 default:
1305 sprintf(cstrName, "Unknown Type");
1306 break;
1310 // ---------------------------------
1311 // returns C string usage given usage page and usage passed in as parameters (see IOUSBHIDParser.h)
1312 // returns usage page and usage values in string form for unknown values
1314 void HIDGetUsageName (const long valueUsagePage, const long valueUsage, char * cstrName)
1316 if (xml_GetUsageName(valueUsagePage, valueUsage, cstrName))
1317 return;
1319 switch (valueUsagePage)
1321 case kHIDPage_Undefined:
1322 switch (valueUsage)
1324 default: sprintf (cstrName, "Undefined Page, Usage 0x%lx", valueUsage); break;
1326 break;
1327 case kHIDPage_GenericDesktop:
1328 switch (valueUsage)
1330 case kHIDUsage_GD_Pointer: sprintf (cstrName, "Pointer"); break;
1331 case kHIDUsage_GD_Mouse: sprintf (cstrName, "Mouse"); break;
1332 case kHIDUsage_GD_Joystick: sprintf (cstrName, "Joystick"); break;
1333 case kHIDUsage_GD_GamePad: sprintf (cstrName, "GamePad"); break;
1334 case kHIDUsage_GD_Keyboard: sprintf (cstrName, "Keyboard"); break;
1335 case kHIDUsage_GD_Keypad: sprintf (cstrName, "Keypad"); break;
1336 case kHIDUsage_GD_MultiAxisController: sprintf (cstrName, "Multi-Axis Controller"); break;
1338 case kHIDUsage_GD_X: sprintf (cstrName, "X-Axis"); break;
1339 case kHIDUsage_GD_Y: sprintf (cstrName, "Y-Axis"); break;
1340 case kHIDUsage_GD_Z: sprintf (cstrName, "Z-Axis"); break;
1341 case kHIDUsage_GD_Rx: sprintf (cstrName, "X-Rotation"); break;
1342 case kHIDUsage_GD_Ry: sprintf (cstrName, "Y-Rotation"); break;
1343 case kHIDUsage_GD_Rz: sprintf (cstrName, "Z-Rotation"); break;
1344 case kHIDUsage_GD_Slider: sprintf (cstrName, "Slider"); break;
1345 case kHIDUsage_GD_Dial: sprintf (cstrName, "Dial"); break;
1346 case kHIDUsage_GD_Wheel: sprintf (cstrName, "Wheel"); break;
1347 case kHIDUsage_GD_Hatswitch: sprintf (cstrName, "Hatswitch"); break;
1348 case kHIDUsage_GD_CountedBuffer: sprintf (cstrName, "Counted Buffer"); break;
1349 case kHIDUsage_GD_ByteCount: sprintf (cstrName, "Byte Count"); break;
1350 case kHIDUsage_GD_MotionWakeup: sprintf (cstrName, "Motion Wakeup"); break;
1351 case kHIDUsage_GD_Start: sprintf (cstrName, "Start"); break;
1352 case kHIDUsage_GD_Select: sprintf (cstrName, "Select"); break;
1354 case kHIDUsage_GD_Vx: sprintf (cstrName, "X-Velocity"); break;
1355 case kHIDUsage_GD_Vy: sprintf (cstrName, "Y-Velocity"); break;
1356 case kHIDUsage_GD_Vz: sprintf (cstrName, "Z-Velocity"); break;
1357 case kHIDUsage_GD_Vbrx: sprintf (cstrName, "X-Rotation Velocity"); break;
1358 case kHIDUsage_GD_Vbry: sprintf (cstrName, "Y-Rotation Velocity"); break;
1359 case kHIDUsage_GD_Vbrz: sprintf (cstrName, "Z-Rotation Velocity"); break;
1360 case kHIDUsage_GD_Vno: sprintf (cstrName, "Vno"); break;
1362 case kHIDUsage_GD_SystemControl: sprintf (cstrName, "System Control"); break;
1363 case kHIDUsage_GD_SystemPowerDown: sprintf (cstrName, "System Power Down"); break;
1364 case kHIDUsage_GD_SystemSleep: sprintf (cstrName, "System Sleep"); break;
1365 case kHIDUsage_GD_SystemWakeUp: sprintf (cstrName, "System Wake Up"); break;
1366 case kHIDUsage_GD_SystemContextMenu: sprintf (cstrName, "System Context Menu"); break;
1367 case kHIDUsage_GD_SystemMainMenu: sprintf (cstrName, "System Main Menu"); break;
1368 case kHIDUsage_GD_SystemAppMenu: sprintf (cstrName, "System App Menu"); break;
1369 case kHIDUsage_GD_SystemMenuHelp: sprintf (cstrName, "System Menu Help"); break;
1370 case kHIDUsage_GD_SystemMenuExit: sprintf (cstrName, "System Menu Exit"); break;
1371 case kHIDUsage_GD_SystemMenu: sprintf (cstrName, "System Menu"); break;
1372 case kHIDUsage_GD_SystemMenuRight: sprintf (cstrName, "System Menu Right"); break;
1373 case kHIDUsage_GD_SystemMenuLeft: sprintf (cstrName, "System Menu Left"); break;
1374 case kHIDUsage_GD_SystemMenuUp: sprintf (cstrName, "System Menu Up"); break;
1375 case kHIDUsage_GD_SystemMenuDown: sprintf (cstrName, "System Menu Down"); break;
1377 case kHIDUsage_GD_DPadUp: sprintf (cstrName, "DPad Up"); break;
1378 case kHIDUsage_GD_DPadDown: sprintf (cstrName, "DPad Down"); break;
1379 case kHIDUsage_GD_DPadRight: sprintf (cstrName, "DPad Right"); break;
1380 case kHIDUsage_GD_DPadLeft: sprintf (cstrName, "DPad Left"); break;
1382 case kHIDUsage_GD_Reserved: sprintf (cstrName, "Reserved"); break;
1384 default: sprintf (cstrName, "Generic Desktop Usage 0x%lx", valueUsage); break;
1386 break;
1387 case kHIDPage_Simulation:
1388 switch (valueUsage)
1390 default: sprintf (cstrName, "Simulation Usage 0x%lx", valueUsage); break;
1392 break;
1393 case kHIDPage_VR:
1394 switch (valueUsage)
1396 default: sprintf (cstrName, "VR Usage 0x%lx", valueUsage); break;
1398 break;
1399 case kHIDPage_Sport:
1400 switch (valueUsage)
1402 default: sprintf (cstrName, "Sport Usage 0x%lx", valueUsage); break;
1404 break;
1405 case kHIDPage_Game:
1406 switch (valueUsage)
1408 default: sprintf (cstrName, "Game Usage 0x%lx", valueUsage); break;
1410 break;
1411 case kHIDPage_KeyboardOrKeypad:
1412 switch (valueUsage)
1414 default: sprintf (cstrName, "Keyboard Usage 0x%lx", valueUsage); break;
1416 break;
1417 case kHIDPage_LEDs:
1418 switch (valueUsage)
1420 // some LED usages
1421 case kHIDUsage_LED_IndicatorRed: sprintf (cstrName, "Red LED"); break;
1422 case kHIDUsage_LED_IndicatorGreen: sprintf (cstrName, "Green LED"); break;
1423 case kHIDUsage_LED_IndicatorAmber: sprintf (cstrName, "Amber LED"); break;
1424 case kHIDUsage_LED_GenericIndicator: sprintf (cstrName, "Generic LED"); break;
1425 case kHIDUsage_LED_SystemSuspend: sprintf (cstrName, "System Suspend LED"); break;
1426 case kHIDUsage_LED_ExternalPowerConnected: sprintf (cstrName, "External Power LED"); break;
1427 default: sprintf (cstrName, "LED Usage 0x%lx", valueUsage); break;
1429 break;
1430 case kHIDPage_Button:
1431 switch (valueUsage)
1433 default: sprintf (cstrName, "Button #%ld", valueUsage); break;
1435 break;
1436 case kHIDPage_Ordinal:
1437 switch (valueUsage)
1439 default: sprintf (cstrName, "Ordinal Instance %lx", valueUsage); break;
1441 break;
1442 case kHIDPage_Telephony:
1443 switch (valueUsage)
1445 default: sprintf (cstrName, "Telephony Usage 0x%lx", valueUsage); break;
1447 break;
1448 case kHIDPage_Consumer:
1449 switch (valueUsage)
1451 default: sprintf (cstrName, "Consumer Usage 0x%lx", valueUsage); break;
1453 break;
1454 case kHIDPage_Digitizer:
1455 switch (valueUsage)
1457 default: sprintf (cstrName, "Digitizer Usage 0x%lx", valueUsage); break;
1459 break;
1460 case kHIDPage_PID:
1461 if (((valueUsage >= 0x02) && (valueUsage <= 0x1F)) || ((valueUsage >= 0x29) && (valueUsage <= 0x2F)) ||
1462 ((valueUsage >= 0x35) && (valueUsage <= 0x3F)) || ((valueUsage >= 0x44) && (valueUsage <= 0x4F)) ||
1463 (valueUsage == 0x8A) || (valueUsage == 0x93) || ((valueUsage >= 0x9D) && (valueUsage <= 0x9E)) ||
1464 ((valueUsage >= 0xA1) && (valueUsage <= 0xA3)) || ((valueUsage >= 0xAD) && (valueUsage <= 0xFFFF)))
1465 sprintf (cstrName, "PID Reserved");
1466 else
1467 switch (valueUsage)
1469 case 0x00: sprintf (cstrName, "PID Undefined Usage"); break;
1470 case kHIDUsage_PID_PhysicalInterfaceDevice: sprintf (cstrName, "Physical Interface Device"); break;
1471 case kHIDUsage_PID_Normal: sprintf (cstrName, "Normal Force"); break;
1473 case kHIDUsage_PID_SetEffectReport: sprintf (cstrName, "Set Effect Report"); break;
1474 case kHIDUsage_PID_EffectBlockIndex: sprintf (cstrName, "Effect Block Index"); break;
1475 case kHIDUsage_PID_ParamBlockOffset: sprintf (cstrName, "Parameter Block Offset"); break;
1476 case kHIDUsage_PID_ROM_Flag: sprintf (cstrName, "ROM Flag"); break;
1478 case kHIDUsage_PID_EffectType: sprintf (cstrName, "Effect Type"); break;
1479 case kHIDUsage_PID_ET_ConstantForce: sprintf (cstrName, "Effect Type Constant Force"); break;
1480 case kHIDUsage_PID_ET_Ramp: sprintf (cstrName, "Effect Type Ramp"); break;
1481 case kHIDUsage_PID_ET_CustomForceData: sprintf (cstrName, "Effect Type Custom Force Data"); break;
1482 case kHIDUsage_PID_ET_Square: sprintf (cstrName, "Effect Type Square"); break;
1483 case kHIDUsage_PID_ET_Sine: sprintf (cstrName, "Effect Type Sine"); break;
1484 case kHIDUsage_PID_ET_Triangle: sprintf (cstrName, "Effect Type Triangle"); break;
1485 case kHIDUsage_PID_ET_SawtoothUp: sprintf (cstrName, "Effect Type Sawtooth Up"); break;
1486 case kHIDUsage_PID_ET_SawtoothDown: sprintf (cstrName, "Effect Type Sawtooth Down"); break;
1487 case kHIDUsage_PID_ET_Spring: sprintf (cstrName, "Effect Type Spring"); break;
1488 case kHIDUsage_PID_ET_Damper: sprintf (cstrName, "Effect Type Damper"); break;
1489 case kHIDUsage_PID_ET_Inertia: sprintf (cstrName, "Effect Type Inertia"); break;
1490 case kHIDUsage_PID_ET_Friction: sprintf (cstrName, "Effect Type Friction"); break;
1491 case kHIDUsage_PID_Duration: sprintf (cstrName, "Effect Duration"); break;
1492 case kHIDUsage_PID_SamplePeriod: sprintf (cstrName, "Effect Sample Period"); break;
1493 case kHIDUsage_PID_Gain: sprintf (cstrName, "Effect Gain"); break;
1494 case kHIDUsage_PID_TriggerButton: sprintf (cstrName, "Effect Trigger Button"); break;
1495 case kHIDUsage_PID_TriggerRepeatInterval: sprintf (cstrName, "Effect Trigger Repeat Interval"); break;
1497 case kHIDUsage_PID_AxesEnable: sprintf (cstrName, "Axis Enable"); break;
1498 case kHIDUsage_PID_DirectionEnable: sprintf (cstrName, "Direction Enable"); break;
1500 case kHIDUsage_PID_Direction: sprintf (cstrName, "Direction"); break;
1502 case kHIDUsage_PID_TypeSpecificBlockOffset: sprintf (cstrName, "Type Specific Block Offset"); break;
1504 case kHIDUsage_PID_BlockType: sprintf (cstrName, "Block Type"); break;
1506 case kHIDUsage_PID_SetEnvelopeReport: sprintf (cstrName, "Set Envelope Report"); break;
1507 case kHIDUsage_PID_AttackLevel: sprintf (cstrName, "Envelope Attack Level"); break;
1508 case kHIDUsage_PID_AttackTime: sprintf (cstrName, "Envelope Attack Time"); break;
1509 case kHIDUsage_PID_FadeLevel: sprintf (cstrName, "Envelope Fade Level"); break;
1510 case kHIDUsage_PID_FadeTime: sprintf (cstrName, "Envelope Fade Time"); break;
1512 case kHIDUsage_PID_SetConditionReport: sprintf (cstrName, "Set Condition Report"); break;
1513 case kHIDUsage_PID_CP_Offset: sprintf (cstrName, "Condition CP Offset"); break;
1514 case kHIDUsage_PID_PositiveCoefficient: sprintf (cstrName, "Condition Positive Coefficient"); break;
1515 case kHIDUsage_PID_NegativeCoefficient: sprintf (cstrName, "Condition Negative Coefficient"); break;
1516 case kHIDUsage_PID_PositiveSaturation: sprintf (cstrName, "Condition Positive Saturation"); break;
1517 case kHIDUsage_PID_NegativeSaturation: sprintf (cstrName, "Condition Negative Saturation"); break;
1518 case kHIDUsage_PID_DeadBand: sprintf (cstrName, "Condition Dead Band"); break;
1520 case kHIDUsage_PID_DownloadForceSample: sprintf (cstrName, "Download Force Sample"); break;
1521 case kHIDUsage_PID_IsochCustomForceEnable: sprintf (cstrName, "Isoch Custom Force Enable"); break;
1523 case kHIDUsage_PID_CustomForceDataReport: sprintf (cstrName, "Custom Force Data Report"); break;
1524 case kHIDUsage_PID_CustomForceData: sprintf (cstrName, "Custom Force Data"); break;
1526 case kHIDUsage_PID_CustomForceVendorDefinedData: sprintf (cstrName, "Custom Force Vendor Defined Data"); break;
1527 case kHIDUsage_PID_SetCustomForceReport: sprintf (cstrName, "Set Custom Force Report"); break;
1528 case kHIDUsage_PID_CustomForceDataOffset: sprintf (cstrName, "Custom Force Data Offset"); break;
1529 case kHIDUsage_PID_SampleCount: sprintf (cstrName, "Custom Force Sample Count"); break;
1531 case kHIDUsage_PID_SetPeriodicReport: sprintf (cstrName, "Set Periodic Report"); break;
1532 case kHIDUsage_PID_Offset: sprintf (cstrName, "Periodic Offset"); break;
1533 case kHIDUsage_PID_Magnitude: sprintf (cstrName, "Periodic Magnitude"); break;
1534 case kHIDUsage_PID_Phase: sprintf (cstrName, "Periodic Phase"); break;
1535 case kHIDUsage_PID_Period: sprintf (cstrName, "Periodic Period"); break;
1537 case kHIDUsage_PID_SetConstantForceReport: sprintf (cstrName, "Set Constant Force Report"); break;
1539 case kHIDUsage_PID_SetRampForceReport: sprintf (cstrName, "Set Ramp Force Report"); break;
1540 case kHIDUsage_PID_RampStart: sprintf (cstrName, "Ramp Start"); break;
1541 case kHIDUsage_PID_RampEnd: sprintf (cstrName, "Ramp End"); break;
1543 case kHIDUsage_PID_EffectOperationReport: sprintf (cstrName, "Effect Operation Report"); break;
1545 case kHIDUsage_PID_EffectOperation: sprintf (cstrName, "Effect Operation"); break;
1546 case kHIDUsage_PID_OpEffectStart: sprintf (cstrName, "Op Effect Start"); break;
1547 case kHIDUsage_PID_OpEffectStartSolo: sprintf (cstrName, "Op Effect Start Solo"); break;
1548 case kHIDUsage_PID_OpEffectStop: sprintf (cstrName, "Op Effect Stop"); break;
1549 case kHIDUsage_PID_LoopCount: sprintf (cstrName, "Op Effect Loop Count"); break;
1551 case kHIDUsage_PID_DeviceGainReport: sprintf (cstrName, "Device Gain Report"); break;
1552 case kHIDUsage_PID_DeviceGain: sprintf (cstrName, "Device Gain"); break;
1554 case kHIDUsage_PID_PoolReport: sprintf (cstrName, "PID Pool Report"); break;
1555 case kHIDUsage_PID_RAM_PoolSize: sprintf (cstrName, "RAM Pool Size"); break;
1556 case kHIDUsage_PID_ROM_PoolSize: sprintf (cstrName, "ROM Pool Size"); break;
1557 case kHIDUsage_PID_ROM_EffectBlockCount: sprintf (cstrName, "ROM Effect Block Count"); break;
1558 case kHIDUsage_PID_SimultaneousEffectsMax: sprintf (cstrName, "Simultaneous Effects Max"); break;
1559 case kHIDUsage_PID_PoolAlignment: sprintf (cstrName, "Pool Alignment"); break;
1561 case kHIDUsage_PID_PoolMoveReport: sprintf (cstrName, "PID Pool Move Report"); break;
1562 case kHIDUsage_PID_MoveSource: sprintf (cstrName, "Move Source"); break;
1563 case kHIDUsage_PID_MoveDestination: sprintf (cstrName, "Move Destination"); break;
1564 case kHIDUsage_PID_MoveLength: sprintf (cstrName, "Move Length"); break;
1566 case kHIDUsage_PID_BlockLoadReport: sprintf (cstrName, "PID Block Load Report"); break;
1568 case kHIDUsage_PID_BlockLoadStatus: sprintf (cstrName, "Block Load Status"); break;
1569 case kHIDUsage_PID_BlockLoadSuccess: sprintf (cstrName, "Block Load Success"); break;
1570 case kHIDUsage_PID_BlockLoadFull: sprintf (cstrName, "Block Load Full"); break;
1571 case kHIDUsage_PID_BlockLoadError: sprintf (cstrName, "Block Load Error"); break;
1572 case kHIDUsage_PID_BlockHandle: sprintf (cstrName, "Block Handle"); break;
1574 case kHIDUsage_PID_BlockFreeReport: sprintf (cstrName, "PID Block Free Report"); break;
1576 case kHIDUsage_PID_TypeSpecificBlockHandle: sprintf (cstrName, "Type Specific Block Handle"); break;
1578 case kHIDUsage_PID_StateReport: sprintf (cstrName, "PID State Report"); break;
1579 case kHIDUsage_PID_EffectPlaying: sprintf (cstrName, "Effect Playing"); break;
1581 case kHIDUsage_PID_DeviceControlReport: sprintf (cstrName, "PID Device Control Report"); break;
1583 case kHIDUsage_PID_DeviceControl: sprintf (cstrName, "PID Device Control"); break;
1584 case kHIDUsage_PID_DC_EnableActuators: sprintf (cstrName, "Device Control Enable Actuators"); break;
1585 case kHIDUsage_PID_DC_DisableActuators: sprintf (cstrName, "Device Control Disable Actuators"); break;
1586 case kHIDUsage_PID_DC_StopAllEffects: sprintf (cstrName, "Device Control Stop All Effects"); break;
1587 case kHIDUsage_PID_DC_DeviceReset: sprintf (cstrName, "Device Control Reset"); break;
1588 case kHIDUsage_PID_DC_DevicePause: sprintf (cstrName, "Device Control Pause"); break;
1589 case kHIDUsage_PID_DC_DeviceContinue: sprintf (cstrName, "Device Control Continue"); break;
1590 case kHIDUsage_PID_DevicePaused: sprintf (cstrName, "Device Paused"); break;
1591 case kHIDUsage_PID_ActuatorsEnabled: sprintf (cstrName, "Actuators Enabled"); break;
1592 case kHIDUsage_PID_SafetySwitch: sprintf (cstrName, "Safety Switch"); break;
1593 case kHIDUsage_PID_ActuatorOverrideSwitch: sprintf (cstrName, "Actuator Override Switch"); break;
1594 case kHIDUsage_PID_ActuatorPower: sprintf (cstrName, "Actuator Power"); break;
1595 case kHIDUsage_PID_StartDelay: sprintf (cstrName, "Start Delay"); break;
1597 case kHIDUsage_PID_ParameterBlockSize: sprintf (cstrName, "Parameter Block Size"); break;
1598 case kHIDUsage_PID_DeviceManagedPool: sprintf (cstrName, "Device Managed Pool"); break;
1599 case kHIDUsage_PID_SharedParameterBlocks: sprintf (cstrName, "Shared Parameter Blocks"); break;
1601 case kHIDUsage_PID_CreateNewEffectReport: sprintf (cstrName, "Create New Effect Report"); break;
1602 case kHIDUsage_PID_RAM_PoolAvailable: sprintf (cstrName, "RAM Pool Available"); break;
1603 default: sprintf (cstrName, "PID Usage 0x%lx", valueUsage); break;
1605 break;
1606 case kHIDPage_Unicode:
1607 switch (valueUsage)
1609 default: sprintf (cstrName, "Unicode Usage 0x%lx", valueUsage); break;
1611 break;
1612 case kHIDPage_PowerDevice:
1613 if (((valueUsage >= 0x06) && (valueUsage <= 0x0F)) || ((valueUsage >= 0x26) && (valueUsage <= 0x2F)) ||
1614 ((valueUsage >= 0x39) && (valueUsage <= 0x3F)) || ((valueUsage >= 0x48) && (valueUsage <= 0x4F)) ||
1615 ((valueUsage >= 0x58) && (valueUsage <= 0x5F)) || (valueUsage == 0x6A) ||
1616 ((valueUsage >= 0x74) && (valueUsage <= 0xFC)))
1617 sprintf (cstrName, "Power Device Reserved");
1618 else
1619 switch (valueUsage)
1621 case kHIDUsage_PD_Undefined: sprintf (cstrName, "Power Device Undefined Usage"); break;
1622 case kHIDUsage_PD_iName: sprintf (cstrName, "Power Device Name Index"); break;
1623 case kHIDUsage_PD_PresentStatus: sprintf (cstrName, "Power Device Present Status"); break;
1624 case kHIDUsage_PD_ChangedStatus: sprintf (cstrName, "Power Device Changed Status"); break;
1625 case kHIDUsage_PD_UPS: sprintf (cstrName, "Uninterruptible Power Supply"); break;
1626 case kHIDUsage_PD_PowerSupply: sprintf (cstrName, "Power Supply"); break;
1628 case kHIDUsage_PD_BatterySystem: sprintf (cstrName, "Battery System Power Module"); break;
1629 case kHIDUsage_PD_BatterySystemID: sprintf (cstrName, "Battery System ID"); break;
1630 case kHIDUsage_PD_Battery: sprintf (cstrName, "Battery"); break;
1631 case kHIDUsage_PD_BatteryID: sprintf (cstrName, "Battery ID"); break;
1632 case kHIDUsage_PD_Charger: sprintf (cstrName, "Charger"); break;
1633 case kHIDUsage_PD_ChargerID: sprintf (cstrName, "Charger ID"); break;
1634 case kHIDUsage_PD_PowerConverter: sprintf (cstrName, "Power Converter Power Module"); break;
1635 case kHIDUsage_PD_PowerConverterID: sprintf (cstrName, "Power Converter ID"); break;
1636 case kHIDUsage_PD_OutletSystem: sprintf (cstrName, "Outlet System power module"); break;
1637 case kHIDUsage_PD_OutletSystemID: sprintf (cstrName, "Outlet System ID"); break;
1638 case kHIDUsage_PD_Input: sprintf (cstrName, "Power Device Input"); break;
1639 case kHIDUsage_PD_InputID: sprintf (cstrName, "Power Device Input ID"); break;
1640 case kHIDUsage_PD_Output: sprintf (cstrName, "Power Device Output"); break;
1641 case kHIDUsage_PD_OutputID: sprintf (cstrName, "Power Device Output ID"); break;
1642 case kHIDUsage_PD_Flow: sprintf (cstrName, "Power Device Flow"); break;
1643 case kHIDUsage_PD_FlowID: sprintf (cstrName, "Power Device Flow ID"); break;
1644 case kHIDUsage_PD_Outlet: sprintf (cstrName, "Power Device Outlet"); break;
1645 case kHIDUsage_PD_OutletID: sprintf (cstrName, "Power Device Outlet ID"); break;
1646 case kHIDUsage_PD_Gang: sprintf (cstrName, "Power Device Gang"); break;
1647 case kHIDUsage_PD_GangID: sprintf (cstrName, "Power Device Gang ID"); break;
1648 case kHIDUsage_PD_PowerSummary: sprintf (cstrName, "Power Device Power Summary"); break;
1649 case kHIDUsage_PD_PowerSummaryID: sprintf (cstrName, "Power Device Power Summary ID"); break;
1651 case kHIDUsage_PD_Voltage: sprintf (cstrName, "Power Device Voltage"); break;
1652 case kHIDUsage_PD_Current: sprintf (cstrName, "Power Device Current"); break;
1653 case kHIDUsage_PD_Frequency: sprintf (cstrName, "Power Device Frequency"); break;
1654 case kHIDUsage_PD_ApparentPower: sprintf (cstrName, "Power Device Apparent Power"); break;
1655 case kHIDUsage_PD_ActivePower: sprintf (cstrName, "Power Device RMS Power"); break;
1656 case kHIDUsage_PD_PercentLoad: sprintf (cstrName, "Power Device Percent Load"); break;
1657 case kHIDUsage_PD_Temperature: sprintf (cstrName, "Power Device Temperature"); break;
1658 case kHIDUsage_PD_Humidity: sprintf (cstrName, "Power Device Humidity"); break;
1659 case kHIDUsage_PD_BadCount: sprintf (cstrName, "Power Device Bad Condition Count"); break;
1661 case kHIDUsage_PD_ConfigVoltage: sprintf (cstrName, "Power Device Nominal Voltage"); break;
1662 case kHIDUsage_PD_ConfigCurrent: sprintf (cstrName, "Power Device Nominal Current"); break;
1663 case kHIDUsage_PD_ConfigFrequency: sprintf (cstrName, "Power Device Nominal Frequency"); break;
1664 case kHIDUsage_PD_ConfigApparentPower: sprintf (cstrName, "Power Device Nominal Apparent Power"); break;
1665 case kHIDUsage_PD_ConfigActivePower: sprintf (cstrName, "Power Device Nominal RMS Power"); break;
1666 case kHIDUsage_PD_ConfigPercentLoad: sprintf (cstrName, "Power Device Nominal Percent Load"); break;
1667 case kHIDUsage_PD_ConfigTemperature: sprintf (cstrName, "Power Device Nominal Temperature"); break;
1669 case kHIDUsage_PD_ConfigHumidity: sprintf (cstrName, "Power Device Nominal Humidity"); break;
1670 case kHIDUsage_PD_SwitchOnControl: sprintf (cstrName, "Power Device Switch On Control"); break;
1671 case kHIDUsage_PD_SwitchOffControl: sprintf (cstrName, "Power Device Switch Off Control"); break;
1672 case kHIDUsage_PD_ToggleControl: sprintf (cstrName, "Power Device Toogle Sequence Control"); break;
1673 case kHIDUsage_PD_LowVoltageTransfer: sprintf (cstrName, "Power Device Min Transfer Voltage"); break;
1674 case kHIDUsage_PD_HighVoltageTransfer: sprintf (cstrName, "Power Device Max Transfer Voltage"); break;
1675 case kHIDUsage_PD_DelayBeforeReboot: sprintf (cstrName, "Power Device Delay Before Reboot"); break;
1676 case kHIDUsage_PD_DelayBeforeStartup: sprintf (cstrName, "Power Device Delay Before Startup"); break;
1677 case kHIDUsage_PD_DelayBeforeShutdown: sprintf (cstrName, "Power Device Delay Before Shutdown"); break;
1678 case kHIDUsage_PD_Test: sprintf (cstrName, "Power Device Test Request/Result"); break;
1679 case kHIDUsage_PD_ModuleReset: sprintf (cstrName, "Power Device Reset Request/Result"); break;
1680 case kHIDUsage_PD_AudibleAlarmControl: sprintf (cstrName, "Power Device Audible Alarm Control"); break;
1682 case kHIDUsage_PD_Present: sprintf (cstrName, "Power Device Present"); break;
1683 case kHIDUsage_PD_Good: sprintf (cstrName, "Power Device Good"); break;
1684 case kHIDUsage_PD_InternalFailure: sprintf (cstrName, "Power Device Internal Failure"); break;
1685 case kHIDUsage_PD_VoltageOutOfRange: sprintf (cstrName, "Power Device Voltage Out Of Range"); break;
1686 case kHIDUsage_PD_FrequencyOutOfRange: sprintf (cstrName, "Power Device Frequency Out Of Range"); break;
1687 case kHIDUsage_PD_Overload: sprintf (cstrName, "Power Device Overload"); break;
1688 case kHIDUsage_PD_OverCharged: sprintf (cstrName, "Power Device Over Charged"); break;
1689 case kHIDUsage_PD_OverTemperature: sprintf (cstrName, "Power Device Over Temperature"); break;
1690 case kHIDUsage_PD_ShutdownRequested: sprintf (cstrName, "Power Device Shutdown Requested"); break;
1692 case kHIDUsage_PD_ShutdownImminent: sprintf (cstrName, "Power Device Shutdown Imminent"); break;
1693 case kHIDUsage_PD_SwitchOnOff: sprintf (cstrName, "Power Device On/Off Switch Status"); break;
1694 case kHIDUsage_PD_Switchable: sprintf (cstrName, "Power Device Switchable"); break;
1695 case kHIDUsage_PD_Used: sprintf (cstrName, "Power Device Used"); break;
1696 case kHIDUsage_PD_Boost: sprintf (cstrName, "Power Device Boosted"); break;
1697 case kHIDUsage_PD_Buck: sprintf (cstrName, "Power Device Bucked"); break;
1698 case kHIDUsage_PD_Initialized: sprintf (cstrName, "Power Device Initialized"); break;
1699 case kHIDUsage_PD_Tested: sprintf (cstrName, "Power Device Tested"); break;
1700 case kHIDUsage_PD_AwaitingPower: sprintf (cstrName, "Power Device Awaiting Power"); break;
1701 case kHIDUsage_PD_CommunicationLost: sprintf (cstrName, "Power Device Communication Lost"); break;
1703 case kHIDUsage_PD_iManufacturer: sprintf (cstrName, "Power Device Manufacturer String Index"); break;
1704 case kHIDUsage_PD_iProduct: sprintf (cstrName, "Power Device Product String Index"); break;
1705 case kHIDUsage_PD_iserialNumber: sprintf (cstrName, "Power Device Serial Number String Index"); break;
1706 default: sprintf (cstrName, "Power Device Usage 0x%lx", valueUsage); break;
1708 break;
1709 case kHIDPage_BatterySystem:
1710 if (((valueUsage >= 0x0A) && (valueUsage <= 0x0F)) || ((valueUsage >= 0x1E) && (valueUsage <= 0x27)) ||
1711 ((valueUsage >= 0x30) && (valueUsage <= 0x3F)) || ((valueUsage >= 0x4C) && (valueUsage <= 0x5F)) ||
1712 ((valueUsage >= 0x6C) && (valueUsage <= 0x7F)) || ((valueUsage >= 0x90) && (valueUsage <= 0xBF)) ||
1713 ((valueUsage >= 0xC3) && (valueUsage <= 0xCF)) || ((valueUsage >= 0xDD) && (valueUsage <= 0xEF)) ||
1714 ((valueUsage >= 0xF2) && (valueUsage <= 0xFF)))
1715 sprintf (cstrName, "Power Device Reserved");
1716 else
1717 switch (valueUsage)
1719 case kHIDUsage_BS_Undefined: sprintf (cstrName, "Battery System Undefined"); break;
1720 case kHIDUsage_BS_SMBBatteryMode: sprintf (cstrName, "SMB Mode"); break;
1721 case kHIDUsage_BS_SMBBatteryStatus: sprintf (cstrName, "SMB Status"); break;
1722 case kHIDUsage_BS_SMBAlarmWarning: sprintf (cstrName, "SMB Alarm Warning"); break;
1723 case kHIDUsage_BS_SMBChargerMode: sprintf (cstrName, "SMB Charger Mode"); break;
1724 case kHIDUsage_BS_SMBChargerStatus: sprintf (cstrName, "SMB Charger Status"); break;
1725 case kHIDUsage_BS_SMBChargerSpecInfo: sprintf (cstrName, "SMB Charger Extended Status"); break;
1726 case kHIDUsage_BS_SMBSelectorState: sprintf (cstrName, "SMB Selector State"); break;
1727 case kHIDUsage_BS_SMBSelectorPresets: sprintf (cstrName, "SMB Selector Presets"); break;
1728 case kHIDUsage_BS_SMBSelectorInfo: sprintf (cstrName, "SMB Selector Info"); break;
1729 case kHIDUsage_BS_OptionalMfgFunction1: sprintf (cstrName, "Battery System Optional SMB Mfg Function 1"); break;
1730 case kHIDUsage_BS_OptionalMfgFunction2: sprintf (cstrName, "Battery System Optional SMB Mfg Function 2"); break;
1731 case kHIDUsage_BS_OptionalMfgFunction3: sprintf (cstrName, "Battery System Optional SMB Mfg Function 3"); break;
1732 case kHIDUsage_BS_OptionalMfgFunction4: sprintf (cstrName, "Battery System Optional SMB Mfg Function 4"); break;
1733 case kHIDUsage_BS_OptionalMfgFunction5: sprintf (cstrName, "Battery System Optional SMB Mfg Function 5"); break;
1734 case kHIDUsage_BS_ConnectionToSMBus: sprintf (cstrName, "Battery System Connection To System Management Bus"); break;
1735 case kHIDUsage_BS_OutputConnection: sprintf (cstrName, "Battery System Output Connection Status"); break;
1736 case kHIDUsage_BS_ChargerConnection: sprintf (cstrName, "Battery System Charger Connection"); break;
1737 case kHIDUsage_BS_BatteryInsertion: sprintf (cstrName, "Battery System Battery Insertion"); break;
1738 case kHIDUsage_BS_Usenext: sprintf (cstrName, "Battery System Use Next"); break;
1739 case kHIDUsage_BS_OKToUse: sprintf (cstrName, "Battery System OK To Use"); break;
1740 case kHIDUsage_BS_BatterySupported: sprintf (cstrName, "Battery System Battery Supported"); break;
1741 case kHIDUsage_BS_SelectorRevision: sprintf (cstrName, "Battery System Selector Revision"); break;
1742 case kHIDUsage_BS_ChargingIndicator: sprintf (cstrName, "Battery System Charging Indicator"); break;
1743 case kHIDUsage_BS_ManufacturerAccess: sprintf (cstrName, "Battery System Manufacturer Access"); break;
1744 case kHIDUsage_BS_RemainingCapacityLimit: sprintf (cstrName, "Battery System Remaining Capacity Limit"); break;
1745 case kHIDUsage_BS_RemainingTimeLimit: sprintf (cstrName, "Battery System Remaining Time Limit"); break;
1746 case kHIDUsage_BS_AtRate: sprintf (cstrName, "Battery System At Rate..."); break;
1747 case kHIDUsage_BS_CapacityMode: sprintf (cstrName, "Battery System Capacity Mode"); break;
1748 case kHIDUsage_BS_BroadcastToCharger: sprintf (cstrName, "Battery System Broadcast To Charger"); break;
1749 case kHIDUsage_BS_PrimaryBattery: sprintf (cstrName, "Battery System Primary Battery"); break;
1750 case kHIDUsage_BS_ChargeController: sprintf (cstrName, "Battery System Charge Controller"); break;
1751 case kHIDUsage_BS_TerminateCharge: sprintf (cstrName, "Battery System Terminate Charge"); break;
1752 case kHIDUsage_BS_TerminateDischarge: sprintf (cstrName, "Battery System Terminate Discharge"); break;
1753 case kHIDUsage_BS_BelowRemainingCapacityLimit: sprintf (cstrName, "Battery System Below Remaining Capacity Limit"); break;
1754 case kHIDUsage_BS_RemainingTimeLimitExpired: sprintf (cstrName, "Battery System Remaining Time Limit Expired"); break;
1755 case kHIDUsage_BS_Charging: sprintf (cstrName, "Battery System Charging"); break;
1756 case kHIDUsage_BS_Discharging: sprintf (cstrName, "Battery System Discharging"); break;
1757 case kHIDUsage_BS_FullyCharged: sprintf (cstrName, "Battery System Fully Charged"); break;
1758 case kHIDUsage_BS_FullyDischarged: sprintf (cstrName, "Battery System Fully Discharged"); break;
1759 case kHIDUsage_BS_ConditioningFlag: sprintf (cstrName, "Battery System Conditioning Flag"); break;
1760 case kHIDUsage_BS_AtRateOK: sprintf (cstrName, "Battery System At Rate OK"); break;
1761 case kHIDUsage_BS_SMBErrorCode: sprintf (cstrName, "Battery System SMB Error Code"); break;
1762 case kHIDUsage_BS_NeedReplacement: sprintf (cstrName, "Battery System Need Replacement"); break;
1763 case kHIDUsage_BS_AtRateTimeToFull: sprintf (cstrName, "Battery System At Rate Time To Full"); break;
1764 case kHIDUsage_BS_AtRateTimeToEmpty: sprintf (cstrName, "Battery System At Rate Time To Empty"); break;
1765 case kHIDUsage_BS_AverageCurrent: sprintf (cstrName, "Battery System Average Current"); break;
1766 case kHIDUsage_BS_Maxerror: sprintf (cstrName, "Battery System Max Error"); break;
1767 case kHIDUsage_BS_RelativeStateOfCharge: sprintf (cstrName, "Battery System Relative State Of Charge"); break;
1768 case kHIDUsage_BS_AbsoluteStateOfCharge: sprintf (cstrName, "Battery System Absolute State Of Charge"); break;
1769 case kHIDUsage_BS_RemainingCapacity: sprintf (cstrName, "Battery System Remaining Capacity"); break;
1770 case kHIDUsage_BS_FullChargeCapacity: sprintf (cstrName, "Battery System Full Charge Capacity"); break;
1771 case kHIDUsage_BS_RunTimeToEmpty: sprintf (cstrName, "Battery System Run Time To Empty"); break;
1772 case kHIDUsage_BS_AverageTimeToEmpty: sprintf (cstrName, "Battery System Average Time To Empty"); break;
1773 case kHIDUsage_BS_AverageTimeToFull: sprintf (cstrName, "Battery System Average Time To Full"); break;
1774 case kHIDUsage_BS_CycleCount: sprintf (cstrName, "Battery System Cycle Count"); break;
1775 case kHIDUsage_BS_BattPackModelLevel: sprintf (cstrName, "Battery System Batt Pack Model Level"); break;
1776 case kHIDUsage_BS_InternalChargeController: sprintf (cstrName, "Battery System Internal Charge Controller"); break;
1777 case kHIDUsage_BS_PrimaryBatterySupport: sprintf (cstrName, "Battery System Primary Battery Support"); break;
1778 case kHIDUsage_BS_DesignCapacity: sprintf (cstrName, "Battery System Design Capacity"); break;
1779 case kHIDUsage_BS_SpecificationInfo: sprintf (cstrName, "Battery System Specification Info"); break;
1780 case kHIDUsage_BS_ManufacturerDate: sprintf (cstrName, "Battery System Manufacturer Date"); break;
1781 case kHIDUsage_BS_SerialNumber: sprintf (cstrName, "Battery System Serial Number"); break;
1782 case kHIDUsage_BS_iManufacturerName: sprintf (cstrName, "Battery System Manufacturer Name Index"); break;
1783 case kHIDUsage_BS_iDevicename: sprintf (cstrName, "Battery System Device Name Index"); break;
1784 case kHIDUsage_BS_iDeviceChemistry: sprintf (cstrName, "Battery System Device Chemistry Index"); break;
1785 case kHIDUsage_BS_ManufacturerData: sprintf (cstrName, "Battery System Manufacturer Data"); break;
1786 case kHIDUsage_BS_Rechargable: sprintf (cstrName, "Battery System Rechargable"); break;
1787 case kHIDUsage_BS_WarningCapacityLimit: sprintf (cstrName, "Battery System Warning Capacity Limit"); break;
1788 case kHIDUsage_BS_CapacityGranularity1: sprintf (cstrName, "Battery System Capacity Granularity 1"); break;
1789 case kHIDUsage_BS_CapacityGranularity2: sprintf (cstrName, "Battery System Capacity Granularity 2"); break;
1790 case kHIDUsage_BS_iOEMInformation: sprintf (cstrName, "Battery System OEM Information Index"); break;
1791 case kHIDUsage_BS_InhibitCharge: sprintf (cstrName, "Battery System Inhibit Charge"); break;
1792 case kHIDUsage_BS_EnablePolling: sprintf (cstrName, "Battery System Enable Polling"); break;
1793 case kHIDUsage_BS_ResetToZero: sprintf (cstrName, "Battery System Reset To Zero"); break;
1794 case kHIDUsage_BS_ACPresent: sprintf (cstrName, "Battery System AC Present"); break;
1795 case kHIDUsage_BS_BatteryPresent: sprintf (cstrName, "Battery System Battery Present"); break;
1796 case kHIDUsage_BS_PowerFail: sprintf (cstrName, "Battery System Power Fail"); break;
1797 case kHIDUsage_BS_AlarmInhibited: sprintf (cstrName, "Battery System Alarm Inhibited"); break;
1798 case kHIDUsage_BS_ThermistorUnderRange: sprintf (cstrName, "Battery System Thermistor Under Range"); break;
1799 case kHIDUsage_BS_ThermistorHot: sprintf (cstrName, "Battery System Thermistor Hot"); break;
1800 case kHIDUsage_BS_ThermistorCold: sprintf (cstrName, "Battery System Thermistor Cold"); break;
1801 case kHIDUsage_BS_ThermistorOverRange: sprintf (cstrName, "Battery System Thermistor Over Range"); break;
1802 case kHIDUsage_BS_VoltageOutOfRange: sprintf (cstrName, "Battery System Voltage Out Of Range"); break;
1803 case kHIDUsage_BS_CurrentOutOfRange: sprintf (cstrName, "Battery System Current Out Of Range"); break;
1804 case kHIDUsage_BS_CurrentNotRegulated: sprintf (cstrName, "Battery System Current Not Regulated"); break;
1805 case kHIDUsage_BS_VoltageNotRegulated: sprintf (cstrName, "Battery System Voltage Not Regulated"); break;
1806 case kHIDUsage_BS_MasterMode: sprintf (cstrName, "Battery System Master Mode"); break;
1807 case kHIDUsage_BS_ChargerSelectorSupport: sprintf (cstrName, "Battery System Charger Support Selector"); break;
1808 case kHIDUsage_BS_ChargerSpec: sprintf (cstrName, "attery System Charger Specification"); break;
1809 case kHIDUsage_BS_Level2: sprintf (cstrName, "Battery System Charger Level 2"); break;
1810 case kHIDUsage_BS_Level3: sprintf (cstrName, "Battery System Charger Level 3"); break;
1811 default: sprintf (cstrName, "Battery System Usage 0x%lx", valueUsage); break;
1813 break;
1814 case kHIDPage_AlphanumericDisplay:
1815 switch (valueUsage)
1817 default: sprintf (cstrName, "Alphanumeric Display Usage 0x%lx", valueUsage); break;
1819 break;
1820 case kHIDPage_BarCodeScanner:
1821 switch (valueUsage)
1823 default: sprintf (cstrName, "Bar Code Scanner Usage 0x%lx", valueUsage); break;
1825 break;
1826 case kHIDPage_Scale:
1827 switch (valueUsage)
1829 default: sprintf (cstrName, "Scale Usage 0x%lx", valueUsage); break;
1831 break;
1832 case kHIDPage_CameraControl:
1833 switch (valueUsage)
1835 default: sprintf (cstrName, "Camera Control Usage 0x%lx", valueUsage); break;
1837 break;
1838 case kHIDPage_Arcade:
1839 switch (valueUsage)
1841 default: sprintf (cstrName, "Arcade Usage 0x%lx", valueUsage); break;
1843 break;
1844 default:
1845 if (valueUsagePage > kHIDPage_VendorDefinedStart)
1846 sprintf (cstrName, "Vendor Defined Usage 0x%lx", valueUsage);
1847 else
1848 sprintf (cstrName, "Page: 0x%lx, Usage: 0x%lx", valueUsagePage, valueUsage);
1849 break;
1853 // ---------------------------------
1854 // returns calibrated value given raw value passed in
1855 // calibrated value is equal to min and max values returned by HIDGetElementValue since device list built scaled to element reported min and max values
1857 SInt32 HIDCalibrateValue (SInt32 value, pRecElement pElement)
1859 if (NULL != pElement)
1861 float deviceScale = pElement->max - pElement->min;
1862 float readScale = pElement->calMax - pElement->calMin;
1863 if (readScale == 0)
1864 return value; // no scaling as
1865 else
1866 return ((value - pElement->calMin) * deviceScale / readScale) + pElement->min;
1868 else
1869 return 0; // bad element passed in
1872 // ---------------------------------
1873 // returns scaled value given raw value passed in
1874 // scaled value is equal to current value assumed to be in the range of element reported min and max values scaled to user min and max scaled values
1876 SInt32 HIDScaleValue (SInt32 value, pRecElement pElement)
1878 float deviceScale = pElement->userMax - pElement->userMin;
1879 float readScale = pElement->max - pElement->min;
1880 if (readScale == 0)
1881 return value;
1882 else
1883 return (value - pElement->min) * deviceScale / readScale + pElement->userMin;
1886 // ---------------------------------
1887 // convert an element type to a mask
1888 HIDElementTypeMask HIDConvertElementTypeToMask (const long type)
1890 HIDElementTypeMask result = kHIDElementTypeAll;
1892 switch (type)
1894 case kIOHIDElementTypeInput_Misc:
1895 case kIOHIDElementTypeInput_Button:
1896 case kIOHIDElementTypeInput_Axis:
1897 case kIOHIDElementTypeInput_ScanCodes:
1898 result = kHIDElementTypeInput;
1899 break;
1900 case kIOHIDElementTypeOutput:
1901 result = kHIDElementTypeOutput;
1902 break;
1903 case kIOHIDElementTypeFeature:
1904 result = kHIDElementTypeFeature;
1905 break;
1906 case kIOHIDElementTypeCollection:
1907 result = kHIDElementTypeCollection;
1908 break;
1909 default:
1910 result = kHIDElementTypeAll;
1911 break;
1913 return result;
1916 Boolean HIDFindDevice(const pRecDevice pSearchDevice, pRecDevice *ppFoundDevice)
1918 pRecDevice pDevice, pBestDevice = NULL;
1919 long bestScore = 0;
1921 // iterate over all devices
1922 pDevice = HIDGetFirstDevice();
1923 while (pDevice)
1925 long deviceScore = 1;
1927 if (pSearchDevice->vendorID && (pSearchDevice->vendorID == pDevice->vendorID))
1929 deviceScore += 10;
1930 if (pSearchDevice->productID && (pSearchDevice->productID == pDevice->productID))
1931 deviceScore += 8;
1934 if ((pSearchDevice->usagePage && (pSearchDevice->usagePage == pDevice->usagePage)) &&
1935 (pSearchDevice->usage && (pSearchDevice->usage == pDevice->usage)))
1936 deviceScore += 9;
1938 if (pSearchDevice->locID && (pSearchDevice->locID == pDevice->locID))
1939 deviceScore += 5;
1941 if (deviceScore > bestScore)
1943 pBestDevice = pDevice;
1944 bestScore = deviceScore;
1945 #if 0 // set true to output scoring informaton
1946 printf("\n-HIDFindDevice(%ld:%ld)-I-Debug, better score: %ld.",pSearchElement->usagePage, pSearchElement->usage, score);
1947 HIDPrintElement(pBestElement);
1948 #endif
1950 pDevice = HIDGetNextDevice(pDevice);
1953 if (NULL != pBestDevice)
1955 *ppFoundDevice = pBestDevice;
1956 #if 0 // set true to output scoring informaton
1957 printf("\n-HIDFindDevice(%ld:%ld)-I-Debug, best score: %ld.",pSearchElement->usagePage, pSearchElement->usage, bestScore);
1958 HIDPrintElement(pBestElement);
1959 printf("\n");
1960 #endif
1961 return true;
1963 else
1964 return false;
1967 // ---------------------------------
1968 // find the device and element for this action
1969 // Device: serial, vendorID, productID, location, usagePage, usage
1970 // Element: cookie, usagePage, usage,
1972 Boolean HIDFindActionDeviceAndElement(const pRecDevice pSearchDevice, const pRecElement pSearchElement,
1973 pRecDevice *ppFoundDevice, pRecElement *ppFoundElement)
1975 pRecDevice pDevice, pBestDevice = NULL;
1976 pRecElement pElement, pBestElement = NULL;
1977 HIDElementTypeMask hidMask = HIDConvertElementTypeToMask (pSearchElement->type);
1978 long bestScore = 0;
1980 // iterate over all devices
1981 pDevice = HIDGetFirstDevice();
1982 while (pDevice)
1984 long deviceScore = 1;
1986 if (pSearchDevice->vendorID && (pSearchDevice->vendorID == pDevice->vendorID))
1988 deviceScore += 10;
1989 if (pSearchDevice->productID && (pSearchDevice->productID == pDevice->productID))
1990 deviceScore += 8;
1992 if ((pSearchDevice->usagePage && (pSearchDevice->usagePage == pDevice->usagePage)) &&
1993 (pSearchDevice->usage && (pSearchDevice->usage == pDevice->usage)))
1994 deviceScore += 9;
1996 if (pSearchDevice->locID && (pSearchDevice->locID == pDevice->locID))
1997 deviceScore += 5;
1999 // iterate over all elements of this device
2000 pElement = HIDGetFirstDeviceElement(pDevice, hidMask);
2001 while (pElement)
2003 long score = deviceScore;
2005 if ((pSearchElement->usagePage && (pSearchElement->usagePage == pElement->usagePage)) &&
2006 (pSearchElement->usage && (pSearchElement->usage == pElement->usage)))
2008 score += 5;
2010 if (pSearchElement->cookie && (pSearchElement->cookie == pElement->cookie))
2011 score += 4;
2013 else
2014 score = 0;
2015 #if 0 // set true to output scoring informaton
2016 if (kHIDPage_KeyboardOrKeypad != pElement->usagePage) // skip keyboards here
2018 printf("\n-HIDFindActionDeviceAndElement(%ld:%ld)-I-Debug, score: %ld.",pSearchElement->usagePage, pSearchElement->usage, score);
2019 HIDPrintElement(pElement);
2021 #endif
2022 if (score > bestScore)
2024 pBestDevice = pDevice;
2025 pBestElement = pElement;
2026 bestScore = score;
2027 #if 0 // set true to output scoring informaton
2028 printf("\n-HIDFindActionDeviceAndElement(%ld:%ld)-I-Debug, better score: %ld.",pSearchElement->usagePage, pSearchElement->usage, score);
2029 HIDPrintElement(pBestElement);
2030 #endif
2032 pElement = HIDGetNextDeviceElement(pElement, hidMask);
2034 pDevice = HIDGetNextDevice(pDevice);
2037 if ((NULL != pBestDevice) || (NULL != pBestElement))
2039 *ppFoundDevice = pBestDevice;
2040 *ppFoundElement = pBestElement;
2041 #if 0 // set true to output scoring informaton
2042 printf("\n-HIDFindActionDeviceAndElement(%ld:%ld)-I-Debug, best score: %ld.",pSearchElement->usagePage, pSearchElement->usage, bestScore);
2043 HIDPrintElement(pBestElement);
2044 printf("\n");
2045 #endif
2046 return true;
2048 else
2049 return false;
2052 // ---------------------------------
2053 // find the device and element for this action
2054 // Device: serial, vendorID, productID, location, usagePage, usage
2055 // Element: cookie, usagePage, usage,
2057 Boolean HIDFindSubElement(const pRecElement pStartElement, const pRecElement pSearchElement, pRecElement *ppFoundElement)
2059 pRecElement pElement, pBestElement = NULL;
2060 HIDElementTypeMask hidMask = HIDConvertElementTypeToMask (pSearchElement->type);
2061 long bestScore = 0;
2063 if ((NULL == pStartElement) || (NULL == pSearchElement) || (NULL == ppFoundElement))
2064 return false;
2066 // iterate over all children of this element
2067 pElement = pStartElement->pChild;
2069 while (pElement)
2071 long score = 0;
2072 #if 0 // set true to output searching informaton
2073 printf("\n-HIDFindSubElement, search = {t:%.2lX, u:%.4lX:%.4lX}, match = {t:%.2lX, u:%.4lX:%.4lX, s:\"%s\"}",
2074 pSearchElement->type, pSearchElement->usagePage, pSearchElement->usage,
2075 pElement->type, pElement->usagePage, pElement->usage, pElement->name);
2076 fflush(stdout);
2077 #endif
2078 if ((pSearchElement->usagePage && (pSearchElement->usagePage == pElement->usagePage)) && (pSearchElement->usage && (pSearchElement->usage == pElement->usage)))
2080 score += 4;
2081 if (pSearchElement->cookie && (pSearchElement->cookie == pElement->cookie))
2082 score += 5;
2084 #if 0 // set true to output searching informaton
2085 if (kHIDPage_KeyboardOrKeypad != pElement->usagePage) // skip keyboards here
2087 printf("\n-HIDFindSubElement(%ld:%ld)-I-Debug, score: %ld.",pSearchElement->usagePage, pSearchElement->usage, score);
2088 HIDPrintElement(pElement);
2090 #endif
2092 if (score > bestScore)
2094 pBestElement = pElement;
2095 bestScore = score;
2096 #if 0 // set true to output searching informaton
2097 printf("\n-HIDFindSubElement(%ld:%ld)-I-Debug, better score: %ld.",pSearchElement->usagePage, pSearchElement->usage, score);
2098 HIDPrintElement(pBestElement);
2099 #endif
2101 pElement = HIDGetNextDeviceElement(pElement, hidMask);
2103 #if 0 // set true to output searching informaton
2104 if (pBestElement)
2106 printf("\n-HIDFindSubElement(%ld:%ld)-I-Debug, best score: %ld.",pSearchElement->usagePage, pSearchElement->usage, bestScore);
2107 HIDPrintElement(pBestElement);
2108 printf("\n");
2110 #endif
2112 *ppFoundElement = pBestElement;
2113 return (NULL != pBestElement);
2116 // print out all of an elements information
2117 int HIDPrintElement(const pRecElement pElement)
2119 int results;
2120 int count;
2122 printf("\n");
2124 if (gDepth != pElement->depth)
2125 printf("%d",gDepth);
2126 for (count = 0;count < pElement->depth;count++)
2127 printf(" | ");
2129 #if 0 // this is verbose
2130 results =
2131 printf("-HIDPrintElement = {name: \"%s\", t: 0x%.2lX, u:%ld:%ld, c: %ld, min/max: %ld/%ld, scaled: %ld/%ld, size: %ld, rel: %s, wrap: %s, nonLinear: %s, preferred: %s, nullState: %s, units: %ld, exp: %ld, cal: %ld/%ld, user: %ld/%ld, depth: %ld}.",
2132 pElement->name, // name of element (c string)
2133 pElement->type, // the type defined by IOHIDElementType in IOHIDKeys.h
2134 pElement->usagePage, // usage page from IOUSBHIDParser.h which defines general usage
2135 pElement->usage, // usage within above page from IOUSBHIDParser.h which defines specific usage
2136 (long) pElement->cookie, // unique value (within device of specific vendorID and productID) which identifies element, will NOT change
2137 pElement->min, // reported min value possible
2138 pElement->max, // reported max value possible
2139 pElement->scaledMin, // reported scaled min value possible
2140 pElement->scaledMax, // reported scaled max value possible
2141 pElement->size, // size in bits of data return from element
2142 pElement->relative ? "YES" : "NO", // are reports relative to last report (deltas)
2143 pElement->wrapping ? "YES" : "NO", // does element wrap around (one value higher than max is min)
2144 pElement->nonLinear ? "YES" : "NO", // are the values reported non-linear relative to element movement
2145 pElement->preferredState ? "YES" : "NO",// does element have a preferred state (such as a button)
2146 pElement->nullState ? "YES" : "NO", // does element have null state
2147 pElement->units, // units value is reported in (not used very often)
2148 pElement->unitExp, // exponent for units (also not used very often)
2149 pElement->calMin, // min returned value (for calibrate call)
2150 pElement->calMax, // max returned value
2151 pElement->userMin, // user set min to scale to (for scale call)
2152 pElement->userMax, // user set max
2153 pElement->depth
2155 #else // this is brief
2156 results =
2157 printf("-HIDPrintElement = {t: 0x%lX, u:%ld:%ld, c: %ld, name: \"%s\", d: %ld}.",
2158 pElement->type, // the type defined by IOHIDElementType in IOHIDKeys.h
2159 pElement->usagePage, // usage page from IOUSBHIDParser.h which defines general usage
2160 pElement->usage, // usage within above page from IOUSBHIDParser.h which defines specific usage
2161 (long) pElement->cookie, // unique value (within device of specific vendorID and productID) which identifies element, will NOT change
2162 pElement->name, // name of element (c string)
2163 pElement->depth
2165 #endif
2166 fflush(stdout);
2167 return results;
2170 // return true if this is a valid device pointer
2171 Boolean HIDIsValidDevice(const pRecDevice pSearchDevice)
2173 pRecDevice pDevice = gpDeviceList;
2175 while (pDevice)
2177 if (pDevice == pSearchDevice)
2178 return true;
2179 pDevice = pDevice->pNext;
2181 return false;
2184 // return true if this is a valid element pointer for this device
2185 Boolean HIDIsValidElement(const pRecDevice pSearchDevice, const pRecElement pSearchElement)
2187 if (HIDIsValidDevice(pSearchDevice))
2189 pRecElement pRecElementTemp = HIDGetFirstDeviceElement(pSearchDevice,kHIDElementTypeAll);
2190 while (pRecElementTemp)
2192 if (pRecElementTemp == pSearchElement)
2193 return true;
2194 pRecElementTemp = HIDGetNextDeviceElement(pRecElementTemp,kHIDElementTypeAll);
2197 return false;
2199 #endif //SC_DARWIN