supernova: fix for small audio vector sizes
[supercollider.git] / lang / LangPrimSource / HID_Utilities / HID_Utilities.c
blob6f9e056dd19d586ea4ab3b01256b817c80af142c
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 ) {
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 ) {
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 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 )
294 int count = 0;
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 ) {
307 continue;
310 IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
311 switch ( type ) {
312 case kIOHIDElementTypeInput_Misc:
313 case kIOHIDElementTypeInput_Button:
314 case kIOHIDElementTypeInput_Axis:
315 case kIOHIDElementTypeInput_ScanCodes:
317 if ( typeMask & kHIDElementTypeInput ) {
318 count++;
320 break;
323 case kIOHIDElementTypeOutput:
325 if ( typeMask & kHIDElementTypeOutput ) {
326 count++;
328 break;
331 case kIOHIDElementTypeFeature:
333 if ( typeMask & kHIDElementTypeFeature ) {
334 count++;
336 break;
339 case kIOHIDElementTypeCollection:
341 if ( typeMask & kHIDElementTypeCollection ) {
342 count++;
344 break;
346 } // switch ( type )
347 } // next idx
348 CFRelease( gElementCFArrayRef );
349 gElementCFArrayRef = NULL;
350 } // if ( gElementCFArrayRef )
351 } // if ( inIOHIDDeviceRef )
352 return count;
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;
364 gDeviceIndex = 0;
366 if ( gDeviceCFArrayRef ) {
367 CFIndex count = CFArrayGetCount( gDeviceCFArrayRef );
369 if ( ( gDeviceIndex >= 0 ) && ( gDeviceIndex < count ) ) {
370 result = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, gDeviceIndex );
373 return result;
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 ) ) {
393 result = NULL;
394 gDeviceIndex++; // bump index
395 } else {
396 // previous index was invalid;
397 gDeviceIndex = -1;
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
405 break;
408 result = NULL;
411 if ( ( gDeviceIndex >= 0 ) && ( gDeviceIndex < count ) ) {
412 result = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, gDeviceIndex );
414 } // if valid index
415 } // if ( gDeviceCFArrayRef && inIOHIDDeviceRef )
416 return result;
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 ) {
438 continue;
441 IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
442 switch ( type ) {
443 case kIOHIDElementTypeInput_Misc:
444 case kIOHIDElementTypeInput_Button:
445 case kIOHIDElementTypeInput_Axis:
446 case kIOHIDElementTypeInput_ScanCodes:
448 if ( typeMask & kHIDElementTypeInput ) {
449 result = tIOHIDElementRef;
451 break;
454 case kIOHIDElementTypeOutput:
456 if ( typeMask & kHIDElementTypeOutput ) {
457 result = tIOHIDElementRef;
459 break;
462 case kIOHIDElementTypeFeature:
464 if ( typeMask & kHIDElementTypeFeature ) {
465 result = tIOHIDElementRef;
467 break;
470 case kIOHIDElementTypeCollection:
472 if ( typeMask & kHIDElementTypeCollection ) {
473 result = tIOHIDElementRef;
475 break;
477 } // switch ( type )
479 if ( result ) {
480 break; // DONE!
482 } // next idx
483 CFRelease( gElementCFArrayRef );
484 gElementCFArrayRef = NULL;
485 } // if ( gElementCFArrayRef )
486 } // if ( inIOHIDDeviceRef )
487 return result;
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 ) {
517 continue;
520 if ( !found ) {
521 if ( inIOHIDElementRef == tIOHIDElementRef ) {
522 found = TRUE;
524 continue; // next element
525 } else {
526 // we've found the current element; now find the next one of the right type
527 IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef );
528 switch ( type ) {
529 case kIOHIDElementTypeInput_Misc:
530 case kIOHIDElementTypeInput_Button:
531 case kIOHIDElementTypeInput_Axis:
532 case kIOHIDElementTypeInput_ScanCodes:
534 if ( typeMask & kHIDElementTypeInput ) {
535 result = tIOHIDElementRef;
537 break;
540 case kIOHIDElementTypeOutput:
542 if ( typeMask & kHIDElementTypeOutput ) {
543 result = tIOHIDElementRef;
545 break;
548 case kIOHIDElementTypeFeature:
550 if ( typeMask & kHIDElementTypeFeature ) {
551 result = tIOHIDElementRef;
553 break;
556 case kIOHIDElementTypeCollection:
558 if ( typeMask & kHIDElementTypeCollection ) {
559 result = tIOHIDElementRef;
561 break;
563 } // switch ( type )
565 if ( result ) {
566 break; // DONE!
568 } // if ( !found )
569 } // next idx
570 CFRelease( gElementCFArrayRef );
571 gElementCFArrayRef = NULL;
572 } // if ( gElementCFArrayRef )
573 } // if ( inIOHIDDeviceRef )
574 } // if ( inIOHIDElementRef )
575 return result;
576 } /* HIDGetNextDeviceElement */
578 #if 0
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 */
596 #endif
598 // utility routine to dump device info
599 void HIDDumpDeviceInfo( IOHIDDeviceRef inIOHIDDeviceRef )
601 char cstring[256];
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 );
623 if ( vendorID ) {
624 #if 1
625 printf( " vendorID: 0x%04lX, ", vendorID );
626 #else
627 if ( HIDGetVendorNameFromVendorID( vendorID, cstring ) ) {
628 printf( " vendorID: 0x%04lX (\"%s\"), ", vendorID, cstring );
629 } else {
630 printf( " vendorID: 0x%04lX, ", vendorID );
632 #endif
635 long productID = IOHIDDevice_GetProductID( inIOHIDDeviceRef );
637 if ( productID ) {
638 #if 1
639 printf( " productID: 0x%04lX, ", productID );
640 #else
642 if ( HIDGetProductNameFromVendorProductID( vendorID, productID, cstring ) ) {
643 printf( " productID: 0x%04lX (\"%s\"), ", productID, cstring );
644 } else {
645 printf( " productID: 0x%04lX, ", productID );
647 #endif
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 );
660 #if 1
661 tCFStringRef = HIDCopyUsageName( usagePage, usage );
662 if ( tCFStringRef ) {
663 verify( CFStringGetCString( tCFStringRef, cstring, sizeof( cstring ), kCFStringEncodingUTF8 ) );
664 printf( "\"%s\", ", cstring );
665 CFRelease( tCFStringRef );
667 #endif
669 #if 1
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 );
680 if ( version ) {
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 );
690 if ( country ) {
691 printf( "CountryCode: %ld, ", country );
693 long locationID = IOHIDDevice_GetLocationID( inIOHIDDeviceRef );
694 if ( locationID ) {
695 printf( "locationID: 0x%08lX, ", locationID );
697 #if 0
698 CFArrayRef pairs = IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef );
699 if ( pairs ) {
700 CFIndex idx, cnt = CFArrayGetCount(pairs);
701 for ( idx = 0; idx < cnt; idx++ ) {
702 const void * pair = CFArrayGetValueAtIndex(pairs, idx);
703 CFShow( pair );
706 #endif
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 );
728 if ( queueRef ) {
729 printf( "queue: %p, ", queueRef);
731 IOHIDTransactionRef transactionRef = IOHIDDevice_GetTransaction( inIOHIDDeviceRef );
732 if ( transactionRef ) {
733 printf( "transaction: %p, ", transactionRef);
735 #endif
736 printf( "}\n" );
737 fflush( stdout );
738 } // HIDDumpDeviceInfo
740 // utility routine to dump element info
741 void HIDDumpElementInfo( IOHIDElementRef inIOHIDElementRef )
743 if ( inIOHIDElementRef ) {
744 printf( " Element: %p = { ", inIOHIDElementRef );
745 #if 0
746 IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice( inIOHIDElementRef );
747 printf( "Device: %p, ", tIOHIDDeviceRef );
748 #endif
749 IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent( inIOHIDElementRef );
750 printf( "parent: %p, ", parentIOHIDElementRef );
751 #if 0
752 CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren( inIOHIDElementRef );
753 printf( "children: %p: { ", childrenCFArrayRef ); fflush( stdout );
754 CFShow( childrenCFArrayRef ); fflush( stdout );
755 printf( " }, " );
756 #endif
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, " );
764 break;
767 case kIOHIDElementTypeInput_Button: {
768 printf( "type: Button, " );
769 break;
772 case kIOHIDElementTypeInput_Axis: {
773 printf( "type: Axis, " );
774 break;
777 case kIOHIDElementTypeInput_ScanCodes: {
778 printf( "type: ScanCodes, " );
779 break;
782 case kIOHIDElementTypeOutput: {
783 printf( "type: Output, " );
784 break;
787 case kIOHIDElementTypeFeature: {
788 printf( "type: Feature, " );
789 break;
792 case kIOHIDElementTypeCollection: {
793 IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType( inIOHIDElementRef );
794 switch (tIOHIDElementCollectionType ) {
795 case kIOHIDElementCollectionTypePhysical: {
796 printf( "type: Physical Collection, " );
797 break;
799 case kIOHIDElementCollectionTypeApplication: {
800 printf( "type: Application Collection, " );
801 break;
804 case kIOHIDElementCollectionTypeLogical: {
805 printf( "type: Logical Collection, " );
806 break;
809 case kIOHIDElementCollectionTypeReport: {
810 printf( "type: Report Collection, " );
811 break;
814 case kIOHIDElementCollectionTypeNamedArray: {
815 printf( "type: Named Array Collection, " );
816 break;
819 case kIOHIDElementCollectionTypeUsageSwitch: {
820 printf( "type: Usage Switch Collection, " );
821 break;
824 case kIOHIDElementCollectionTypeUsageModifier: {
825 printf( "type: Usage Modifier Collection, " );
826 break;
829 default: {
830 printf( "type: %p Collection, ", (void*) tIOHIDElementCollectionType );
831 break;
834 break;
837 default: {
838 printf( "type: %p, ", (void*) tIOHIDElementType );
839 break;
841 } /* switch */
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 );
846 #if 1
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 );
855 #endif
856 CFStringRef nameCFStringRef = IOHIDElementGetName( inIOHIDElementRef );
857 char buffer[256];
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 );
892 if ( isVirtual ) {
893 printf( "isVirtual, " );
896 Boolean isRelative = IOHIDElementIsRelative( inIOHIDElementRef );
898 if ( isRelative ) {
899 printf( "isRelative, " );
902 Boolean isWrapping = IOHIDElementIsWrapping( inIOHIDElementRef );
904 if ( isWrapping ) {
905 printf( "isWrapping, " );
908 Boolean isArray = IOHIDElementIsArray( inIOHIDElementRef );
910 if ( isArray ) {
911 printf( "isArray, " );
914 Boolean isNonLinear = IOHIDElementIsNonLinear( inIOHIDElementRef );
916 if ( isNonLinear ) {
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, " );
932 printf( " }\n" );
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
972 // Returns: nothing
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 );
992 if ( loc1 < loc2 ) {
993 result = kCFCompareLessThan;
994 } else if ( loc1 > loc2 ) {
995 result = kCFCompareGreaterThan;
997 return result;
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
1009 // inUsage - usages
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
1031 if ( inUsage ) {
1032 CFNumberRef usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &inUsage );
1034 if ( usageCFNumberRef ) {
1035 CFDictionarySetValue( refHIDMatchDictionary,
1036 CFSTR( kIOHIDPrimaryUsageKey ), usageCFNumberRef );
1037 CFRelease( usageCFNumberRef );
1038 } else {
1039 fprintf( stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__ );
1042 } else {
1043 fprintf( stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__ );
1046 } else {
1047 fprintf( stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__ );
1049 return refHIDMatchDictionary;
1050 } // hu_SetUpMatchingDictionary