Sample Code

OSX Driver and Kext Samples/ HID_Dumper/ HID_Dumper/ HID_Dumper/ HID Utilities/ HID_Name_Lookup.c/

//     File: HID_Name_Lookup.c
// Abstract: HID Name Lookup Utilities.
//  Version: 2.0
// 
// Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
// Inc. ("Apple") in consideration of your agreement to the following
// terms, and your use, installation, modification or redistribution of
// this Apple software constitutes acceptance of these terms.  If you do
// not agree with these terms, please do not use, install, modify or
// redistribute this Apple software.
// 
// In consideration of your agreement to abide by the following terms, and
// subject to these terms, Apple grants you a personal, non-exclusive
// license, under Apple's copyrights in this original Apple software (the
// "Apple Software"), to use, reproduce, modify and redistribute the Apple
// Software, with or without modifications, in source and/or binary forms;
// provided that if you redistribute the Apple Software in its entirety and
// without modifications, you must retain this notice and the following
// text and disclaimers in all such redistributions of the Apple Software.
// Neither the name, trademarks, service marks or logos of Apple Inc. may
// be used to endorse or promote products derived from the Apple Software
// without specific prior written permission from Apple.  Except as
// expressly stated in this notice, no other rights or licenses, express or
// implied, are granted by Apple herein, including but not limited to any
// patent rights that may be infringed by your derivative works or by other
// works in which the Apple Software may be incorporated.
// 
// The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
// 
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// Copyright (C) 2013 Apple Inc. All Rights Reserved.
// 
// *****************************************************
#pragma mark - includes & imports
// *****************************************************
#include "HID_Utilities_External.h"
// *****************************************************
#pragma mark - typedefs, enums, defines, etc.
// *****************************************************
#define FAKE_MISSING_NAMES       0  // for debugging; returns the vendor, product & cookie (or usage info) as numbers.
#define VERBOSE_ELEMENT_NAMES    0  // set true to include vender & product names in element names (useful for debugging)

#define kNameKeyCFStringRef      CFSTR("Name")
// *****************************************************
#pragma mark - local (static) function prototypes
// *****************************************************

#if false   // currently unused
static SInt32 hu_SaveToXMLFile(CFPropertyListRef inCFPRef, CFURLRef inCFURLRef);
static SInt32 hu_XMLSave(CFPropertyListRef inCFPropertyListRef, CFStringRef inResourceName, CFStringRef inResourceExtension);
#endif // if 0
static CFPropertyListRef hu_LoadFromXMLFile(CFURLRef inCFURLRef);
static CFPropertyListRef hu_XMLLoad(CFStringRef inResourceName, CFStringRef inResourceExtension);

static Boolean hu_XMLSearchForElementNameByCookie(long inVendorID, long inProductID, IOHIDElementCookie inCookie, char * outCStr);
static Boolean hu_XMLSearchForElementNameByUsage(long inVendorID, long inProductID, long inUsagePage, long inUsage, char * outCStr);

static Boolean hu_XMLSearchForVendorNameByVendorID(long inVendorID, char * outCStr);
static Boolean hu_XMLSearchForProductNameByVendorProductID(long inVendorID, long inProductID, char * outCStr);

#if false   // currently unused
static Boolean hu_AddVendorProductToCFDict(CFMutableDictionaryRef inCFMutableDictionaryRef,
                                           long                   inVendorID,
                                           CFStringRef            inVendorCFStringRef,
                                           long                   inProductID,
                                           CFStringRef            inProductCFStringRef);
static Boolean hu_AddDeviceElementToUsageXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef);
#endif // if 0
// *****************************************************
#pragma mark - exported globals
// *****************************************************
#pragma mark - local (static) globals
// *****************************************************
static CFPropertyListRef gCookieCFPropertyListRef = NULL;
static CFPropertyListRef gUsageCFPropertyListRef  = NULL;

// *****************************************************
#pragma mark - exported function implementations
// *****************************************************

/*************************************************************************
 *
 * HIDGetVendorNameFromVendorID(inVendorID, inProductID, inCookie, outCStrName)
 *
 * Purpose: Uses an devices vendor ID to generate a name for it.
 *
 * Notes:	Now uses XML files to store dictionary of names
 *
 * Inputs: inVendorID - the elements vendor ID
 *			outCStrName - address where result will be returned
 * Returns: Boolean		- if successful
 */
Boolean HIDGetVendorNameFromVendorID(long inVendorID, char * outCStrName) {
	Boolean result = false;
	
	*outCStrName = 0;  // clear name
	if ( hu_XMLSearchForVendorNameByVendorID(inVendorID, outCStrName) ) {
		return (true);
	}
	
#if FAKE_MISSING_NAMES
	sprintf(outCStrName, "#{ V: %ld}#", inVendorID);
	result = true;
#endif // FAKE_MISSING_NAMES
	return (result);
}   // HIDGetVendorNameFromVendorID

/*************************************************************************
 *
 * HIDGetProductNameFromVendorProductID(inVendorID, inProductID, outCStrName)
 *
 * Purpose: Uses an elements vendor, product & usage info to generate a name for it.
 *
 * Notes:	Now uses XML files to store dictionary of names
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			inUsagePage	- the elements usage page
 *			inUsage		- the elements usage
 *			outCStrName - address where result will be returned
 * Returns: Boolean		- if successful
 */
Boolean HIDGetProductNameFromVendorProductID(long inVendorID, long inProductID, char * outCStrName) {
	Boolean result = false;
	
	*outCStrName = 0;  // clear name
	if ( hu_XMLSearchForProductNameByVendorProductID(inVendorID, inProductID, outCStrName) ) {
		return (true);
	}
	
#if FAKE_MISSING_NAMES
	sprintf(outCStrName, "#{ V: %ld, P: %ld, U: %ld: %ld}#", inVendorID, inProductID, inUsagePage, inUsage);
	result = true;
#endif // FAKE_MISSING_NAMES
	return (result);
}   // HIDGetProductNameFromVendorProductID

