Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangPrimSource / HID_Utilities / HID_Utilities.c
blobd767edf8f8adae224eb9e5c93cba6ad0bc5dc9b7
1 //
2 // File: HID_Utilities.c
3 //
4 // Contains: Implementation of the HID utilities
5 //
6 // Copyright © 2007-2009 Apple Inc., All Rights Reserved
7 //
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
58 // generic ones
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;
77 CFIndex gDeviceIndex;
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 );
108 // }
110 if ( gIOHIDManagerRef ) {
111 CFMutableArrayRef hidMatchingCFMutableArrayRef = NULL;
113 if ( inUsages && inUsagePages && inNumDeviceTypes ) {
114 hidMatchingCFMutableArrayRef = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
116 if ( hidMatchingCFMutableArrayRef ) {
117 int idx;
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 );
125 } else {
126 fprintf( stderr, "%s: Couldn’t create a matching dictionary.", __PRETTY_FUNCTION__ );
129 } else {
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 );
141 if ( first ) {
142 // open it
143 IOReturn tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, kIOHIDOptionsTypeNone );
145 if ( kIOReturnSuccess != tIOReturn ) {
146 fprintf( stderr, "%s: Couldn’t open IOHIDManager.", __PRETTY_FUNCTION__ );
147 goto Oops;
150 HIDRebuildDevices( );
151 result = TRUE;
152 } else {
153 fprintf( stderr, "%s: Couldn’t create a IOHIDManager.", __PRETTY_FUNCTION__ );
155 Oops: ;
156 return result;
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
174 * inUsage - usages
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
214 * Inputs: none
216 * Returns: none
219 void HIDReleaseDeviceList( void )
221 if ( gDeviceCFArrayRef ) {
222 CFRelease(gDeviceCFArrayRef);
223 gDeviceCFArrayRef = NULL;
227 /*************************************************************************
229 * HIDHaveDeviceList( void )
231 * Purpose: does a device list exist?
233 * Inputs: none
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
249 // Inputs: none
251 // Returns: none
254 void HIDRebuildDevices( void ) {
255 // get the set of devices from the IOHID manager
256 CFSetRef devCFSetRef = IOHIDManagerCopyDevices( gIOHIDManagerRef );
258 if ( devCFSetRef ) {
259 // if the existing array isn't empty...
260 if ( gDeviceCFArrayRef ) {
261 // release it
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 );
286 else
287 return 0;
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 )
297 int count = 0;
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 ) {
310 continue;
313 IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
314 switch ( type ) {
315 case kIOHIDElementTypeInput_Misc:
316 case kIOHIDElementTypeInput_Button:
317 case kIOHIDElementTypeInput_Axis:
318 case kIOHIDElementTypeInput_ScanCodes:
320 if ( typeMask & kHIDElementTypeInput ) {
321 count++;
323 break;
326 case kIOHIDElementTypeOutput:
328 if ( typeMask & kHIDElementTypeOutput ) {
329 count++;
331 break;
334 case kIOHIDElementTypeFeature:
336 if ( typeMask & kHIDElementTypeFeature ) {
337 count++;
339 break;
342 case kIOHIDElementTypeCollection:
344 if ( typeMask & kHIDElementTypeCollection ) {
345 count++;
347 break;
349 } // switch ( type )
350 } // next idx
351 CFRelease( gElementCFArrayRef );
352 gElementCFArrayRef = NULL;
353 } // if ( gElementCFArrayRef )
354 } // if ( inIOHIDDeviceRef )
355 return count;
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;
367 gDeviceIndex = 0;
369 if ( gDeviceCFArrayRef ) {
370 CFIndex count = CFArrayGetCount( gDeviceCFArrayRef );
372 if ( ( gDeviceIndex >= 0 ) && ( gDeviceIndex < count ) ) {
373 result = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, gDeviceIndex );
376 return result;
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 ) ) {
396 result = NULL;
397 gDeviceIndex++; // bump index
398 } else {
399 // previous index was invalid;
400 gDeviceIndex = -1;
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
408 break;
411 result = NULL;
414 if ( ( gDeviceIndex >= 0 ) && ( gDeviceIndex < count ) ) {
415 result = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, gDeviceIndex );
417 } // if valid index
418 } // if ( gDeviceCFArrayRef && inIOHIDDeviceRef )
419 return result;
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 ) {
441 continue;
444 IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
445 switch ( type ) {
446 case kIOHIDElementTypeInput_Misc:
447 case kIOHIDElementTypeInput_Button:
448 case kIOHIDElementTypeInput_Axis:
449 case kIOHIDElementTypeInput_ScanCodes:
451 if ( typeMask & kHIDElementTypeInput ) {
452 result = tIOHIDElementRef;
454 break;
457 case kIOHIDElementTypeOutput:
459 if ( typeMask & kHIDElementTypeOutput ) {
460 result = tIOHIDElementRef;
462 break;
465 case kIOHIDElementTypeFeature:
467 if ( typeMask & kHIDElementTypeFeature ) {
468 result = tIOHIDElementRef;
470 break;
473 case kIOHIDElementTypeCollection:
475 if ( typeMask & kHIDElementTypeCollection ) {
476 result = tIOHIDElementRef;
478 break;
480 } // switch ( type )
482 if ( result ) {
483 break; // DONE!
485 } // next idx
486 CFRelease( gElementCFArrayRef );
487 gElementCFArrayRef = NULL;
488 } // if ( gElementCFArrayRef )
489 } // if ( inIOHIDDeviceRef )
490 return result;
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 ) {
520 continue;
523 if ( !found ) {
524 if ( inIOHIDElementRef == tIOHIDElementRef ) {
525 found = TRUE;
527 continue; // next element
528 } else {
529 // we've found the current element; now find the next one of the right type
530 IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
531 switch ( type ) {
532 case kIOHIDElementTypeInput_Misc:
533 case kIOHIDElementTypeInput_Button:
534 case kIOHIDElementTypeInput_Axis:
535 case kIOHIDElementTypeInput_ScanCodes:
537 if ( typeMask & kHIDElementTypeInput ) {
538 result = tIOHIDElementRef;
540 break;
543 case kIOHIDElementTypeOutput:
545 if ( typeMask & kHIDElementTypeOutput ) {
546 result = tIOHIDElementRef;
548 break;
551 case kIOHIDElementTypeFeature:
553 if ( typeMask & kHIDElementTypeFeature ) {
554 result = tIOHIDElementRef;
556 break;
559 case kIOHIDElementTypeCollection:
561 if ( typeMask & kHIDElementTypeCollection ) {
562 result = tIOHIDElementRef;
564 break;
566 } // switch ( type )
568 if ( result ) {
569 break; // DONE!
571 } // if ( !found )
572 } // next idx
573 CFRelease( gElementCFArrayRef );
574 gElementCFArrayRef = NULL;
575 } // if ( gElementCFArrayRef )
576 } // if ( inIOHIDDeviceRef )
577 } // if ( inIOHIDElementRef )
578 return result;
579 } /* HIDGetNextDeviceElement */
581 #if 0
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 */
599 #endif
601 // utility routine to dump device info
602 void HIDDumpDeviceInfo( IOHIDDeviceRef inIOHIDDeviceRef )
604 char cstring[256];
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 );
626 if ( vendorID ) {
627 #if 1
628 printf( " vendorID: 0x%04lX, ", vendorID );
629 #else
630 if ( HIDGetVendorNameFromVendorID( vendorID, cstring ) ) {
631 printf( " vendorID: 0x%04lX (\"%s\"), ", vendorID, cstring );
632 } else {
633 printf( " vendorID: 0x%04lX, ", vendorID );
635 #endif
638 long productID = IOHIDDevice_GetProductID( inIOHIDDeviceRef );
640 if ( productID ) {
641 #if 1
642 printf( " productID: 0x%04lX, ", productID );
643 #else
645 if ( HIDGetProductNameFromVendorProductID( vendorID, productID, cstring ) ) {
646 printf( " productID: 0x%04lX (\"%s\"), ", productID, cstring );
647 } else {
648 printf( " productID: 0x%04lX, ", productID );
650 #endif
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 );
663 #if 1
664 tCFStringRef = HIDCopyUsageName( usagePage, usage );
665 if ( tCFStringRef ) {
666 verify( CFStringGetCString( tCFStringRef, cstring, sizeof( cstring ), kCFStringEncodingUTF8 ) );
667 printf( "\"%s\", ", cstring );
668 CFRelease( tCFStringRef );
670 #endif
672 #if 1
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 );
683 if ( version ) {
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 );
693 if ( country ) {
694 printf( "CountryCode: %ld, ", country );
696 long locationID = IOHIDDevice_GetLocationID( inIOHIDDeviceRef );
697 if ( locationID ) {
698 printf( "locationID: 0x%08lX, ", locationID );
700 #if 0
701 CFArrayRef pairs = IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef );
702 if ( pairs ) {
703 CFIndex idx, cnt = CFArrayGetCount(pairs);
704 for ( idx = 0; idx < cnt; idx++ ) {
705 const void * pair = CFArrayGetValueAtIndex(pairs, idx);
706 CFShow( pair );
709 #endif
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 );
731 if ( queueRef ) {
732 printf( "queue: %p, ", queueRef);
734 IOHIDTransactionRef transactionRef = IOHIDDevice_GetTransaction( inIOHIDDeviceRef );
735 if ( transactionRef ) {
736 printf( "transaction: %p, ", transactionRef);
738 #endif
739 printf( "}\n" );
740 fflush( stdout );
741 } // HIDDumpDeviceInfo
743 // utility routine to dump element info
744 void HIDDumpElementInfo( IOHIDElementRef inIOHIDElementRef )
746 if ( inIOHIDElementRef ) {
747 printf( " Element: %p = { ", inIOHIDElementRef );
748 #if 0
749 IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice( inIOHIDElementRef );
750 printf( "Device: %p, ", tIOHIDDeviceRef );
751 #endif
752 IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent( inIOHIDElementRef );
753 printf( "parent: %p, ", parentIOHIDElementRef );
754 #if 0
755 CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren( inIOHIDElementRef );
756 printf( "children: %p: { ", childrenCFArrayRef ); fflush( stdout );
757 CFShow( childrenCFArrayRef ); fflush( stdout );
758 printf( " }, " );
759 #endif
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, " );
767 break;
770 case kIOHIDElementTypeInput_Button: {
771 printf( "type: Button, " );
772 break;
775 case kIOHIDElementTypeInput_Axis: {
776 printf( "type: Axis, " );
777 break;
780 case kIOHIDElementTypeInput_ScanCodes: {
781 printf( "type: ScanCodes, " );
782 break;
785 case kIOHIDElementTypeOutput: {
786 printf( "type: Output, " );
787 break;
790 case kIOHIDElementTypeFeature: {
791 printf( "type: Feature, " );
792 break;
795 case kIOHIDElementTypeCollection: {
796 IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType( inIOHIDElementRef );
797 switch (tIOHIDElementCollectionType ) {
798 case kIOHIDElementCollectionTypePhysical: {
799 printf( "type: Physical Collection, " );
800 break;
802 case kIOHIDElementCollectionTypeApplication: {
803 printf( "type: Application Collection, " );
804 break;
807 case kIOHIDElementCollectionTypeLogical: {
808 printf( "type: Logical Collection, " );
809 break;
812 case kIOHIDElementCollectionTypeReport: {
813 printf( "type: Report Collection, " );
814 break;
817 case kIOHIDElementCollectionTypeNamedArray: {
818 printf( "type: Named Array Collection, " );
819 break;
822 case kIOHIDElementCollectionTypeUsageSwitch: {
823 printf( "type: Usage Switch Collection, " );
824 break;
827 case kIOHIDElementCollectionTypeUsageModifier: {
828 printf( "type: Usage Modifier Collection, " );
829 break;
832 default: {
833 printf( "type: %p Collection, ", (void*) tIOHIDElementCollectionType );
834 break;
837 break;
840 default: {
841 printf( "type: %p, ", (void*) tIOHIDElementType );
842 break;
844 } /* switch */
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 );
849 #if 1
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 );
858 #endif
859 CFStringRef nameCFStringRef = IOHIDElementGetName( inIOHIDElementRef );
860 char buffer[256];
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 );
895 if ( isVirtual ) {
896 printf( "isVirtual, " );
899 Boolean isRelative = IOHIDElementIsRelative( inIOHIDElementRef );
901 if ( isRelative ) {
902 printf( "isRelative, " );
905 Boolean isWrapping = IOHIDElementIsWrapping( inIOHIDElementRef );
907 if ( isWrapping ) {
908 printf( "isWrapping, " );
911 Boolean isArray = IOHIDElementIsArray( inIOHIDElementRef );
913 if ( isArray ) {
914 printf( "isArray, " );
917 Boolean isNonLinear = IOHIDElementIsNonLinear( inIOHIDElementRef );
919 if ( isNonLinear ) {
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, " );
935 printf( " }\n" );
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
975 // Returns: nothing
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 );
995 if ( loc1 < loc2 ) {
996 result = kCFCompareLessThan;
997 } else if ( loc1 > loc2 ) {
998 result = kCFCompareGreaterThan;
1000 return result;
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
1012 // inUsage - usages
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
1034 if ( inUsage ) {
1035 CFNumberRef usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsage );
1037 if ( usageCFNumberRef ) {
1038 CFDictionarySetValue( refHIDMatchDictionary,
1039 CFSTR( kIOHIDPrimaryUsageKey ), usageCFNumberRef );
1040 CFRelease( usageCFNumberRef );
1041 } else {
1042 fprintf( stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__ );
1045 } else {
1046 fprintf( stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__ );
1049 } else {
1050 fprintf( stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__ );
1052 return refHIDMatchDictionary;
1053 } // hu_SetUpMatchingDictionary