2 // File: HID_Utilities.c
4 // Contains: Implementation of the HID utilities
6 // Copyright © 2007-2009 Apple Inc., All Rights Reserved
8 // Disclaimer: IMPORTANT: This Apple software is supplied to you by
9 // Apple Inc. ("Apple") in consideration of your agreement to the
10 // following terms, and your use, installation, modification or
11 // redistribution of this Apple software constitutes acceptance of these
12 // terms. If you do not agree with these terms, please do not use,
13 // install, modify or redistribute this Apple software.
15 // In consideration of your agreement to abide by the following terms, and
16 // subject to these terms, Apple grants you a personal, non-exclusive
17 // license, under Apple's copyrights in this original Apple software (the
18 // "Apple Software"), to use, reproduce, modify and redistribute the Apple
19 // Software, with or without modifications, in source and/or binary forms;
20 // provided that if you redistribute the Apple Software in its entirety and
21 // without modifications, you must retain this notice and the following
22 // text and disclaimers in all such redistributions of the Apple Software.
23 // Neither the name, trademarks, service marks or logos of Apple Inc.
24 // may be used to endorse or promote products derived from the Apple
25 // Software without specific prior written permission from Apple. Except
26 // as expressly stated in this notice, no other rights or licenses, express
27 // or implied, are granted by Apple herein, including but not limited to
28 // any patent rights that may be infringed by your derivative works or by
29 // other works in which the Apple Software may be incorporated.
31 // The Apple Software is provided by Apple on an "AS IS" basis. APPLE
32 // MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
33 // THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
34 // FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
35 // OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
37 // IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
38 // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
41 // MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
42 // AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
43 // STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
44 // POSSIBILITY OF SUCH DAMAGE.
46 //***************************************************
47 #pragma mark - includes & imports
48 //-----------------------------------------------------
50 #include <AssertMacros.h>
52 #include "HID_Utilities_External.h"
54 //***************************************************
55 #pragma mark - typedefs, enums, defines, etc.
56 //-----------------------------------------------------
57 #define FAKE_MISSING_NAMES 1 // set this to true while debuging to get more explicit element names; false for the
60 #define kPercentMove 10 // precent of overall range a element must move to register
61 #define kNameKeyCFStringRef CFSTR( "Name" ) // dictionary key
63 //***************************************************
64 #pragma mark - local ( static ) function prototypes
65 //-----------------------------------------------------
67 static void CFSetApplierFunctionCopyToCFArray( const void *value
, void *context
);
68 static CFComparisonResult
CFDeviceArrayComparatorFunction( const void *val1
, const void *val2
, void *context
);
69 static CFMutableDictionaryRef
hu_SetUpMatchingDictionary( UInt32 inUsagePage
, UInt32 inUsage
);
71 //***************************************************
72 #pragma mark - exported globals
73 //-----------------------------------------------------
75 IOHIDManagerRef gIOHIDManagerRef
= NULL
;
76 CFMutableArrayRef gDeviceCFArrayRef
= NULL
;
78 CFArrayRef gElementCFArrayRef
= NULL
;
80 //***************************************************
81 #pragma mark - local ( static ) globals
82 //-----------------------------------------------------
84 //***************************************************
85 #pragma mark - exported function implementations
86 //-----------------------------------------------------
88 //*************************************************************************
90 // HIDBuildMultiDeviceList( inUsagePages, inUsages, inNumDeviceTypes )
92 // Purpose: builds list of devices with elements
94 // Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages
95 // inUsages - inNumDeviceTypes sized array of matching usages
96 // inNumDeviceTypes - number of usage pages & usages
98 // Returns: Boolean - if successful
100 Boolean
HIDBuildMultiDeviceList( const UInt32
*inUsagePages
, const UInt32
*inUsages
, int inNumDeviceTypes
)
102 Boolean result
= FALSE
; // assume failure ( pessimist! )
103 Boolean first
= ( !gIOHIDManagerRef
); // not yet created?
106 // create the manager
107 gIOHIDManagerRef
= IOHIDManagerCreate( kCFAllocatorDefault
, kIOHIDOptionsTypeNone
);
110 if ( gIOHIDManagerRef
) {
111 CFMutableArrayRef hidMatchingCFMutableArrayRef
= NULL
;
113 if ( inUsages
&& inUsagePages
&& inNumDeviceTypes
) {
114 hidMatchingCFMutableArrayRef
= CFArrayCreateMutable( kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
116 if ( hidMatchingCFMutableArrayRef
) {
118 for ( idx
= 0; idx
< inNumDeviceTypes
; idx
++ ) { // for all usage and usage page types
119 // Set up matching dictionary. returns NULL on error.
120 CFMutableDictionaryRef hidMatchingCFDictRef
= hu_SetUpMatchingDictionary( inUsagePages
[idx
], inUsages
[idx
] );
122 if ( hidMatchingCFDictRef
) {
123 CFArrayAppendValue( hidMatchingCFMutableArrayRef
, (void*) hidMatchingCFDictRef
);
124 CFRelease( hidMatchingCFDictRef
);
126 fprintf( stderr
, "%s: Couldn’t create a matching dictionary.", __PRETTY_FUNCTION__
);
130 fprintf( stderr
, "%s: Couldn’t create a matching array.", __PRETTY_FUNCTION__
);
134 // set it for IOHIDManager to use to match against
135 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef
, hidMatchingCFMutableArrayRef
);
137 if ( hidMatchingCFMutableArrayRef
) {
138 CFRelease( hidMatchingCFMutableArrayRef
);
143 IOReturn tIOReturn
= IOHIDManagerOpen( gIOHIDManagerRef
, kIOHIDOptionsTypeNone
);
145 if ( kIOReturnSuccess
!= tIOReturn
) {
146 fprintf( stderr
, "%s: Couldn’t open IOHIDManager.", __PRETTY_FUNCTION__
);
150 HIDRebuildDevices( );
153 fprintf( stderr
, "%s: Couldn’t create a IOHIDManager.", __PRETTY_FUNCTION__
);
157 } // HIDBuildMultiDeviceList
160 /*************************************************************************
162 * HIDBuildDeviceList( inUsagePage, inUsage )
164 * Purpose: builds list of devices with elements
166 * Notes: same as above but this uses a single inUsagePage and usage
167 * allocates memory and captures devices
168 * list is allocated internally within HID Utilites and can be accessed via accessor functions
169 * structures within list are considered flat and user accessable, but not user modifiable
170 * can be called again to rebuild list to account for new devices
171 * ( will do the right thing in case of disposing existing list )
173 * Inputs: inUsagePage - usage page
176 * Returns: Boolean - if successful
179 Boolean
HIDBuildDeviceList( UInt32 inUsagePage
, UInt32 inUsage
)
181 return HIDBuildMultiDeviceList( &inUsagePage
, &inUsage
, 1 ); // call HIDBuildMultiDeviceList with a single usage
184 /*************************************************************************
186 * HIDUpdateDeviceList( inUsagePages, inUsages, inNumDeviceTypes )
188 * Purpose: updates the current device list for any new/removed devices
190 * Notes: if this is called before HIDBuildDeviceList then it functions like HIDBuildMultiDeviceList
191 * inUsagePage & inUsage are each a inNumDeviceTypes sized array of matching usage and usage pages
193 * Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages
194 * inUsages - inNumDeviceTypes sized array of matching usages
195 * inNumDeviceTypes - number of usage pages & usages
197 * Returns: Boolean - TRUE if the device config changed
200 Boolean
HIDUpdateDeviceList( const UInt32
*inUsagePages
, const UInt32
*inUsages
, int inNumDeviceTypes
)
202 return HIDBuildMultiDeviceList( inUsagePages
, inUsages
, inNumDeviceTypes
);
205 /*************************************************************************
207 * HIDReleaseDeviceList( void )
209 * Purpose: release list built by above functions
211 * Notes: MUST be called prior to application exit to properly release devices
212 * if not called( or app crashes ) devices can be recovered by pluging into different location in USB chain
219 void HIDReleaseDeviceList( void )
221 if ( gDeviceCFArrayRef
) {
222 CFRelease(gDeviceCFArrayRef
);
223 gDeviceCFArrayRef
= NULL
;
227 /*************************************************************************
229 * HIDHaveDeviceList( void )
231 * Purpose: does a device list exist?
235 * Returns: Boolean - TRUE if we have previously built a device list
238 Boolean
HIDHaveDeviceList( void )
240 return ( NULL
!= gDeviceCFArrayRef
);
243 //*************************************************************************
245 // HIDRebuildDevices( )
247 // Purpose: rebuilds the (internal) list of IOHIDDevices
254 void HIDRebuildDevices( void ) {
255 // get the set of devices from the IOHID manager
256 CFSetRef devCFSetRef
= IOHIDManagerCopyDevices( gIOHIDManagerRef
);
259 // if the existing array isn't empty...
260 if ( gDeviceCFArrayRef
) {
262 CFRelease( gDeviceCFArrayRef
);
264 // create an empty array
265 gDeviceCFArrayRef
= CFArrayCreateMutable( kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
266 // now copy the set to the array
267 CFSetApplyFunction( devCFSetRef
, CFSetApplierFunctionCopyToCFArray
, ( void * ) gDeviceCFArrayRef
);
268 // now sort the array by location ID's
269 CFIndex cnt
= CFArrayGetCount( gDeviceCFArrayRef
);
270 CFArraySortValues( gDeviceCFArrayRef
, CFRangeMake( 0, cnt
), CFDeviceArrayComparatorFunction
, NULL
);
272 // and release the set we copied from the IOHID manager
273 CFRelease( devCFSetRef
);
275 } // HIDRebuildDevices
277 // ---------------------------------
279 // how many HID devices have been found
280 // returns 0 if no device list exist
282 UInt32
HIDCountDevices( void )
284 return CFArrayGetCount( gDeviceCFArrayRef
);
287 // ---------------------------------
289 // how many elements does a specific device have
290 // returns 0 if device is invlaid or NULL
292 UInt32
HIDCountDeviceElements( IOHIDDeviceRef inIOHIDDeviceRef
, HIDElementTypeMask typeMask
)
296 if ( inIOHIDDeviceRef
) {
297 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
299 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements( inIOHIDDeviceRef
, NULL
, kIOHIDOptionsTypeNone
);
301 if ( gElementCFArrayRef
) {
302 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
303 for ( idx
= 0; idx
< cnt
; idx
++ ) {
304 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
306 if ( !tIOHIDElementRef
) {
310 IOHIDElementType type
= IOHIDElementGetType( tIOHIDElementRef
);
312 case kIOHIDElementTypeInput_Misc
:
313 case kIOHIDElementTypeInput_Button
:
314 case kIOHIDElementTypeInput_Axis
:
315 case kIOHIDElementTypeInput_ScanCodes
:
317 if ( typeMask
& kHIDElementTypeInput
) {
323 case kIOHIDElementTypeOutput
:
325 if ( typeMask
& kHIDElementTypeOutput
) {
331 case kIOHIDElementTypeFeature
:
333 if ( typeMask
& kHIDElementTypeFeature
) {
339 case kIOHIDElementTypeCollection
:
341 if ( typeMask
& kHIDElementTypeCollection
) {
348 CFRelease( gElementCFArrayRef
);
349 gElementCFArrayRef
= NULL
;
350 } // if ( gElementCFArrayRef )
351 } // if ( inIOHIDDeviceRef )
353 } /* HIDCountDeviceElements */
355 // ---------------------------------
357 // get the first device in the device list
358 // returns NULL if no list exists or it's empty
360 IOHIDDeviceRef
HIDGetFirstDevice( void )
362 IOHIDDeviceRef result
= NULL
;
366 if ( gDeviceCFArrayRef
) {
367 CFIndex count
= CFArrayGetCount( gDeviceCFArrayRef
);
369 if ( ( gDeviceIndex
>= 0 ) && ( gDeviceIndex
< count
) ) {
370 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
374 } /* HIDGetFirstDevice */
376 // ---------------------------------
378 // get next device in list given current device as parameter
379 // returns NULL if end of list
381 IOHIDDeviceRef
HIDGetNextDevice( IOHIDDeviceRef inIOHIDDeviceRef
)
383 IOHIDDeviceRef result
= NULL
;
385 if ( gDeviceCFArrayRef
&& inIOHIDDeviceRef
) {
386 CFIndex index
, count
= CFArrayGetCount( gDeviceCFArrayRef
);
388 // quick case to verify the current device index is valid for current device
389 if ( ( gDeviceIndex
>= 0 ) && ( gDeviceIndex
< count
) ) {
390 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
392 if ( result
&& ( result
== inIOHIDDeviceRef
) ) {
394 gDeviceIndex
++; // bump index
396 // previous index was invalid;
399 // search for current device's index
400 for ( index
= 0; index
< count
; index
++ ) {
401 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
403 if ( ( result
) && ( result
== inIOHIDDeviceRef
) ) {
404 gDeviceIndex
= index
+ 1; // found valid index; bump to next one
411 if ( ( gDeviceIndex
>= 0 ) && ( gDeviceIndex
< count
) ) {
412 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
415 } // if ( gDeviceCFArrayRef && inIOHIDDeviceRef )
417 } /* HIDGetNextDevice */
419 // ---------------------------------
421 // get the first element of device passed in as parameter
422 // returns NULL if no list exists or device does not exists or is NULL
423 IOHIDElementRef
HIDGetFirstDeviceElement( IOHIDDeviceRef inIOHIDDeviceRef
, HIDElementTypeMask typeMask
)
425 IOHIDElementRef result
= NULL
;
427 if ( inIOHIDDeviceRef
) {
428 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
430 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements( inIOHIDDeviceRef
, NULL
, kIOHIDOptionsTypeNone
);
432 if ( gElementCFArrayRef
) {
433 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
434 for ( idx
= 0; idx
< cnt
; idx
++ ) {
435 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
437 if ( !tIOHIDElementRef
) {
441 IOHIDElementType type
= IOHIDElementGetType( tIOHIDElementRef
);
443 case kIOHIDElementTypeInput_Misc
:
444 case kIOHIDElementTypeInput_Button
:
445 case kIOHIDElementTypeInput_Axis
:
446 case kIOHIDElementTypeInput_ScanCodes
:
448 if ( typeMask
& kHIDElementTypeInput
) {
449 result
= tIOHIDElementRef
;
454 case kIOHIDElementTypeOutput
:
456 if ( typeMask
& kHIDElementTypeOutput
) {
457 result
= tIOHIDElementRef
;
462 case kIOHIDElementTypeFeature
:
464 if ( typeMask
& kHIDElementTypeFeature
) {
465 result
= tIOHIDElementRef
;
470 case kIOHIDElementTypeCollection
:
472 if ( typeMask
& kHIDElementTypeCollection
) {
473 result
= tIOHIDElementRef
;
483 CFRelease( gElementCFArrayRef
);
484 gElementCFArrayRef
= NULL
;
485 } // if ( gElementCFArrayRef )
486 } // if ( inIOHIDDeviceRef )
488 } /* HIDGetFirstDeviceElement */
490 // ---------------------------------
492 // get next element of given device in list given current element as parameter
493 // will walk down each collection then to next element or collection (depthwise traverse)
494 // returns NULL if end of list
495 // uses mask of HIDElementTypeMask to restrict element found
496 // use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality
497 IOHIDElementRef
HIDGetNextDeviceElement( IOHIDElementRef inIOHIDElementRef
, HIDElementTypeMask typeMask
)
499 IOHIDElementRef result
= NULL
;
501 if ( inIOHIDElementRef
) {
502 assert( IOHIDElementGetTypeID() == CFGetTypeID( inIOHIDElementRef
) );
504 IOHIDDeviceRef tIOHIDDeviceRef
= IOHIDElementGetDevice( inIOHIDElementRef
);
506 if ( tIOHIDDeviceRef
) {
507 Boolean found
= FALSE
;
509 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef
, NULL
, kIOHIDOptionsTypeNone
);
511 if ( gElementCFArrayRef
) {
512 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
513 for ( idx
= 0; idx
< cnt
; idx
++ ) {
514 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
516 if ( !tIOHIDElementRef
) {
521 if ( inIOHIDElementRef
== tIOHIDElementRef
) {
524 continue; // next element
526 // we've found the current element; now find the next one of the right type
527 IOHIDElementType type
= IOHIDElementGetType( tIOHIDElementRef
);
529 case kIOHIDElementTypeInput_Misc
:
530 case kIOHIDElementTypeInput_Button
:
531 case kIOHIDElementTypeInput_Axis
:
532 case kIOHIDElementTypeInput_ScanCodes
:
534 if ( typeMask
& kHIDElementTypeInput
) {
535 result
= tIOHIDElementRef
;
540 case kIOHIDElementTypeOutput
:
542 if ( typeMask
& kHIDElementTypeOutput
) {
543 result
= tIOHIDElementRef
;
548 case kIOHIDElementTypeFeature
:
550 if ( typeMask
& kHIDElementTypeFeature
) {
551 result
= tIOHIDElementRef
;
556 case kIOHIDElementTypeCollection
:
558 if ( typeMask
& kHIDElementTypeCollection
) {
559 result
= tIOHIDElementRef
;
570 CFRelease( gElementCFArrayRef
);
571 gElementCFArrayRef
= NULL
;
572 } // if ( gElementCFArrayRef )
573 } // if ( inIOHIDDeviceRef )
574 } // if ( inIOHIDElementRef )
576 } /* HIDGetNextDeviceElement */
579 // ---------------------------------
580 // get previous element of given device in list given current element as parameter
581 // this wlaks directly up the tree to the top element and does not search at each level
582 // returns NULL if beginning of list
583 // uses mask of HIDElementTypeMask to restrict element found
584 // use kHIDElementTypeIO to get non-collection elements
585 IOHIDElementRef
HIDGetPreviousDeviceElement( IOHIDElementRef pElement
, HIDElementTypeMask typeMask
)
587 IOHIDElementRef pPreviousElement
= pElement
->pPrevious
;
588 // walk back up tree to element prior
589 while ( pPreviousElement
&& !HIDMatchElementTypeMask( pPreviousElement
->type
, typeMask
) ) {
590 pElement
= pPreviousElement
; // look at previous element
591 pPreviousElement
= pElement
->pPrevious
;
593 return pPreviousElement
; // return this element
594 } /* HIDGetPreviousDeviceElement */
598 // utility routine to dump device info
599 void HIDDumpDeviceInfo( IOHIDDeviceRef inIOHIDDeviceRef
)
603 printf( "Device: %p = { ", inIOHIDDeviceRef
);
605 char manufacturer
[256] = ""; // name of manufacturer
606 CFStringRef tCFStringRef
= IOHIDDevice_GetManufacturer( inIOHIDDeviceRef
);
608 if ( tCFStringRef
) {
609 verify( CFStringGetCString( tCFStringRef
, manufacturer
, sizeof( manufacturer
), kCFStringEncodingUTF8
) );
612 char product
[256] = ""; // name of product
613 tCFStringRef
= IOHIDDevice_GetProduct( inIOHIDDeviceRef
);
615 if ( tCFStringRef
) {
616 verify( CFStringGetCString( tCFStringRef
, product
, sizeof( product
), kCFStringEncodingUTF8
) );
619 printf( "%s - %s, ", manufacturer
, product
);
621 long vendorID
= IOHIDDevice_GetVendorID( inIOHIDDeviceRef
);
625 printf( " vendorID: 0x%04lX, ", vendorID
);
627 if ( HIDGetVendorNameFromVendorID( vendorID
, cstring
) ) {
628 printf( " vendorID: 0x%04lX (\"%s\"), ", vendorID
, cstring
);
630 printf( " vendorID: 0x%04lX, ", vendorID
);
635 long productID
= IOHIDDevice_GetProductID( inIOHIDDeviceRef
);
639 printf( " productID: 0x%04lX, ", productID
);
642 if ( HIDGetProductNameFromVendorProductID( vendorID
, productID
, cstring
) ) {
643 printf( " productID: 0x%04lX (\"%s\"), ", productID
, cstring
);
645 printf( " productID: 0x%04lX, ", productID
);
650 uint32_t usagePage
= IOHIDDevice_GetUsagePage( inIOHIDDeviceRef
);
651 uint32_t usage
= IOHIDDevice_GetUsage( inIOHIDDeviceRef
);
653 if ( !usagePage
|| !usage
) {
654 usagePage
= IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef
);
655 usage
= IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef
);
658 printf( "usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage
, (long unsigned int) usage
);
661 tCFStringRef
= HIDCopyUsageName( usagePage
, usage
);
662 if ( tCFStringRef
) {
663 verify( CFStringGetCString( tCFStringRef
, cstring
, sizeof( cstring
), kCFStringEncodingUTF8
) );
664 printf( "\"%s\", ", cstring
);
665 CFRelease( tCFStringRef
);
670 tCFStringRef
= IOHIDDevice_GetTransport( inIOHIDDeviceRef
);
671 if ( tCFStringRef
) {
672 verify( CFStringGetCString( tCFStringRef
, cstring
, sizeof( cstring
), kCFStringEncodingUTF8
) );
673 printf( "Transport: \"%s\", ", cstring
);
675 long vendorIDSource
= IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef
);
676 if ( vendorIDSource
) {
677 printf( "VendorIDSource: %ld, ", vendorIDSource
);
679 long version
= IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef
);
681 printf( "version: %ld, ", version
);
684 tCFStringRef
= IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef
);
685 if ( tCFStringRef
) {
686 verify( CFStringGetCString( tCFStringRef
, cstring
, sizeof( cstring
), kCFStringEncodingUTF8
) );
687 printf( "SerialNumber: \"%s\", ", cstring
);
689 long country
= IOHIDDevice_GetCountryCode( inIOHIDDeviceRef
);
691 printf( "CountryCode: %ld, ", country
);
693 long locationID
= IOHIDDevice_GetLocationID( inIOHIDDeviceRef
);
695 printf( "locationID: 0x%08lX, ", locationID
);
698 CFArrayRef pairs
= IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef
);
700 CFIndex idx
, cnt
= CFArrayGetCount(pairs
);
701 for ( idx
= 0; idx
< cnt
; idx
++ ) {
702 const void * pair
= CFArrayGetValueAtIndex(pairs
, idx
);
707 long maxInputReportSize
= IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef
);
708 if ( maxInputReportSize
) {
709 printf( "MaxInputReportSize: %ld, ", maxInputReportSize
);
712 long maxOutputReportSize
= IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef
);
713 if ( maxOutputReportSize
) {
714 printf( "MaxOutputReportSize: %ld, ", maxOutputReportSize
);
717 long maxFeatureReportSize
= IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef
);
718 if ( maxFeatureReportSize
) {
719 printf( "MaxFeatureReportSize: %ld, ", maxOutputReportSize
);
722 long reportInterval
= IOHIDDevice_GetReportInterval( inIOHIDDeviceRef
);
723 if ( reportInterval
) {
724 printf( "ReportInterval: %ld, ", reportInterval
);
727 IOHIDQueueRef queueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
729 printf( "queue: %p, ", queueRef
);
731 IOHIDTransactionRef transactionRef
= IOHIDDevice_GetTransaction( inIOHIDDeviceRef
);
732 if ( transactionRef
) {
733 printf( "transaction: %p, ", transactionRef
);
738 } // HIDDumpDeviceInfo
740 // utility routine to dump element info
741 void HIDDumpElementInfo( IOHIDElementRef inIOHIDElementRef
)
743 if ( inIOHIDElementRef
) {
744 printf( " Element: %p = { ", inIOHIDElementRef
);
746 IOHIDDeviceRef tIOHIDDeviceRef
= IOHIDElementGetDevice( inIOHIDElementRef
);
747 printf( "Device: %p, ", tIOHIDDeviceRef
);
749 IOHIDElementRef parentIOHIDElementRef
= IOHIDElementGetParent( inIOHIDElementRef
);
750 printf( "parent: %p, ", parentIOHIDElementRef
);
752 CFArrayRef childrenCFArrayRef
= IOHIDElementGetChildren( inIOHIDElementRef
);
753 printf( "children: %p: { ", childrenCFArrayRef
); fflush( stdout
);
754 CFShow( childrenCFArrayRef
); fflush( stdout
);
757 IOHIDElementCookie tIOHIDElementCookie
= IOHIDElementGetCookie( inIOHIDElementRef
);
758 printf( "cookie: %p, ", tIOHIDElementCookie
);
760 IOHIDElementType tIOHIDElementType
= IOHIDElementGetType( inIOHIDElementRef
);
761 switch ( tIOHIDElementType
) {
762 case kIOHIDElementTypeInput_Misc
: {
763 printf( "type: Misc, " );
767 case kIOHIDElementTypeInput_Button
: {
768 printf( "type: Button, " );
772 case kIOHIDElementTypeInput_Axis
: {
773 printf( "type: Axis, " );
777 case kIOHIDElementTypeInput_ScanCodes
: {
778 printf( "type: ScanCodes, " );
782 case kIOHIDElementTypeOutput
: {
783 printf( "type: Output, " );
787 case kIOHIDElementTypeFeature
: {
788 printf( "type: Feature, " );
792 case kIOHIDElementTypeCollection
: {
793 IOHIDElementCollectionType tIOHIDElementCollectionType
= IOHIDElementGetCollectionType( inIOHIDElementRef
);
794 switch (tIOHIDElementCollectionType
) {
795 case kIOHIDElementCollectionTypePhysical
: {
796 printf( "type: Physical Collection, " );
799 case kIOHIDElementCollectionTypeApplication
: {
800 printf( "type: Application Collection, " );
804 case kIOHIDElementCollectionTypeLogical
: {
805 printf( "type: Logical Collection, " );
809 case kIOHIDElementCollectionTypeReport
: {
810 printf( "type: Report Collection, " );
814 case kIOHIDElementCollectionTypeNamedArray
: {
815 printf( "type: Named Array Collection, " );
819 case kIOHIDElementCollectionTypeUsageSwitch
: {
820 printf( "type: Usage Switch Collection, " );
824 case kIOHIDElementCollectionTypeUsageModifier
: {
825 printf( "type: Usage Modifier Collection, " );
830 printf( "type: %p Collection, ", (void*) tIOHIDElementCollectionType
);
838 printf( "type: %p, ", (void*) tIOHIDElementType
);
843 uint32_t usagePage
= IOHIDElementGetUsagePage( inIOHIDElementRef
);
844 uint32_t usage
= IOHIDElementGetUsage( inIOHIDElementRef
);
845 printf( "usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage
, (long unsigned int) usage
);
847 CFStringRef tCFStringRef
= HIDCopyUsageName( usagePage
, usage
);
849 if ( tCFStringRef
) {
850 char usageString
[256] = "";
851 verify( CFStringGetCString( tCFStringRef
, usageString
, sizeof( usageString
), kCFStringEncodingUTF8
) );
852 printf( "\"%s\", ", usageString
);
853 CFRelease( tCFStringRef
);
856 CFStringRef nameCFStringRef
= IOHIDElementGetName( inIOHIDElementRef
);
859 if ( nameCFStringRef
&& CFStringGetCString( nameCFStringRef
, buffer
, sizeof( buffer
), kCFStringEncodingUTF8
) ) {
860 printf( "name: %s, ", buffer
);
863 uint32_t reportID
= IOHIDElementGetReportID( inIOHIDElementRef
);
864 uint32_t reportSize
= IOHIDElementGetReportSize( inIOHIDElementRef
);
865 uint32_t reportCount
= IOHIDElementGetReportCount( inIOHIDElementRef
);
866 printf( "report: { ID: %lu, Size: %lu, Count: %lu }, ",
867 (long unsigned int) reportID
, (long unsigned int) reportSize
, (long unsigned int) reportCount
);
869 uint32_t unit
= IOHIDElementGetUnit( inIOHIDElementRef
);
870 uint32_t unitExp
= IOHIDElementGetUnitExponent( inIOHIDElementRef
);
872 if ( unit
|| unitExp
) {
873 printf( "unit: %lu * 10^%lu, ", (long unsigned int) unit
, (long unsigned int) unitExp
);
876 CFIndex logicalMin
= IOHIDElementGetLogicalMin( inIOHIDElementRef
);
877 CFIndex logicalMax
= IOHIDElementGetLogicalMax( inIOHIDElementRef
);
879 if ( logicalMin
!= logicalMax
) {
880 printf( "logical: {min: %ld, max: %ld}, ", logicalMin
, logicalMax
);
883 CFIndex physicalMin
= IOHIDElementGetPhysicalMin( inIOHIDElementRef
);
884 CFIndex physicalMax
= IOHIDElementGetPhysicalMax( inIOHIDElementRef
);
886 if ( physicalMin
!= physicalMax
) {
887 printf( "physical: {min: %ld, max: %ld}, ", physicalMin
, physicalMax
);
890 Boolean isVirtual
= IOHIDElementIsVirtual( inIOHIDElementRef
);
893 printf( "isVirtual, " );
896 Boolean isRelative
= IOHIDElementIsRelative( inIOHIDElementRef
);
899 printf( "isRelative, " );
902 Boolean isWrapping
= IOHIDElementIsWrapping( inIOHIDElementRef
);
905 printf( "isWrapping, " );
908 Boolean isArray
= IOHIDElementIsArray( inIOHIDElementRef
);
911 printf( "isArray, " );
914 Boolean isNonLinear
= IOHIDElementIsNonLinear( inIOHIDElementRef
);
917 printf( "isNonLinear, " );
920 Boolean hasPreferredState
= IOHIDElementHasPreferredState( inIOHIDElementRef
);
922 if ( hasPreferredState
) {
923 printf( "hasPreferredState, " );
926 Boolean hasNullState
= IOHIDElementHasNullState( inIOHIDElementRef
);
928 if ( hasNullState
) {
929 printf( "hasNullState, " );
934 } // HIDDumpElementInfo
936 void HIDDumpElementCalibrationInfo( IOHIDElementRef inIOHIDElementRef
)
938 printf( " Element: %p = { ", inIOHIDElementRef
);
940 CFIndex calMin
= IOHIDElement_GetCalibrationMin(inIOHIDElementRef
);
941 CFIndex calMax
= IOHIDElement_GetCalibrationMax(inIOHIDElementRef
);
942 printf( "cal: {min: %ld, max: %ld}, ", calMin
, calMax
);
944 CFIndex satMin
= IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef
);
945 CFIndex satMax
= IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef
);
946 printf( "sat: {min: %ld, max: %ld}, ", satMin
, satMax
);
948 CFIndex deadMin
= IOHIDElement_GetCalibrationDeadZoneMin(inIOHIDElementRef
);
949 CFIndex deadMax
= IOHIDElement_GetCalibrationDeadZoneMax(inIOHIDElementRef
);
950 printf( "dead: {min: %ld, max: %ld}, ", deadMin
, deadMax
);
952 double_t granularity
= IOHIDElement_GetCalibrationGranularity(inIOHIDElementRef
);
953 printf( "granularity: %6.2f }\n", granularity
);
957 //***************************************************
958 #pragma mark - local ( static ) function implementations
959 //-----------------------------------------------------
961 //*************************************************************************
963 // CFSetApplierFunctionCopyToCFArray( value, context )
965 // Purpose: CFSetApplierFunction to copy the CFSet to a CFArray
967 // Notes: called one time for each item in the CFSet
969 // Inputs: value - the current element of the CFSet
970 // context - the CFMutableArrayRef we're adding the CFSet elements to
974 static void CFSetApplierFunctionCopyToCFArray( const void *value
, void *context
)
976 // printf( "%s: 0x%08lX\n", __PRETTY_FUNCTION__, (long unsigned int) value );
977 CFArrayAppendValue( ( CFMutableArrayRef
) context
, value
);
978 } // CFSetApplierFunctionCopyToCFArray
980 // ---------------------------------
981 // used to sort the CFDevice array after copying it from the (unordered) (CF)set.
982 // we compare based on the location ID's since they're consistant (across boots & launches).
984 static CFComparisonResult
CFDeviceArrayComparatorFunction( const void *val1
, const void *val2
, void *context
)
986 #pragma unused( context )
987 CFComparisonResult result
= kCFCompareEqualTo
;
989 long loc1
= IOHIDDevice_GetLocationID( ( IOHIDDeviceRef
) val1
);
990 long loc2
= IOHIDDevice_GetLocationID( ( IOHIDDeviceRef
) val2
);
993 result
= kCFCompareLessThan
;
994 } else if ( loc1
> loc2
) {
995 result
= kCFCompareGreaterThan
;
998 } // CFDeviceArrayComparatorFunction
1000 //*************************************************************************
1002 // hu_SetUpMatchingDictionary( inUsagePage, inUsage )
1004 // Purpose: builds a matching dictionary based on usage page and usage
1006 // Notes: Only called by HIDBuildMultiDeviceList
1008 // Inputs: inUsagePage - usage page
1011 // Returns: CFMutableDictionaryRef - the matching dictionary
1014 static CFMutableDictionaryRef
hu_SetUpMatchingDictionary( UInt32 inUsagePage
, UInt32 inUsage
)
1016 // create a dictionary to add usage page/usages to
1017 CFMutableDictionaryRef refHIDMatchDictionary
= CFDictionaryCreateMutable( kCFAllocatorDefault
, 0,
1018 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1020 if ( refHIDMatchDictionary
) {
1021 if ( inUsagePage
) {
1022 // Add key for device type to refine the matching dictionary.
1023 CFNumberRef pageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
, kCFNumberIntType
, &inUsagePage
);
1025 if ( pageCFNumberRef
) {
1026 CFDictionarySetValue( refHIDMatchDictionary
,
1027 CFSTR( kIOHIDPrimaryUsagePageKey
), pageCFNumberRef
);
1028 CFRelease( pageCFNumberRef
);
1030 // note: the usage is only valid if the usage page is also defined
1032 CFNumberRef usageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
, kCFNumberIntType
, &inUsage
);
1034 if ( usageCFNumberRef
) {
1035 CFDictionarySetValue( refHIDMatchDictionary
,
1036 CFSTR( kIOHIDPrimaryUsageKey
), usageCFNumberRef
);
1037 CFRelease( usageCFNumberRef
);
1039 fprintf( stderr
, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__
);
1043 fprintf( stderr
, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__
);
1047 fprintf( stderr
, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__
);
1049 return refHIDMatchDictionary
;
1050 } // hu_SetUpMatchingDictionary