/*************************************************************************
 *
 * HIDGetElementNameFromVendorProductCookie(inVendorID, inProductID, inCookie, outCStrName)
 *
 * Purpose: Uses an elements vendor, product & cookie to generate a name for it.
 *
 * Notes:	Now uses XML files to store dictionary of names
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			inCookie		- the elements cookie
 *			outCStrName - address where result will be returned
 * Returns: Boolean		- if successful
 */
Boolean HIDGetElementNameFromVendorProductCookie(int inVendorID, int inProductID, IOHIDElementCookie inCookie,
                                                 char * outCStrName) {
	Boolean result = false;
	
	*outCStrName = 0; // clear name
	// Look in the XML file first
	if ( hu_XMLSearchForElementNameByCookie(inVendorID, inProductID, inCookie, outCStrName) ) {
		return (true);
	}
	
#if FAKE_MISSING_NAMES
	sprintf(outCStrName, "#{ V: %ld, P: %ld, C: %ld}#", inVendorID, inProductID, inCookie);
#else // if FAKE_MISSING_NAMES
	result = false;
#endif // FAKE_MISSING_NAMES
	return (result);
}   // HIDGetElementNameFromVendorProductCookie

/*************************************************************************
 *
 * HIDGetElementNameFromVendorProductUsage(inVendorID, inProductID, inUsagePage, inUsage, outCStrName)
 *
 * Purpose: Uses an elements vendor, product & usage info to generate a name for it.
 *
 * Notes:	Now uses XML files to store dictionary of names
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			inUsagePage	- the elements usage page
 *			inUsage		- the elements usage
 *			outCStrName - address where result will be returned
 * Returns: Boolean		- if successful
 */
Boolean HIDGetElementNameFromVendorProductUsage(long   inVendorID,
                                                long   inProductID,
                                                long   inUsagePage,
                                                long   inUsage,
                                                char * outCStrName) {
	Boolean result = false;
	
	*outCStrName = 0;  // clear name
	if ( hu_XMLSearchForElementNameByUsage(inVendorID, inProductID, inUsagePage, inUsage, outCStrName) ) {
		return (true);
	}
	
#if FAKE_MISSING_NAMES
	sprintf(outCStrName, "#{ V: %ld, P: %ld, U: %ld: %ld}#", inVendorID, inProductID, inUsagePage, inUsage);
	result = true;
#endif // FAKE_MISSING_NAMES
	return (result);
}   // HIDGetElementNameFromVendorProductUsage

#if false   // currently unused
/*************************************************************************
 *
 * HIDAddDeviceToXML(inDevice)
 *
 * Purpose: Adds a devices info to the HID_device_usage_strings.plist(XML) file
 *
 * Inputs: inDevice		- the device
 * Returns: Boolean		- if successful
 */
static Boolean HIDAddDeviceToXML(IOHIDDeviceRef inIOHIDDeviceRef) {
	Boolean result = false;
	
	if ( HIDIsValidDevice(inIOHIDDeviceRef) ) {
		CFStringRef vendorCFStringRef  = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef);
		CFStringRef productCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef);
		if (vendorCFStringRef && productCFStringRef) {
#if false       // don't update the cookie xml file
			gCookieCFPropertyListRef =
			hu_XMLLoad(CFSTR("HID_cookie_strings"), CFSTR("plist") );
			if (gCookieCFPropertyListRef) {
				CFMutableDictionaryRef tCFMutableDictionaryRef =
				CFDictionaryCreateMutableCopy(
											  kCFAllocatorDefault,
											  0,
											  gCookieCFPropertyListRef);
				if (tCFMutableDictionaryRef) {
					if ( hu_AddVendorProductToCFDict(tCFMutableDictionaryRef, vendorID, vendorCFStringRef, productID,
					                                 productCFStringRef) )
					{
						hu_XMLSave( tCFMutableDictionaryRef, CFSTR("HID_cookie_strings"), CFSTR("plist") );
						result = true;
					}
					
					CFRelease(tCFMutableDictionaryRef);
				}
			}
			
#endif      // if 0
			if (gUsageCFPropertyListRef) {
				CFRelease(gUsageCFPropertyListRef);
			}
			
			gUsageCFPropertyListRef =
			hu_XMLLoad(CFSTR("HID_device_usage_strings"), CFSTR("plist") );
			if (gUsageCFPropertyListRef) {
				CFMutableDictionaryRef tCFMutableDictionaryRef =
				CFDictionaryCreateMutableCopy(
											  kCFAllocatorDefault,
											  0,
											  gUsageCFPropertyListRef);
				if (tCFMutableDictionaryRef) {
					long vendorID  = IOHIDDevice_GetVendorID(inIOHIDDeviceRef);
					long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef);
					if ( hu_AddVendorProductToCFDict(tCFMutableDictionaryRef, vendorID, vendorCFStringRef, productID,
					                                 productCFStringRef) )
					{
						hu_XMLSave( tCFMutableDictionaryRef,CFSTR("HID_device_usage_strings"), CFSTR("plist") );
						result = true;
					}
					
					CFRelease(tCFMutableDictionaryRef);
				}
			}
		}
	}
	
	return (result);
}   // HIDAddDeviceToXML

/*************************************************************************
 *
 * HIDAddDeviceElementToXML(inDevice, inElement)
 *
 * Purpose: Adds a devices info to the HID_device_usage_strings.plist(XML) file
 *
 * Inputs: inDevice		- the device
 *			inElement	- the element
 *
 * Returns: Boolean		- if successful
 */
Boolean HIDAddDeviceElementToXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
	Boolean result = false;
	
	if ( HIDIsValidElement(inIOHIDElementRef) ) {
		if ( HIDAddDeviceToXML(inIOHIDDeviceRef) ) {
			result = true;
		}
		if ( hu_AddDeviceElementToUsageXML(inIOHIDDeviceRef, inIOHIDElementRef) ) {
			result = true;
		}
	}
	
	return (result);
}   // HIDAddDeviceElementToXML
#endif // if 0
/*************************************************************************
 *
 * HIDGetTypeName(inIOHIDElementType, outCStrName)
 *
 * Purpose: return a C string for a given element type(see IOHIDKeys.h)
 * Notes:	returns "Unknown Type" for invalid types
 *
 * Inputs: inIOHIDElementType	- type element type
 *			outCStrName			- address where to store element type string
 *
 * Returns: outCStrName			- the element type string
 */

void HIDGetTypeName(IOHIDElementType inIOHIDElementType, char * outCStrName) {
	switch (inIOHIDElementType) {
		case kIOHIDElementTypeInput_Misc:
		{
			sprintf(outCStrName, "Miscellaneous Input");
			break;
		}
			
		case kIOHIDElementTypeInput_Button:
		{
			sprintf(outCStrName, "Button Input");
			break;
		}
			
		case kIOHIDElementTypeInput_Axis:
		{
			sprintf(outCStrName, "Axis Input");
			break;
		}
			
		case kIOHIDElementTypeInput_ScanCodes:
		{
			sprintf(outCStrName, "Scan Code Input");
			break;
		}
			
		case kIOHIDElementTypeOutput:
		{
			sprintf(outCStrName, "Output");
			break;
		}
			
		case kIOHIDElementTypeFeature:
		{
			sprintf(outCStrName, "Feature");
			break;
		}
			
		case kIOHIDElementTypeCollection:
		{
			sprintf(outCStrName, "Collection");
			break;
		}
			
		default:
		{
			sprintf(outCStrName, "Unknown Type");
			break;
		}
	} // switch
}   // HIDGetTypeName

// *************************************************************************
//
// HIDCopyUsagePageName(inUsagePage)
//
// Purpose:	return a CFStringRef string for a given usage page (see IOUSBHIDParser.h)
//
// Notes:	returns usage page in CFString form for unknown values
//
// Inputs:	inUsagePage	- the usage page
//
// Returns:	CFStringRef	- the resultant string
//

CFStringRef HIDCopyUsagePageName(long inUsagePage) {
	static CFPropertyListRef tCFPropertyListRef = NULL;
	CFStringRef              result             = NULL;
	
	if (!tCFPropertyListRef) {
		tCFPropertyListRef =
		hu_XMLLoad(CFSTR("HID_usage_strings"), CFSTR("plist") );
	}
	if (tCFPropertyListRef) {
		if ( 
		    CFDictionaryGetTypeID() == CFGetTypeID(tCFPropertyListRef) ) {
			CFStringRef pageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%4.4lX"), inUsagePage);
			if (pageKeyCFStringRef) {
				CFDictionaryRef pageCFDictionaryRef;
				if (     CFDictionaryGetValueIfPresent(tCFPropertyListRef, pageKeyCFStringRef,
				                                       (const void * *) &pageCFDictionaryRef) ) {
					CFStringRef pageCFStringRef;
					if ( CFDictionaryGetValueIfPresent(pageCFDictionaryRef,
					                                   kNameKeyCFStringRef,
					                                   (const void * *) &pageCFStringRef) )
					{
						result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), pageCFStringRef);
					}
#if FAKE_MISSING_NAMES
					else {
						// no name data for this page key (so we use the key)
						result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("#%@"), pageKeyCFStringRef);
					}
				} else {
					// no name data for this page key (so we use the key)
					result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("#%@"), pageKeyCFStringRef);
#endif              // if FAKE_MISSING_NAMES
				}
				
				CFRelease(pageKeyCFStringRef);
			}
		}
		// CFRelease(tCFPropertyListRef);	// Leak this!
		// tCFPropertyListRef = NULL;
	}
	
	return (result);
}   // HIDCopyUsagePageName

// *************************************************************************
//
// HIDCopyUsageName(inUsagePage, inUsage)
//
// Purpose:	return a CFStringRef string for a given usage page & usage(see IOUSBHIDParser.h)
//
// Notes:	returns usage page and usage values in CFString form for unknown values
//
// Inputs:	inUsagePage	- the usage page
// inUsage		- the usage
//
// Returns:	CFStringRef	- the resultant string
//

