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?
105 // if ( first ) { // it appears this needs to happen every time?
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 if(gDeviceCFArrayRef
)
285 return CFArrayGetCount( gDeviceCFArrayRef
);
290 // ---------------------------------
292 // how many elements does a specific device have
293 // returns 0 if device is invlaid or NULL
295 UInt32
HIDCountDeviceElements( IOHIDDeviceRef inIOHIDDeviceRef
, HIDElementTypeMask typeMask
)
299 if ( inIOHIDDeviceRef
) {
300 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
302 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements( inIOHIDDeviceRef
, NULL
, kIOHIDOptionsTypeNone
);
304 if ( gElementCFArrayRef
) {
305 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
306 for ( idx
= 0; idx
< cnt
; idx
++ ) {
307 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
309 if ( !tIOHIDElementRef
) {
313 IOHIDElementType type
= IOHIDElementGetType( tIOHIDElementRef
);
315 case kIOHIDElementTypeInput_Misc
:
316 case kIOHIDElementTypeInput_Button
:
317 case kIOHIDElementTypeInput_Axis
:
318 case kIOHIDElementTypeInput_ScanCodes
:
320 if ( typeMask
& kHIDElementTypeInput
) {
326 case kIOHIDElementTypeOutput
:
328 if ( typeMask
& kHIDElementTypeOutput
) {
334 case kIOHIDElementTypeFeature
:
336 if ( typeMask
& kHIDElementTypeFeature
) {
342 case kIOHIDElementTypeCollection
:
344 if ( typeMask
& kHIDElementTypeCollection
) {
351 CFRelease( gElementCFArrayRef
);
352 gElementCFArrayRef
= NULL
;
353 } // if ( gElementCFArrayRef )
354 } // if ( inIOHIDDeviceRef )
356 } /* HIDCountDeviceElements */
358 // ---------------------------------
360 // get the first device in the device list
361 // returns NULL if no list exists or it's empty
363 IOHIDDeviceRef
HIDGetFirstDevice( void )
365 IOHIDDeviceRef result
= NULL
;
369 if ( gDeviceCFArrayRef
) {
370 CFIndex count
= CFArrayGetCount( gDeviceCFArrayRef
);
372 if ( ( gDeviceIndex
>= 0 ) && ( gDeviceIndex
< count
) ) {
373 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
377 } /* HIDGetFirstDevice */
379 // ---------------------------------
381 // get next device in list given current device as parameter
382 // returns NULL if end of list
384 IOHIDDeviceRef
HIDGetNextDevice( IOHIDDeviceRef inIOHIDDeviceRef
)
386 IOHIDDeviceRef result
= NULL
;
388 if ( gDeviceCFArrayRef
&& inIOHIDDeviceRef
) {
389 CFIndex index
, count
= CFArrayGetCount( gDeviceCFArrayRef
);
391 // quick case to verify the current device index is valid for current device
392 if ( ( gDeviceIndex
>= 0 ) && ( gDeviceIndex
< count
) ) {
393 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
395 if ( result
&& ( result
== inIOHIDDeviceRef
) ) {
397 gDeviceIndex
++; // bump index
399 // previous index was invalid;
402 // search for current device's index
403 for ( index
= 0; index
< count
; index
++ ) {
404 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
406 if ( ( result
) && ( result
== inIOHIDDeviceRef
) ) {
407 gDeviceIndex
= index
+ 1; // found valid index; bump to next one
414 if ( ( gDeviceIndex
>= 0 ) && ( gDeviceIndex
< count
) ) {
415 result
= ( IOHIDDeviceRef
) CFArrayGetValueAtIndex( gDeviceCFArrayRef
, gDeviceIndex
);
418 } // if ( gDeviceCFArrayRef && inIOHIDDeviceRef )
420 } /* HIDGetNextDevice */
422 // ---------------------------------
424 // get the first element of device passed in as parameter
425 // returns NULL if no list exists or device does not exists or is NULL
426 IOHIDElementRef
HIDGetFirstDeviceElement( IOHIDDeviceRef inIOHIDDeviceRef
, HIDElementTypeMask typeMask
)
428 IOHIDElementRef result
= NULL
;
430 if ( inIOHIDDeviceRef
) {
431 assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef
) );
433 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements( inIOHIDDeviceRef
, NULL
, kIOHIDOptionsTypeNone
);
435 if ( gElementCFArrayRef
) {
436 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
437 for ( idx
= 0; idx
< cnt
; idx
++ ) {
438 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
440 if ( !tIOHIDElementRef
) {
444 IOHIDElementType type
= IOHIDElementGetType( tIOHIDElementRef
);
446 case kIOHIDElementTypeInput_Misc
:
447 case kIOHIDElementTypeInput_Button
:
448 case kIOHIDElementTypeInput_Axis
:
449 case kIOHIDElementTypeInput_ScanCodes
:
451 if ( typeMask
& kHIDElementTypeInput
) {
452 result
= tIOHIDElementRef
;
457 case kIOHIDElementTypeOutput
:
459 if ( typeMask
& kHIDElementTypeOutput
) {
460 result
= tIOHIDElementRef
;
465 case kIOHIDElementTypeFeature
:
467 if ( typeMask
& kHIDElementTypeFeature
) {
468 result
= tIOHIDElementRef
;
473 case kIOHIDElementTypeCollection
:
475 if ( typeMask
& kHIDElementTypeCollection
) {
476 result
= tIOHIDElementRef
;
486 CFRelease( gElementCFArrayRef
);
487 gElementCFArrayRef
= NULL
;
488 } // if ( gElementCFArrayRef )
489 } // if ( inIOHIDDeviceRef )
491 } /* HIDGetFirstDeviceElement */
493 // ---------------------------------
495 // get next element of given device in list given current element as parameter
496 // will walk down each collection then to next element or collection (depthwise traverse)
497 // returns NULL if end of list
498 // uses mask of HIDElementTypeMask to restrict element found
499 // use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality
500 IOHIDElementRef
HIDGetNextDeviceElement( IOHIDElementRef inIOHIDElementRef
, HIDElementTypeMask typeMask
)
502 IOHIDElementRef result
= NULL
;
504 if ( inIOHIDElementRef
) {
505 assert( IOHIDElementGetTypeID() == CFGetTypeID( inIOHIDElementRef
) );
507 IOHIDDeviceRef tIOHIDDeviceRef
= IOHIDElementGetDevice( inIOHIDElementRef
);
509 if ( tIOHIDDeviceRef
) {
510 Boolean found
= FALSE
;
512 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef
, NULL
, kIOHIDOptionsTypeNone
);
514 if ( gElementCFArrayRef
) {
515 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
516 for ( idx
= 0; idx
< cnt
; idx
++ ) {
517 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
519 if ( !tIOHIDElementRef
) {
524 if ( inIOHIDElementRef
== tIOHIDElementRef
) {
527 continue; // next element
529 // we've found the current element; now find the next one of the right type
530 IOHIDElementType type
= IOHIDElementGetType( tIOHIDElementRef
);
532 case kIOHIDElementTypeInput_Misc
:
533 case kIOHIDElementTypeInput_Button
:
534 case kIOHIDElementTypeInput_Axis
:
535 case kIOHIDElementTypeInput_ScanCodes
:
537 if ( typeMask
& kHIDElementTypeInput
) {
538 result
= tIOHIDElementRef
;
543 case kIOHIDElementTypeOutput
:
545 if ( typeMask
& kHIDElementTypeOutput
) {
546 result
= tIOHIDElementRef
;
551 case kIOHIDElementTypeFeature
:
553 if ( typeMask
& kHIDElementTypeFeature
) {
554 result
= tIOHIDElementRef
;
559 case kIOHIDElementTypeCollection
:
561 if ( typeMask
& kHIDElementTypeCollection
) {
562 result
= tIOHIDElementRef
;
573 CFRelease( gElementCFArrayRef
);
574 gElementCFArrayRef
= NULL
;
575 } // if ( gElementCFArrayRef )
576 } // if ( inIOHIDDeviceRef )
577 } // if ( inIOHIDElementRef )
579 } /* HIDGetNextDeviceElement */
582 // ---------------------------------
583 // get previous element of given device in list given current element as parameter
584 // this wlaks directly up the tree to the top element and does not search at each level
585 // returns NULL if beginning of list
586 // uses mask of HIDElementTypeMask to restrict element found
587 // use kHIDElementTypeIO to get non-collection elements
588 IOHIDElementRef
HIDGetPreviousDeviceElement( IOHIDElementRef pElement
, HIDElementTypeMask typeMask
)
590 IOHIDElementRef pPreviousElement
= pElement
->pPrevious
;
591 // walk back up tree to element prior
592 while ( pPreviousElement
&& !HIDMatchElementTypeMask( pPreviousElement
->type
, typeMask
) ) {
593 pElement
= pPreviousElement
; // look at previous element
594 pPreviousElement
= pElement
->pPrevious
;
596 return pPreviousElement
; // return this element
597 } /* HIDGetPreviousDeviceElement */
601 // utility routine to dump device info
602 void HIDDumpDeviceInfo( IOHIDDeviceRef inIOHIDDeviceRef
)
606 printf( "Device: %p = { ", inIOHIDDeviceRef
);
608 char manufacturer
[256] = ""; // name of manufacturer
609 CFStringRef tCFStringRef
= IOHIDDevice_GetManufacturer( inIOHIDDeviceRef
);
611 if ( tCFStringRef
) {
612 verify( CFStringGetCString( tCFStringRef
, manufacturer
, sizeof( manufacturer
), kCFStringEncodingUTF8
) );
615 char product
[256] = ""; // name of product
616 tCFStringRef
= IOHIDDevice_GetProduct( inIOHIDDeviceRef
);
618 if ( tCFStringRef
) {
619 verify( CFStringGetCString( tCFStringRef
, product
, sizeof( product
), kCFStringEncodingUTF8
) );
622 printf( "%s - %s, ", manufacturer
, product
);
624 long vendorID
= IOHIDDevice_GetVendorID( inIOHIDDeviceRef
);
628 printf( " vendorID: 0x%04lX, ", vendorID
);
630 if ( HIDGetVendorNameFromVendorID( vendorID
, cstring
) ) {
631 printf( " vendorID: 0x%04lX (\"%s\"), ", vendorID
, cstring
);
633 printf( " vendorID: 0x%04lX, ", vendorID
);
638 long productID
= IOHIDDevice_GetProductID( inIOHIDDeviceRef
);
642 printf( " productID: 0x%04lX, ", productID
);
645 if ( HIDGetProductNameFromVendorProductID( vendorID
, productID
, cstring
) ) {
646 printf( " productID: 0x%04lX (\"%s\"), ", productID
, cstring
);
648 printf( " productID: 0x%04lX, ", productID
);
653 uint32_t usagePage
= IOHIDDevice_GetUsagePage( inIOHIDDeviceRef
);
654 uint32_t usage
= IOHIDDevice_GetUsage( inIOHIDDeviceRef
);
656 if ( !usagePage
|| !usage
) {
657 usagePage
= IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef
);
658 usage
= IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef
);
661 printf( "usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage
, (long unsigned int) usage
);
664 tCFStringRef
= HIDCopyUsageName( usagePage
, usage
);
665 if ( tCFStringRef
) {
666 verify( CFStringGetCString( tCFStringRef
, cstring
, sizeof( cstring
), kCFStringEncodingUTF8
) );
667 printf( "\"%s\", ", cstring
);
668 CFRelease( tCFStringRef
);
673 tCFStringRef
= IOHIDDevice_GetTransport( inIOHIDDeviceRef
);
674 if ( tCFStringRef
) {
675 verify( CFStringGetCString( tCFStringRef
, cstring
, sizeof( cstring
), kCFStringEncodingUTF8
) );
676 printf( "Transport: \"%s\", ", cstring
);
678 long vendorIDSource
= IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef
);
679 if ( vendorIDSource
) {
680 printf( "VendorIDSource: %ld, ", vendorIDSource
);
682 long version
= IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef
);
684 printf( "version: %ld, ", version
);
687 tCFStringRef
= IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef
);
688 if ( tCFStringRef
) {
689 verify( CFStringGetCString( tCFStringRef
, cstring
, sizeof( cstring
), kCFStringEncodingUTF8
) );
690 printf( "SerialNumber: \"%s\", ", cstring
);
692 long country
= IOHIDDevice_GetCountryCode( inIOHIDDeviceRef
);
694 printf( "CountryCode: %ld, ", country
);
696 long locationID
= IOHIDDevice_GetLocationID( inIOHIDDeviceRef
);
698 printf( "locationID: 0x%08lX, ", locationID
);
701 CFArrayRef pairs
= IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef
);
703 CFIndex idx
, cnt
= CFArrayGetCount(pairs
);
704 for ( idx
= 0; idx
< cnt
; idx
++ ) {
705 const void * pair
= CFArrayGetValueAtIndex(pairs
, idx
);
710 long maxInputReportSize
= IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef
);
711 if ( maxInputReportSize
) {
712 printf( "MaxInputReportSize: %ld, ", maxInputReportSize
);
715 long maxOutputReportSize
= IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef
);
716 if ( maxOutputReportSize
) {
717 printf( "MaxOutputReportSize: %ld, ", maxOutputReportSize
);
720 long maxFeatureReportSize
= IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef
);
721 if ( maxFeatureReportSize
) {
722 printf( "MaxFeatureReportSize: %ld, ", maxOutputReportSize
);
725 long reportInterval
= IOHIDDevice_GetReportInterval( inIOHIDDeviceRef
);
726 if ( reportInterval
) {
727 printf( "ReportInterval: %ld, ", reportInterval
);
730 IOHIDQueueRef queueRef
= IOHIDDevice_GetQueue( inIOHIDDeviceRef
);
732 printf( "queue: %p, ", queueRef
);
734 IOHIDTransactionRef transactionRef
= IOHIDDevice_GetTransaction( inIOHIDDeviceRef
);
735 if ( transactionRef
) {
736 printf( "transaction: %p, ", transactionRef
);
741 } // HIDDumpDeviceInfo
743 // utility routine to dump element info
744 void HIDDumpElementInfo( IOHIDElementRef inIOHIDElementRef
)
746 if ( inIOHIDElementRef
) {
747 printf( " Element: %p = { ", inIOHIDElementRef
);
749 IOHIDDeviceRef tIOHIDDeviceRef
= IOHIDElementGetDevice( inIOHIDElementRef
);
750 printf( "Device: %p, ", tIOHIDDeviceRef
);
752 IOHIDElementRef parentIOHIDElementRef
= IOHIDElementGetParent( inIOHIDElementRef
);
753 printf( "parent: %p, ", parentIOHIDElementRef
);
755 CFArrayRef childrenCFArrayRef
= IOHIDElementGetChildren( inIOHIDElementRef
);
756 printf( "children: %p: { ", childrenCFArrayRef
); fflush( stdout
);
757 CFShow( childrenCFArrayRef
); fflush( stdout
);
760 IOHIDElementCookie tIOHIDElementCookie
= IOHIDElementGetCookie( inIOHIDElementRef
);
761 printf( "cookie: %p, ", tIOHIDElementCookie
);
763 IOHIDElementType tIOHIDElementType
= IOHIDElementGetType( inIOHIDElementRef
);
764 switch ( tIOHIDElementType
) {
765 case kIOHIDElementTypeInput_Misc
: {
766 printf( "type: Misc, " );
770 case kIOHIDElementTypeInput_Button
: {
771 printf( "type: Button, " );
775 case kIOHIDElementTypeInput_Axis
: {
776 printf( "type: Axis, " );
780 case kIOHIDElementTypeInput_ScanCodes
: {
781 printf( "type: ScanCodes, " );
785 case kIOHIDElementTypeOutput
: {
786 printf( "type: Output, " );
790 case kIOHIDElementTypeFeature
: {
791 printf( "type: Feature, " );
795 case kIOHIDElementTypeCollection
: {
796 IOHIDElementCollectionType tIOHIDElementCollectionType
= IOHIDElementGetCollectionType( inIOHIDElementRef
);
797 switch (tIOHIDElementCollectionType
) {
798 case kIOHIDElementCollectionTypePhysical
: {
799 printf( "type: Physical Collection, " );
802 case kIOHIDElementCollectionTypeApplication
: {
803 printf( "type: Application Collection, " );
807 case kIOHIDElementCollectionTypeLogical
: {
808 printf( "type: Logical Collection, " );
812 case kIOHIDElementCollectionTypeReport
: {
813 printf( "type: Report Collection, " );
817 case kIOHIDElementCollectionTypeNamedArray
: {
818 printf( "type: Named Array Collection, " );
822 case kIOHIDElementCollectionTypeUsageSwitch
: {
823 printf( "type: Usage Switch Collection, " );
827 case kIOHIDElementCollectionTypeUsageModifier
: {
828 printf( "type: Usage Modifier Collection, " );
833 printf( "type: %p Collection, ", (void*) tIOHIDElementCollectionType
);
841 printf( "type: %p, ", (void*) tIOHIDElementType
);
846 uint32_t usagePage
= IOHIDElementGetUsagePage( inIOHIDElementRef
);
847 uint32_t usage
= IOHIDElementGetUsage( inIOHIDElementRef
);
848 printf( "usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage
, (long unsigned int) usage
);
850 CFStringRef tCFStringRef
= HIDCopyUsageName( usagePage
, usage
);
852 if ( tCFStringRef
) {
853 char usageString
[256] = "";
854 verify( CFStringGetCString( tCFStringRef
, usageString
, sizeof( usageString
), kCFStringEncodingUTF8
) );
855 printf( "\"%s\", ", usageString
);
856 CFRelease( tCFStringRef
);
859 CFStringRef nameCFStringRef
= IOHIDElementGetName( inIOHIDElementRef
);
862 if ( nameCFStringRef
&& CFStringGetCString( nameCFStringRef
, buffer
, sizeof( buffer
), kCFStringEncodingUTF8
) ) {
863 printf( "name: %s, ", buffer
);
866 uint32_t reportID
= IOHIDElementGetReportID( inIOHIDElementRef
);
867 uint32_t reportSize
= IOHIDElementGetReportSize( inIOHIDElementRef
);
868 uint32_t reportCount
= IOHIDElementGetReportCount( inIOHIDElementRef
);
869 printf( "report: { ID: %lu, Size: %lu, Count: %lu }, ",
870 (long unsigned int) reportID
, (long unsigned int) reportSize
, (long unsigned int) reportCount
);
872 uint32_t unit
= IOHIDElementGetUnit( inIOHIDElementRef
);
873 uint32_t unitExp
= IOHIDElementGetUnitExponent( inIOHIDElementRef
);
875 if ( unit
|| unitExp
) {
876 printf( "unit: %lu * 10^%lu, ", (long unsigned int) unit
, (long unsigned int) unitExp
);
879 CFIndex logicalMin
= IOHIDElementGetLogicalMin( inIOHIDElementRef
);
880 CFIndex logicalMax
= IOHIDElementGetLogicalMax( inIOHIDElementRef
);
882 if ( logicalMin
!= logicalMax
) {
883 printf( "logical: {min: %ld, max: %ld}, ", logicalMin
, logicalMax
);
886 CFIndex physicalMin
= IOHIDElementGetPhysicalMin( inIOHIDElementRef
);
887 CFIndex physicalMax
= IOHIDElementGetPhysicalMax( inIOHIDElementRef
);
889 if ( physicalMin
!= physicalMax
) {
890 printf( "physical: {min: %ld, max: %ld}, ", physicalMin
, physicalMax
);
893 Boolean isVirtual
= IOHIDElementIsVirtual( inIOHIDElementRef
);
896 printf( "isVirtual, " );
899 Boolean isRelative
= IOHIDElementIsRelative( inIOHIDElementRef
);
902 printf( "isRelative, " );
905 Boolean isWrapping
= IOHIDElementIsWrapping( inIOHIDElementRef
);
908 printf( "isWrapping, " );
911 Boolean isArray
= IOHIDElementIsArray( inIOHIDElementRef
);
914 printf( "isArray, " );
917 Boolean isNonLinear
= IOHIDElementIsNonLinear( inIOHIDElementRef
);
920 printf( "isNonLinear, " );
923 Boolean hasPreferredState
= IOHIDElementHasPreferredState( inIOHIDElementRef
);
925 if ( hasPreferredState
) {
926 printf( "hasPreferredState, " );
929 Boolean hasNullState
= IOHIDElementHasNullState( inIOHIDElementRef
);
931 if ( hasNullState
) {
932 printf( "hasNullState, " );
937 } // HIDDumpElementInfo
939 void HIDDumpElementCalibrationInfo( IOHIDElementRef inIOHIDElementRef
)
941 printf( " Element: %p = { ", inIOHIDElementRef
);
943 CFIndex calMin
= IOHIDElement_GetCalibrationMin(inIOHIDElementRef
);
944 CFIndex calMax
= IOHIDElement_GetCalibrationMax(inIOHIDElementRef
);
945 printf( "cal: {min: %ld, max: %ld}, ", calMin
, calMax
);
947 CFIndex satMin
= IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef
);
948 CFIndex satMax
= IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef
);
949 printf( "sat: {min: %ld, max: %ld}, ", satMin
, satMax
);
951 CFIndex deadMin
= IOHIDElement_GetCalibrationDeadZoneMin(inIOHIDElementRef
);
952 CFIndex deadMax
= IOHIDElement_GetCalibrationDeadZoneMax(inIOHIDElementRef
);
953 printf( "dead: {min: %ld, max: %ld}, ", deadMin
, deadMax
);
955 double_t granularity
= IOHIDElement_GetCalibrationGranularity(inIOHIDElementRef
);
956 printf( "granularity: %6.2f }\n", granularity
);
960 //***************************************************
961 #pragma mark - local ( static ) function implementations
962 //-----------------------------------------------------
964 //*************************************************************************
966 // CFSetApplierFunctionCopyToCFArray( value, context )
968 // Purpose: CFSetApplierFunction to copy the CFSet to a CFArray
970 // Notes: called one time for each item in the CFSet
972 // Inputs: value - the current element of the CFSet
973 // context - the CFMutableArrayRef we're adding the CFSet elements to
977 static void CFSetApplierFunctionCopyToCFArray( const void *value
, void *context
)
979 // printf( "%s: 0x%08lX\n", __PRETTY_FUNCTION__, (long unsigned int) value );
980 CFArrayAppendValue( ( CFMutableArrayRef
) context
, value
);
981 } // CFSetApplierFunctionCopyToCFArray
983 // ---------------------------------
984 // used to sort the CFDevice array after copying it from the (unordered) (CF)set.
985 // we compare based on the location ID's since they're consistant (across boots & launches).
987 static CFComparisonResult
CFDeviceArrayComparatorFunction( const void *val1
, const void *val2
, void *context
)
989 #pragma unused( context )
990 CFComparisonResult result
= kCFCompareEqualTo
;
992 long loc1
= IOHIDDevice_GetLocationID( ( IOHIDDeviceRef
) val1
);
993 long loc2
= IOHIDDevice_GetLocationID( ( IOHIDDeviceRef
) val2
);
996 result
= kCFCompareLessThan
;
997 } else if ( loc1
> loc2
) {
998 result
= kCFCompareGreaterThan
;
1001 } // CFDeviceArrayComparatorFunction
1003 //*************************************************************************
1005 // hu_SetUpMatchingDictionary( inUsagePage, inUsage )
1007 // Purpose: builds a matching dictionary based on usage page and usage
1009 // Notes: Only called by HIDBuildMultiDeviceList
1011 // Inputs: inUsagePage - usage page
1014 // Returns: CFMutableDictionaryRef - the matching dictionary
1017 static CFMutableDictionaryRef
hu_SetUpMatchingDictionary( UInt32 inUsagePage
, UInt32 inUsage
)
1019 // create a dictionary to add usage page/usages to
1020 CFMutableDictionaryRef refHIDMatchDictionary
= CFDictionaryCreateMutable( kCFAllocatorDefault
, 0,
1021 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1023 if ( refHIDMatchDictionary
) {
1024 if ( inUsagePage
) {
1025 // Add key for device type to refine the matching dictionary.
1026 CFNumberRef pageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
, kCFNumberIntType
, &inUsagePage
);
1028 if ( pageCFNumberRef
) {
1029 CFDictionarySetValue( refHIDMatchDictionary
,
1030 CFSTR( kIOHIDPrimaryUsagePageKey
), pageCFNumberRef
);
1031 CFRelease( pageCFNumberRef
);
1033 // note: the usage is only valid if the usage page is also defined
1035 CFNumberRef usageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
, kCFNumberIntType
, &inUsage
);
1037 if ( usageCFNumberRef
) {
1038 CFDictionarySetValue( refHIDMatchDictionary
,
1039 CFSTR( kIOHIDPrimaryUsageKey
), usageCFNumberRef
);
1040 CFRelease( usageCFNumberRef
);
1042 fprintf( stderr
, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__
);
1046 fprintf( stderr
, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__
);
1050 fprintf( stderr
, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__
);
1052 return refHIDMatchDictionary
;
1053 } // hu_SetUpMatchingDictionary