CFStringRef HIDCopyUsageName(long inUsagePage, long inUsage) {
	static CFPropertyListRef tCFPropertyListRef = NULL;
	CFStringRef              result             = NULL;
	
	if (!tCFPropertyListRef) {
		tCFPropertyListRef =
		hu_XMLLoad(CFSTR("HID_usage_strings"), CFSTR("plist") );
	}
	if (tCFPropertyListRef) {
		if (CFDictionaryGetTypeID() == CFGetTypeID(tCFPropertyListRef) ) {
			CFStringRef pageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%4.4lX"), inUsagePage);
			if (pageKeyCFStringRef) {
				CFDictionaryRef pageCFDictionaryRef;
				if (CFDictionaryGetValueIfPresent(tCFPropertyListRef, pageKeyCFStringRef,
												  (const void * *) &pageCFDictionaryRef) ) {
					CFStringRef pageCFStringRef;
					if (CFDictionaryGetValueIfPresent(pageCFDictionaryRef, kNameKeyCFStringRef,
													  (const void * *) &pageCFStringRef) )
					{
						CFStringRef usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%4.4lX"), inUsage);
						if (usageKeyCFStringRef) {
							CFStringRef usageCFStringRef;
							if ( CFDictionaryGetValueIfPresent(pageCFDictionaryRef, usageKeyCFStringRef,
							                                   (const void * *) &usageCFStringRef) )
							{
								result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@"), pageCFStringRef, usageCFStringRef);
							}
							
#if FAKE_MISSING_NAMES
							else {
								result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ #%@"), pageCFStringRef, usageKeyCFStringRef);
							}
#endif                      // if FAKE_MISSING_NAMES
							CFRelease(usageKeyCFStringRef);
						}
					} else {
						// no name data for this page
					}
				} else {
					// no data for this page
				}
				
				CFRelease(pageKeyCFStringRef);
			}
		}
		
		// CFRelease(tCFPropertyListRef);	// Leak this!
		// tCFPropertyListRef = NULL;
	}
	
	return (result);
}   // HIDCopyUsageName

// *****************************************************
#pragma mark - local (static) function implementations
// *****************************************************
#if false   // currently unused
/*************************************************************************
 *
 * hu_SaveToXMLFile(inCFPRef, inCFURLRef)
 *
 * Purpose: save a property list into an XML file
 *
 * Inputs: inCFPRef		- the data
 *			inCFURLRef	- URL for the file
 *
 * Returns: SInt32		- error code (if any)
 */
static SInt32 hu_SaveToXMLFile(CFPropertyListRef inCFPRef, CFURLRef inCFURLRef) {
	CFDataRef xmlCFDataRef;
	SInt32    error = coreFoundationUnknownErr;
	
	// Convert the property list into XML data.
	xmlCFDataRef = CFPropertyListCreateXMLData(kCFAllocatorDefault, inCFPRef);
	if (xmlCFDataRef) {
		// Write the XML data to the file.
		(void) CFURLWriteDataAndPropertiesToResource(inCFURLRef, xmlCFDataRef, NULL, &error);
		
		// Release the XML data
		CFRelease(xmlCFDataRef);
	}
	
	return (error);
}   // hu_SaveToXMLFile
#endif // if 0
/*************************************************************************
 *
 * hu_LoadFromXMLFile(inCFURLRef)
 *
 * Purpose: load a property list from an XML file
 *
 * Inputs: inCFURLRef			- URL for the file
 *
 * Returns: CFPropertyListRef - the data
 */
static CFPropertyListRef hu_LoadFromXMLFile(CFURLRef inCFURLRef) {
	CFDataRef         xmlCFDataRef;
	CFPropertyListRef myCFPropertyListRef = NULL;
	
	// Read the XML file.
	SInt32 error;
	
	if ( CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, inCFURLRef, &xmlCFDataRef, NULL, NULL, &error) ) {
		CFStringRef errorString;
		// Reconstitute the dictionary using the XML data.
		myCFPropertyListRef = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
		                                                      xmlCFDataRef,
		                                                      kCFPropertyListImmutable,
		                                                      &errorString);
		// Release the XML data
		CFRelease(xmlCFDataRef);
	}
	
	return (myCFPropertyListRef);
}       // hu_LoadFromXMLFile

#if false   // currently unused
/*************************************************************************
 *
 * hu_XMLSave(inCFPropertyListRef, inResourceName, inResourceExtension)
 *
 * Purpose: save a CFPropertyListRef into a resource(XML) file
 *
 * Inputs: inCFPropertyListRef - the data
 *			inResourceName		- name of the resource file
 *			inResourceExtension - extension of the resource file
 *
 * Returns: SInt32				- error code (if any)
 */
static SInt32 hu_XMLSave(CFPropertyListRef inCFPropertyListRef, CFStringRef inResourceName, CFStringRef inResourceExtension) {
	CFURLRef resFileCFURLRef;
	SInt32   error = -1;
	
	// check the main (application) bundle
	resFileCFURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), inResourceName, inResourceExtension, NULL);
	
	if (!resFileCFURLRef) {
		// check this specific (HID_Utilities framework) bundle
		CFBundleRef tCFBundleRef = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.HID_Utilities") );
		if (tCFBundleRef) {
			resFileCFURLRef = CFBundleCopyResourceURL(tCFBundleRef, inResourceName, inResourceExtension, NULL);
		}
	}
	if (!resFileCFURLRef) {
		// check bundles already loaded or otherwise known to the current process
		CFArrayRef tCFArrayRef = CFBundleGetAllBundles();
		CFIndex    idx, cnt = CFArrayGetCount(tCFArrayRef);
		for (idx = 0; idx < cnt; idx++) {
			CFBundleRef tCFBundleRef = (CFBundleRef) CFArrayGetValueAtIndex(tCFArrayRef, idx);
			if (tCFBundleRef) {
				resFileCFURLRef = CFBundleCopyResourceURL(tCFBundleRef, inResourceName, inResourceExtension, NULL);
				if (resFileCFURLRef) {
					break;
				}
			}
		}
	}
	if (resFileCFURLRef) {
		error = hu_SaveToXMLFile(inCFPropertyListRef, resFileCFURLRef);
		CFRelease(resFileCFURLRef);
	}
	
	return (error);
}   // hu_XMLSave
#endif // if 0
/*************************************************************************
 *
 * hu_XMLLoad(inResourceName, inResourceExtension)
 *
 * Purpose: Load a resource(XML) file into a CFPropertyListRef
 *
 * Inputs: inResourceName		- name of the resource file
 *			inResourceExtension - extension of the resource file
 *
 * Returns: CFPropertyListRef - the data
 */
static CFPropertyListRef hu_XMLLoad(CFStringRef inResourceName, CFStringRef inResourceExtension) {
	CFURLRef          resFileCFURLRef;
	CFPropertyListRef tCFPropertyListRef = NULL;
	
	// check the main (application) bundle
	resFileCFURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), inResourceName, inResourceExtension, NULL);
	
	if (!resFileCFURLRef) {
		// check this specific (HID_Utilities framework) bundle
		CFBundleRef tCFBundleRef = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.HID_Utilities") );
		if (tCFBundleRef) {
			resFileCFURLRef = CFBundleCopyResourceURL(tCFBundleRef, inResourceName, inResourceExtension, NULL);
		}
	}
	if (!resFileCFURLRef) {
		// check bundles already loaded or otherwise known to the current process
		CFArrayRef tCFArrayRef = CFBundleGetAllBundles();
		CFIndex    idx, cnt = CFArrayGetCount(tCFArrayRef);
		for (idx = 0; idx < cnt; idx++) {
			CFBundleRef tCFBundleRef = (CFBundleRef) CFArrayGetValueAtIndex(tCFArrayRef, idx);
			if (tCFBundleRef) {
				resFileCFURLRef = CFBundleCopyResourceURL(tCFBundleRef, inResourceName, inResourceExtension, NULL);
				if (resFileCFURLRef) {
					break;
				}
			}
		}
	}
	if (resFileCFURLRef) {
		tCFPropertyListRef = hu_LoadFromXMLFile(resFileCFURLRef);
		CFRelease(resFileCFURLRef);
	}
	
	return (tCFPropertyListRef);
}   // hu_XMLLoad

/*************************************************************************
 *
 * hu_XMLSearchForVendorNameByVendorID(inVendorID, outCStr)
 *
 * Purpose: Find a vendor string in the <HID_device_usage_strings.plist> resource (XML) file
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			outCStr		- address where result will be returned
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_XMLSearchForVendorNameByVendorID(long inVendorID, char * outCStr) {
	Boolean results = false;
	
	if (!gUsageCFPropertyListRef) {
		gUsageCFPropertyListRef =
		hu_XMLLoad(CFSTR("HID_device_usage_strings"), CFSTR("plist") );
	}
	if (gUsageCFPropertyListRef) {
		if (
		    CFDictionaryGetTypeID() == CFGetTypeID(gUsageCFPropertyListRef) )
		{
			CFDictionaryRef vendorCFDictionaryRef;
			CFStringRef     vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID);
			if (vendorKeyCFStringRef) {
				if (    CFDictionaryGetValueIfPresent(gUsageCFPropertyListRef, vendorKeyCFStringRef,
				                                      (const void * *) &vendorCFDictionaryRef) )
				{
					CFStringRef vendorCFStringRef = NULL;
					if (CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef,
					                                  (const void * *) &vendorCFStringRef) && vendorCFStringRef)
					{
						// CFShow(vendorCFStringRef);
						results =
						CFStringGetCString(vendorCFStringRef, outCStr, CFStringGetLength(
																						 vendorCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8);
					}
				}
				
				CFRelease(vendorKeyCFStringRef);
			}
		}
		
		// ++ CFRelease(gUsageCFPropertyListRef);	// Leak this !
	}
	
	return (results);
}   // hu_XMLSearchForVendorNameByVendorID

/*************************************************************************
 *
 * hu_XMLSearchForProductNameByVendorProductID(inVendorID, inProductID, outCStr)
 *
 * Purpose: Find an product string in the <HID_device_usage_strings.plist> resource (XML) file
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			outCStr		- address where result will be returned
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_XMLSearchForProductNameByVendorProductID(long inVendorID, long inProductID, char * outCStr) {
	Boolean results = false;
	
	if (!gUsageCFPropertyListRef) {
		gUsageCFPropertyListRef =
		hu_XMLLoad(CFSTR("HID_device_usage_strings"), CFSTR("plist") );
	}
	if (gUsageCFPropertyListRef) {
		if (
		    CFDictionaryGetTypeID() == CFGetTypeID(gUsageCFPropertyListRef) )
		{
			// first we make our vendor ID key
			CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID);
			if (vendorKeyCFStringRef) {
				// and use it to look up our vendor dictionary
				CFDictionaryRef vendorCFDictionaryRef;
				if (     CFDictionaryGetValueIfPresent(gUsageCFPropertyListRef, vendorKeyCFStringRef,
				                                       (const void * *) &vendorCFDictionaryRef) )
				{
					// pull our vendor name our of that dictionary
					CFStringRef vendorCFStringRef = NULL;
					if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef,
					                                   (const void * *) &vendorCFStringRef) )
					{
#if FAKE_MISSING_NAMES
						CFRetain(vendorCFStringRef);    // so we can CFRelease it later
					} else {
						vendorCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("V: %@"), vendorKeyCFStringRef);
#endif                  // if FAKE_MISSING_NAMES
					}
					
					// now we make our product ID key
					CFStringRef productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inProductID);
					if (productKeyCFStringRef) {
						// and use that key to look up our product dictionary in the vendor dictionary
						CFDictionaryRef productCFDictionaryRef;
						if (     CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, productKeyCFStringRef,
						                                       (const void * *) &productCFDictionaryRef) )
						{
							// pull our product name our of the product dictionary
							CFStringRef productCFStringRef = NULL;
							if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, kNameKeyCFStringRef,
							                                   (const void * *) &productCFStringRef) )
							{
#if FAKE_MISSING_NAMES
								CFRetain(productCFStringRef);   // so we can CFRelease it later
							} else {
								productCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("P: %@"), kNameKeyCFStringRef);
#endif                          // if FAKE_MISSING_NAMES
							}
							
							CFStringRef fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@"), vendorCFStringRef,
							                                                       productCFStringRef);
							if (fullCFStringRef) {
								// CFShow(fullCFStringRef);
								results =
								CFStringGetCString(fullCFStringRef, outCStr, CFStringGetLength(
																							   fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8);
								CFRelease(fullCFStringRef);
							}
							
#if FAKE_MISSING_NAMES
							if (productCFStringRef) {
								CFRelease(productCFStringRef);
							}
							
#endif                      // if FAKE_MISSING_NAMES
						}
						
						CFRelease(productKeyCFStringRef);
					}
					
#if FAKE_MISSING_NAMES
					if (vendorCFStringRef) {
						CFRelease(vendorCFStringRef);
					}
					
#endif              // if FAKE_MISSING_NAMES
				}
				
				CFRelease(vendorKeyCFStringRef);
			}
		}
		
		// ++ CFRelease(gUsageCFPropertyListRef);	// Leak this !
	}
	
	return (results);
}   // hu_XMLSearchForProductNameByVendorProductID

/*************************************************************************
 *
 * hu_XMLSearchForElementNameByCookie(inVendorID, inProductID, inCookie, outCStr)
 *
 * Purpose: Find an element string in the <HID_cookie_strings.plist> resource(XML) file
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			inCookie		- the elements cookie
 *			outCStr		- address where result will be returned
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_XMLSearchForElementNameByCookie(long inVendorID, long inProductID, IOHIDElementCookie inCookie, char * outCStr) {
	Boolean results = false;
	
	if (!gCookieCFPropertyListRef) {
		gCookieCFPropertyListRef =
		hu_XMLLoad(CFSTR("HID_cookie_strings"), CFSTR("plist") );
	}
	if (gCookieCFPropertyListRef) {
		if (
		    CFDictionaryGetTypeID() == CFGetTypeID(gCookieCFPropertyListRef) )
		{
			CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID);
			if (vendorKeyCFStringRef) {
				CFDictionaryRef vendorCFDictionaryRef;
				if (     CFDictionaryGetValueIfPresent(gCookieCFPropertyListRef, vendorKeyCFStringRef,
				                                       (const void * *) &vendorCFDictionaryRef) )
				{
					CFDictionaryRef productCFDictionaryRef;
					CFStringRef     productKeyCFStringRef;
					CFStringRef     vendorCFStringRef;
					if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef,
					                                   (const void * *) &vendorCFStringRef) )
					{
						// CFShow(vendorCFStringRef);
					}
					
					productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inProductID);
					if (     CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, productKeyCFStringRef,
					                                       (const void * *) &productCFDictionaryRef) )
					{
						CFStringRef fullCFStringRef = NULL;
						CFStringRef cookieKeyCFStringRef;
						CFStringRef productCFStringRef;
						CFStringRef cookieCFStringRef;
						if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, kNameKeyCFStringRef,
						                                   (const void * *) &productCFStringRef) )
						{
							// CFShow(productCFStringRef);
						}
						
						cookieKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), (uint32_t) inCookie);
						if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, cookieKeyCFStringRef,
						                                   (const void * *) &cookieCFStringRef) )
						{
#if VERBOSE_ELEMENT_NAMES
							fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@ %@"), vendorCFStringRef, productCFStringRef,
							                                           cookieCFStringRef);
#else                       // if VERBOSE_ELEMENT_NAMES
							fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), cookieCFStringRef);
#endif                      // VERBOSE_ELEMENT_NAMES
							// CFShow(cookieCFStringRef);
						}
						
#if FAKE_MISSING_NAMES
						else {
							fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@ # %@"), vendorCFStringRef, productCFStringRef,
							                                           cookieKeyCFStringRef);
						}
#endif                  // FAKE_MISSING_NAMES
						if (fullCFStringRef) {
							// CFShow(fullCFStringRef);
							results =
							CFStringGetCString(fullCFStringRef, outCStr, CFStringGetLength(
																						   fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8);
							CFRelease(fullCFStringRef);
						}
						
						CFRelease(cookieKeyCFStringRef);
					}
					
					CFRelease(productKeyCFStringRef);
				}
				
				CFRelease(vendorKeyCFStringRef);
			}
		}
		
		// ++ CFRelease(gCookieCFPropertyListRef);	// Leak this !
	}
	
	return (results);
}   // hu_XMLSearchForElementNameByCookie

/*************************************************************************
 *
 * hu_XMLSearchForElementNameByUsage(inVendorID, inProductID, inUsagePage, inUsage, outCStr)
 *
 * Purpose: Find an element string in the <HID_device_usage_strings.plist> resource(XML) file
 *
 * Inputs: inVendorID - the elements vendor ID
 *			inProductID - the elements product ID
 *			inUsagePage	- the elements usage page
 *			inUsage		- the elements usage
 *			outCStr		- address where result will be returned
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_XMLSearchForElementNameByUsage(long inVendorID, long inProductID, long inUsagePage, long inUsage,
                                                 char * outCStr) {
	Boolean results = false;
	
	if (!gUsageCFPropertyListRef) {
		gUsageCFPropertyListRef =
		hu_XMLLoad(CFSTR("HID_device_usage_strings"), CFSTR("plist") );
	}
	if (gUsageCFPropertyListRef) {
		if (
		    CFDictionaryGetTypeID() == CFGetTypeID(gUsageCFPropertyListRef) )
		{
			CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID);
			if (vendorKeyCFStringRef) {
				CFDictionaryRef vendorCFDictionaryRef;
				if (                        CFDictionaryGetValueIfPresent(gUsageCFPropertyListRef, vendorKeyCFStringRef,
				                                                          (const void * *) &vendorCFDictionaryRef) )
				{
					CFStringRef vendorCFStringRef = NULL;
					if (                    CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef,
					                                                      (const void * *) &vendorCFStringRef) )
					{
						vendorCFStringRef = CFStringCreateCopy(kCFAllocatorDefault, vendorCFStringRef);
					} else {
						vendorCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("v: %ld"), inVendorID);
						// CFShow(vendorCFStringRef);
					}
					
					CFStringRef productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inProductID);
					
					CFDictionaryRef productCFDictionaryRef;
					if (     CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, productKeyCFStringRef,
					                                       (const void * *) &productCFDictionaryRef) )
					{
						CFStringRef fullCFStringRef = NULL;
						
						CFStringRef productCFStringRef;
						if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, kNameKeyCFStringRef,
						                                   (const void * *) &productCFStringRef) )
						{
							// CFShow(productCFStringRef);
						}
						
						CFStringRef usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld:%ld"), inUsagePage, inUsage);
						CFStringRef usageCFStringRef;
						if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, usageKeyCFStringRef,
						                                   (const void * *) &usageCFStringRef) )
						{
#if VERBOSE_ELEMENT_NAMES
							fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@ %@"), vendorCFStringRef, productCFStringRef,
							                                           usageCFStringRef);
#else                       // if VERBOSE_ELEMENT_NAMES
							fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), usageCFStringRef);
#endif                      // VERBOSE_ELEMENT_NAMES
							// CFShow(usageCFStringRef);
						}
						
#if FAKE_MISSING_NAMES
						else {
							fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %@ # %@"), vendorCFStringRef, productCFStringRef,
							                                           usageKeyCFStringRef);
						}
#endif                  // FAKE_MISSING_NAMES
						if (fullCFStringRef) {
							// CFShow(fullCFStringRef);
							results =
							CFStringGetCString(fullCFStringRef, outCStr, CFStringGetLength(
																						   fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8);
							CFRelease(fullCFStringRef);
						}
						
						CFRelease(usageKeyCFStringRef);
					}
					if (vendorCFStringRef) {
						CFRelease(vendorCFStringRef);
					}
					
					CFRelease(productKeyCFStringRef);
				}
				
				CFRelease(vendorKeyCFStringRef);
			}
		}
		
		// ++ CFRelease(gUsageCFPropertyListRef);	// Leak this !
	}
	
	return (results);
}       // hu_XMLSearchForElementNameByUsage

#if false   // currently unused
/*************************************************************************
 *
 * hu_AddVendorProductToCFDict(inCFMutableDictionaryRef, inVendorID, inVendorCFStringRef, inProductID, inProductCFStringRef)
 *
 * Purpose: add a vendor & product to a dictionary
 *
 * Inputs: inCFMutableDictionaryRef - the dictionary
 *			inVendorID				- the elements vendor ID
 *			inProductID				- the elements product ID
 *			inProductCFStringRef	- the string to be added
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_AddVendorProductToCFDict(CFMutableDictionaryRef inCFMutableDictionaryRef,
                                           long                   inVendorID,
                                           CFStringRef            inVendorCFStringRef,
                                           long                   inProductID,
                                           CFStringRef            inProductCFStringRef) {
	Boolean results = false;
	
	if ( inCFMutableDictionaryRef && ( CFDictionaryGetTypeID() == CFGetTypeID(inCFMutableDictionaryRef) ) ) {
		CFMutableDictionaryRef vendorCFMutableDictionaryRef;
		CFStringRef            vendorKeyCFStringRef;
		
		CFMutableDictionaryRef productCFMutableDictionaryRef;
		CFStringRef            productKeyCFStringRef;
		
		// if the vendor dictionary doesn't exist
		vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID);
		if ( CFDictionaryGetValueIfPresent(inCFMutableDictionaryRef, vendorKeyCFStringRef,
		                                   (const void * *) &vendorCFMutableDictionaryRef) )
		{
			// copy it.
			vendorCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, vendorCFMutableDictionaryRef);
		} else {    // ...otherwise...
			// create it.
			vendorCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
			                                                         0,
			                                                         &kCFTypeDictionaryKeyCallBacks,
			                                                         &kCFTypeDictionaryValueCallBacks);
			results = true;
		}
		// if the vendor name key doesn't exist
		if ( !CFDictionaryContainsKey(vendorCFMutableDictionaryRef, kNameKeyCFStringRef) ) {
			// create it.
			CFDictionaryAddValue(vendorCFMutableDictionaryRef, kNameKeyCFStringRef, inVendorCFStringRef);
			results = true;
		}
		
		// if the product key exists in the vendor dictionary
		productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inProductID);
		if ( CFDictionaryGetValueIfPresent(vendorCFMutableDictionaryRef, productKeyCFStringRef,
		                                   (const void * *) &productCFMutableDictionaryRef) )
		{
			// copy it.
			productCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, productCFMutableDictionaryRef);
		} else {    // ...otherwise...
			// create it.
			productCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
			                                                          0,
			                                                          &kCFTypeDictionaryKeyCallBacks,
			                                                          &kCFTypeDictionaryValueCallBacks);
			results = true;
		}
		// if the product name key doesn't exist
		if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, kNameKeyCFStringRef) ) {
			// create it.
			CFDictionaryAddValue(productCFMutableDictionaryRef, kNameKeyCFStringRef, inProductCFStringRef);
			results = true;
		}
		if (vendorCFMutableDictionaryRef) {
			if (productCFMutableDictionaryRef) {
				if (results) {
					CFDictionarySetValue(vendorCFMutableDictionaryRef, productKeyCFStringRef, productCFMutableDictionaryRef);
				}
				
				CFRelease(productCFMutableDictionaryRef);
			}
			if (results) {
				CFDictionarySetValue(inCFMutableDictionaryRef, vendorKeyCFStringRef, vendorCFMutableDictionaryRef);
			}
			
			CFRelease(vendorCFMutableDictionaryRef);
		}
		if (productKeyCFStringRef) {
			CFRelease(productKeyCFStringRef);
		}
		if (vendorKeyCFStringRef) {
			CFRelease(vendorKeyCFStringRef);
		}
	}
	
	return (results);
}   // hu_AddVendorProductToCFDict

/*************************************************************************
 *
 * hu_AddDeviceElementToUsageXML(inDevice, inElement)
 *
 * Purpose: add a device and it's elements to our usage(XML) file
 *
 * Inputs: inDevice		- the device
 *			inElement	- the element
 *
 * Returns: Boolean		- if successful
 */
static Boolean hu_AddDeviceElementToUsageXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) {
	Boolean results = false;
	
	if (gUsageCFPropertyListRef) {
		CFRelease(gUsageCFPropertyListRef);
	}
	
	gUsageCFPropertyListRef =
	hu_XMLLoad(CFSTR("HID_device_usage_strings"), CFSTR("plist") );
	if (gUsageCFPropertyListRef) {
		CFMutableDictionaryRef tCFMutableDictionaryRef =
		CFDictionaryCreateMutableCopy(
									  kCFAllocatorDefault,
									  0,
									  gUsageCFPropertyListRef);
		if (tCFMutableDictionaryRef) {
			CFMutableDictionaryRef vendorCFMutableDictionaryRef;
			
			CFMutableDictionaryRef productCFMutableDictionaryRef;
			CFStringRef            productKeyCFStringRef;
			
			CFStringRef            usageKeyCFStringRef;
			
			// if the vendor dictionary exists...
			long        vendorID             = IOHIDDevice_GetVendorID(inIOHIDDeviceRef);
			CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), vendorID);
			if (vendorKeyCFStringRef) {
				if ( CFDictionaryGetValueIfPresent(tCFMutableDictionaryRef, vendorKeyCFStringRef,
				                                   (const void * *) &vendorCFMutableDictionaryRef) )
				{
					// ...copy it...
					vendorCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
					                                                             0,
					                                                             vendorCFMutableDictionaryRef);
				} else {        // ...otherwise...
					// ...create it.
					vendorCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
					                                                         0,
					                                                         &kCFTypeDictionaryKeyCallBacks,
					                                                         &kCFTypeDictionaryValueCallBacks);
					results = true;
				}
				// if the vendor name key doesn't exist...
				if ( !CFDictionaryContainsKey(vendorCFMutableDictionaryRef, kNameKeyCFStringRef) ) {
					CFStringRef manCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef);
					// ...create it.
					CFDictionaryAddValue(vendorCFMutableDictionaryRef, kNameKeyCFStringRef, manCFStringRef);
					results = true;
				}
				
				// if the product key exists in the vendor dictionary...
				long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef);
				productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), productID);
				if ( CFDictionaryGetValueIfPresent(vendorCFMutableDictionaryRef, productKeyCFStringRef,
				                                   (const void * *) &productCFMutableDictionaryRef) )
				{
					// ...copy it...
					productCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
					                                                              0,
					                                                              productCFMutableDictionaryRef);
				} else {        // ...otherwise...
					// ...create it.
					productCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault,
					                                                          0,
					                                                          &kCFTypeDictionaryKeyCallBacks,
					                                                          &kCFTypeDictionaryValueCallBacks);
					results = true;
				}
				// if the product name key doesn't exist...
				if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, kNameKeyCFStringRef) ) {
					CFStringRef productCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef);
					// ...create it.
					CFDictionaryAddValue(productCFMutableDictionaryRef, kNameKeyCFStringRef, productCFStringRef);
					results = true;
				}
				
				// if the usage key doesn't exist in the product dictionary...
				uint32_t usagePage =  IOHIDElementGetUsagePage(inIOHIDElementRef);
				uint32_t usage     =  IOHIDElementGetUsagePage(inIOHIDElementRef);
				usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld:%ld"), usagePage, usage);
				if (usageKeyCFStringRef) {
					if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, usageKeyCFStringRef) ) {
						// find it's generic name
						CFStringRef usageCFStringRef = HIDCopyUsageName(usagePage, usage);
						if (usageCFStringRef) {
							// and add that.
							CFDictionaryAddValue(productCFMutableDictionaryRef, usageKeyCFStringRef, usageCFStringRef);
							results = true;
							CFRelease(usageCFStringRef);
						}
					}
					
					CFRelease(usageKeyCFStringRef);
				}
				if (vendorCFMutableDictionaryRef) {
					if (productCFMutableDictionaryRef) {
						if (results) {
							CFDictionarySetValue(vendorCFMutableDictionaryRef, productKeyCFStringRef, productCFMutableDictionaryRef);
						}
						
						CFRelease(productCFMutableDictionaryRef);
					}
					if (results) {
						CFDictionarySetValue(tCFMutableDictionaryRef, vendorKeyCFStringRef, vendorCFMutableDictionaryRef);
					}
					
					CFRelease(vendorCFMutableDictionaryRef);
				}
				
				CFRelease(vendorKeyCFStringRef);
			}
			if (productKeyCFStringRef) {
				CFRelease(productKeyCFStringRef);
			}
			if (results) {
				hu_XMLSave( tCFMutableDictionaryRef, CFSTR("HID_device_usage_strings"), CFSTR("plist") );
			}
			
			CFRelease(tCFMutableDictionaryRef);
		}
	}
	
	return (results);
}   // hu_AddDeviceElementToUsageXML
#endif // if 0

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS