diff --git a/src/cocoa/HID_Config_Utilities.c b/src/cocoa/HID_Config_Utilities.c new file mode 100755 index 000000000..6cd1ad56a --- /dev/null +++ b/src/cocoa/HID_Config_Utilities.c @@ -0,0 +1,919 @@ +// File: HID_Config_Utilities.c +// Abstract: Implementation of the HID configuration 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#define LOG_SCORING 0 + +#include // malloc +#include // clock + +#include + +#include "HID_Utilities_External.h" + +// --------------------------------- + +// polls single device's elements for a change greater than kPercentMove. Times out after given time +// returns 1 and pointer to element if found +// returns 0 and NULL for both parameters if not found + +unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float timeout) { + if ( !inIOHIDDeviceRef ) { + return (0); + } + if ( 0 == HIDHaveDeviceList() ) { // if we do not have a device list + return (0); // return 0 + } + + Boolean found = FALSE; + + // build list of device and elements to save current values + int maxElements = HIDCountDeviceElements(inIOHIDDeviceRef, kHIDElementTypeInput); + int *saveValueArray = (int *) calloc( maxElements, sizeof(int) ); // 2D array to save values + + // store initial values on first pass / compare to initial value on subsequent passes + Boolean first = TRUE; + + // get all the elements from this device + CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + // if that worked... + if ( elementCFArrayRef ) { + clock_t start = clock(), end; + + // poll all devices and elements + while ( !found ) { + int currElementIndex = 0; + CFIndex idx, cnt = CFArrayGetCount(elementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + *outIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); + if ( !*outIOHIDElementRef ) { + continue; + } + + // is this an input element? + IOHIDElementType type = IOHIDElementGetType(*outIOHIDElementRef); + + switch ( type ) { + // these types are inputs + case kIOHIDElementTypeInput_Misc: + case kIOHIDElementTypeInput_Button: + case kIOHIDElementTypeInput_Axis: + case kIOHIDElementTypeInput_ScanCodes: + default: + { + break; + } + case kIOHIDElementTypeOutput: + case kIOHIDElementTypeFeature: + case kIOHIDElementTypeCollection: + { + *outIOHIDElementRef = NULL; // these types are not ( Skip them ) + break; + } + } /* switch */ + if ( !*outIOHIDElementRef ) { + continue; // skip this element + } + + // get this elements current value + int value = 0; // default value is zero + IOHIDValueRef tIOHIDValueRef; + IOReturn ioReturn = IOHIDDeviceGetValue(inIOHIDDeviceRef, *outIOHIDElementRef, &tIOHIDValueRef); + if ( kIOReturnSuccess == ioReturn ) { + value = IOHIDValueGetScaledValue(tIOHIDValueRef, kIOHIDValueScaleTypePhysical); + } + if ( first ) { + saveValueArray[currElementIndex] = value; + } else { + CFIndex min = IOHIDElementGetLogicalMin(*outIOHIDElementRef); + CFIndex max = IOHIDElementGetLogicalMax(*outIOHIDElementRef); + + int initialValue = saveValueArray[currElementIndex]; + int delta = (float)(max - min) * kPercentMove * 0.01; + // is the new value within +/- delta of the initial value? + if ( ( (initialValue + delta) < value ) || ( (initialValue - delta) > value ) ) { + found = 1; // ( yes! ) mark as found + break; + } + } // if ( first ) + + currElementIndex++; // bump element index + } // next idx + + first = FALSE; // no longer the first pass + + // are we done? + end = clock(); + double secs = (double)(end - start) / CLOCKS_PER_SEC; + if ( secs > timeout ) { + break; // ( yes ) timeout + } + } // while ( !found ) + + CFRelease(elementCFArrayRef); + } // if ( elementCFArrayRef ) + // return device and element moved + if ( found ) { + return (1); + } else { + *outIOHIDElementRef = NULL; + return (0); + } +} // HIDConfigureSingleDeviceAction + +//************************************************************************* +// +// HIDConfigureAction( outIOHIDDeviceRef, outIOHIDElementRef, inTimeout ) +// +// Purpose: polls all devices and elements for a change greater than kPercentMove. +// Times out after given time returns 1 and pointer to device and element +// if found; returns 0 and NULL for both parameters if not found +// +// Inputs: outIOHIDDeviceRef - address where to store the device +// outIOHIDElementRef - address where to store the element +// inTimeout - the timeout +// Returns: Boolean - if successful +// outIOHIDDeviceRef - the device +// outIOHIDElementRef - the element +// + +Boolean HIDConfigureAction(IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float inTimeout) { + // param error? + if ( !outIOHIDDeviceRef || !outIOHIDElementRef ) { + return (0); + } + if ( !gDeviceCFArrayRef ) { // if we do not have a device list + // and we can't build another list + if ( !HIDBuildDeviceList(0, 0) || !gDeviceCFArrayRef ) { + return (FALSE); // bail + } + } + + IOHIDDeviceRef tIOHIDDeviceRef; + IOHIDElementRef tIOHIDElementRef; + + // remember when we start; used to calculate timeout + clock_t start = clock(), end; + + // determine the maximum number of elements + CFIndex maxElements = 0; + CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef); + for ( devIndex = 0; devIndex < devCount; devIndex++ ) { + tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); + if ( !tIOHIDDeviceRef ) { + continue; // skip this one + } + + CFIndex count = HIDCountDeviceElements(tIOHIDDeviceRef, kHIDElementTypeInput); + if ( count > maxElements ) { + maxElements = count; + } + } + + // allocate an array of int's in which to store devCount * maxElements values + double *saveValueArray = (double *) calloc( devCount * maxElements, sizeof(double) ); // clear 2D array to save values + + // on first pass store initial values / compare current values to initial values on subsequent passes + Boolean found = FALSE, first = TRUE; + + while ( !found ) { + double maxDeltaPercent = 0; // we want to find the one that moves the most ( percentage wise ) + for ( devIndex = 0; devIndex < devCount; devIndex++ ) { + tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); + if ( !tIOHIDDeviceRef ) { + continue; // skip this one + } + +#ifdef DEBUG + long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); + long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); +#endif + gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + if ( gElementCFArrayRef ) { + CFIndex eleIndex, eleCount = CFArrayGetCount(gElementCFArrayRef); + for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) { + tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, eleIndex); + if ( !tIOHIDElementRef ) { + continue; + } + + IOHIDElementType tIOHIDElementType = IOHIDElementGetType(tIOHIDElementRef); + // only care about inputs (no outputs or features) + if ( tIOHIDElementType <= kIOHIDElementTypeInput_ScanCodes ) { + if ( IOHIDElementIsArray(tIOHIDElementRef) ) { + //printf( "ARRAY!\n" ); + continue; // skip array elements + } + + uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); + uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); + uint32_t reportCount = IOHIDElementGetReportCount(tIOHIDElementRef); +#ifdef DEBUG + if ( first ) { + IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); + printf("%s, dev: {ref:%p, ven: 0x%08lX, pro: 0x%08lX}, ele: {ref:%p, cookie: %p, usage:%04lX:%08lX}\n", + __PRETTY_FUNCTION__, + tIOHIDDeviceRef, + vendorID, + productID, + tIOHIDElementRef, + cookie, + (long unsigned int) usagePage, + (long unsigned int) usage); + fflush(stdout); + if ( (0x054C == vendorID) && (0x0268 == productID) && (0x001E == (UInt32) cookie) ) { + //printf( "DING!\n" ); + } + } + +#endif +#if 1 // work-around for IOHIDValueGetScaledValue crash (when element report count > 1) + if ( reportCount > 1 ) { + //printf( "REPORT!\n" ); + continue; // skip reports + } + +#endif + // ignore PID elements and arrays + if ( (kHIDPage_PID != usagePage) && (((uint32_t)-1) != usage) ) { + // get this elements current value + double value = 0.0; // default value is zero + IOHIDValueRef tIOHIDValueRef; + IOReturn ioReturn = IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &tIOHIDValueRef); + if ( kIOReturnSuccess == ioReturn ) { + value = IOHIDValueGetScaledValue(tIOHIDValueRef, kIOHIDValueScaleTypePhysical); + } + if ( first ) { + saveValueArray[(devIndex * maxElements) + eleIndex] = value; + } else { + double initialValue = saveValueArray[(devIndex * maxElements) + eleIndex]; + + CFIndex valueMin = IOHIDElementGetPhysicalMin(tIOHIDElementRef); + CFIndex valueMax = IOHIDElementGetPhysicalMax(tIOHIDElementRef); + + double deltaPercent = fabs( (initialValue - value) * 100.0 / (valueMax - valueMin) ); +#if 0 // debug code useful to dump out value info for specific (vendorID, productID, usagePage and usage) device + if ( !first ) { + // Device: 0x13b6a0 = { Logitech Inc. - WingMan Force 3D, vendorID: 0x046D, productID: 0xC283, + // usage: 0x0001:0x0004, "Generic Desktop Joystick" + if ( (vendorID == 0x046D) && (productID == 0xC283) ) { + if ( (kHIDPage_GenericDesktop == usagePage) && (kHIDUsage_GD_Rz == usage) ) { + printf("initial: %6.2f, value: %6.2f, diff: %6.2f, delta percent: %6.2f!\n", + initialValue, + value, + fabs(initialValue - value), + deltaPercent); + } + } + } + + deltaPercent = 0.0; +#endif + if ( deltaPercent >= kPercentMove ) { + found = TRUE; + if ( deltaPercent > maxDeltaPercent ) { + maxDeltaPercent = deltaPercent; + + *outIOHIDDeviceRef = tIOHIDDeviceRef; + *outIOHIDElementRef = tIOHIDElementRef; + } + + break; + } + } // if first + + } // if usage + + } // if type + + } // for elements... + + CFRelease(gElementCFArrayRef); + gElementCFArrayRef = NULL; + } // if ( gElementCFArrayRef ) + if ( found ) { + // HIDDumpElementInfo( tIOHIDElementRef ); + break; // DONE! + } + } // for devices + + first = FALSE; // no longer the first pass + + // are we done? + end = clock(); + double secs = (double)(end - start) / CLOCKS_PER_SEC; + if ( secs > inTimeout ) { + break; // ( yes ) timeout + } + } // while ( !found ) + // return device and element moved + if ( !found ) { + *outIOHIDDeviceRef = NULL; + *outIOHIDElementRef = NULL; + } + + return (found); +} // HIDConfigureAction + +//************************************************************************* +// +// HIDSaveElementPref( inKeyCFStringRef, inAppCFStringRef, inIOHIDDeviceRef, inIOHIDElementRef ) +// +// Purpose: Save the device & element values into the specified key in the specified applications preferences +// +// Inputs: inKeyCFStringRef - the preference key +// inAppCFStringRef - the application identifier +// inIOHIDDeviceRef - the device +// inIOHIDElementRef - the element +// Returns: Boolean - if successful +// + +Boolean HIDSaveElementPref(const CFStringRef inKeyCFStringRef, + CFStringRef inAppCFStringRef, + IOHIDDeviceRef inIOHIDDeviceRef, + IOHIDElementRef inIOHIDElementRef) { + Boolean success = FALSE; + if ( inKeyCFStringRef && inAppCFStringRef && inIOHIDDeviceRef && inIOHIDElementRef ) { + long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); + require(vendorID, Oops); + + long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); + require(productID, Oops); + + long locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); + require(locID, Oops); + + uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); + uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); + if ( !usagePage || !usage ) { + usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); + usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef); + } + + require(usagePage && usage, Oops); + + uint32_t usagePageE = IOHIDElementGetUsagePage(inIOHIDElementRef); + uint32_t usageE = IOHIDElementGetUsage(inIOHIDElementRef); + IOHIDElementCookie eleCookie = IOHIDElementGetCookie(inIOHIDElementRef); + + CFStringRef prefCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("d:{v:%ld, p:%ld, l:%ld, p:%ld, u:%ld}, e:{p:%ld, u:%ld, c:%ld}"), + vendorID, productID, locID, usagePage, usage, + usagePageE, usageE, eleCookie); + if ( prefCFStringRef ) { + CFPreferencesSetAppValue(inKeyCFStringRef, prefCFStringRef, inAppCFStringRef); + CFRelease(prefCFStringRef); + success = TRUE; + } + } + +Oops: ; + return (success); +} // HIDSaveElementPref + +//************************************************************************* +// +// HIDRestoreElementPref( inKeyCFStringRef, inAppCFStringRef, outIOHIDDeviceRef, outIOHIDElementRef ) +// +// Purpose: Find the specified preference in the specified application +// +// Inputs: inKeyCFStringRef - the preference key +// inAppCFStringRef - the application identifier +// outIOHIDDeviceRef - address where to restore the device +// outIOHIDElementRef - address where to restore the element +// Returns: Boolean - if successful +// outIOHIDDeviceRef - the device +// outIOHIDElementRef - the element +// + +Boolean HIDRestoreElementPref(CFStringRef inKeyCFStringRef, + CFStringRef inAppCFStringRef, + IOHIDDeviceRef * outIOHIDDeviceRef, + IOHIDElementRef *outIOHIDElementRef) { + Boolean found = FALSE; + if ( inKeyCFStringRef && inAppCFStringRef && outIOHIDDeviceRef && outIOHIDElementRef ) { + CFPropertyListRef prefCFPropertyListRef = CFPreferencesCopyAppValue(inKeyCFStringRef, inAppCFStringRef); + if ( prefCFPropertyListRef ) { + if ( CFStringGetTypeID() == CFGetTypeID(prefCFPropertyListRef) ) { + char buffer[256]; + if ( CFStringGetCString( (CFStringRef) prefCFPropertyListRef, buffer, sizeof(buffer), + kCFStringEncodingUTF8 ) ) + { + HID_info_rec searchHIDInfo; + + int count = sscanf(buffer, + "d:{v:%d, p:%d, l:%d, p:%d, u:%d}, e:{p:%d, u:%d, c:%ld}", + &searchHIDInfo.device.vendorID, + &searchHIDInfo.device.productID, + &searchHIDInfo.device.locID, + &searchHIDInfo.device.usagePage, + &searchHIDInfo.device.usage, + &searchHIDInfo.element.usagePage, + &searchHIDInfo.element.usage, + (long *) &searchHIDInfo.element.cookie); + if ( 8 == count ) { // if we found all eight parametersā€¦ + // and can find a device & element that matches theseā€¦ + if ( HIDFindDeviceAndElement(&searchHIDInfo, outIOHIDDeviceRef, outIOHIDElementRef) ) { + found = TRUE; + } + } + } + } else { + // We found the entry with this key but it's the wrong type; delete it. + CFPreferencesSetAppValue(inKeyCFStringRef, NULL, inAppCFStringRef); + (void) CFPreferencesAppSynchronize(inAppCFStringRef); + } + + CFRelease(prefCFPropertyListRef); + } + } + + return (found); +} // HIDRestoreElementPref + +//************************************************************************* +// +// HIDFindDeviceAndElement( inSearchInfo, outFoundDevice, outFoundElement ) +// +// Purpose: find the closest matching device and element for this action +// +// Notes: matches device: serial, vendorID, productID, location, inUsagePage, usage +// matches element: cookie, inUsagePage, usage, +// +// Inputs: inSearchInfo - the device & element info we searching for +// outFoundDevice - the address of the best matching device +// outFoundElement - the address of the best matching element +// +// Returns: Boolean - TRUE if we find a match +// outFoundDevice - the best matching device +// outFoundElement - the best matching element +// + +Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo, IOHIDDeviceRef *outFoundDevice, IOHIDElementRef *outFoundElement) { + Boolean result = FALSE; + + IOHIDDeviceRef bestIOHIDDeviceRef = NULL; + IOHIDElementRef bestIOHIDElementRef = NULL; + long bestScore = 0; + + CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef); + for ( devIndex = 0; devIndex < devCount; devIndex++ ) { + long deviceScore = 1; + + IOHIDDeviceRef tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); + if ( !tIOHIDDeviceRef ) { + continue; + } + // match vendorID, productID (+10, +8) + if ( inSearchInfo->device.vendorID ) { + long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); + if ( vendorID ) { + if ( inSearchInfo->device.vendorID == vendorID ) { + deviceScore += 10; + if ( inSearchInfo->device.productID ) { + long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); + if ( productID ) { + if ( inSearchInfo->device.productID == productID ) { + deviceScore += 8; + } // if ( inSearchInfo->device.productID == productID ) + + } // if ( productID ) + + } // if ( inSearchInfo->device.productID ) + + } // if (inSearchInfo->device.vendorID == vendorID) + + } // if vendorID + + } // if search->device.vendorID + // match usagePage & usage (+9) + if ( inSearchInfo->device.usagePage && inSearchInfo->device.usage ) { + uint32_t usagePage = IOHIDDevice_GetUsagePage(tIOHIDDeviceRef) ; + uint32_t usage = IOHIDDevice_GetUsage(tIOHIDDeviceRef); + if ( !usagePage || !usage ) { + usagePage = IOHIDDevice_GetPrimaryUsagePage(tIOHIDDeviceRef); + usage = IOHIDDevice_GetPrimaryUsage(tIOHIDDeviceRef); + } + if ( usagePage ) { + if ( inSearchInfo->device.usagePage == usagePage ) { + if ( usage ) { + if ( inSearchInfo->device.usage == usage ) { + deviceScore += 9; + } // if ( inSearchInfo->usage == usage ) + + } // if ( usage ) + + } // if ( inSearchInfo->usagePage == usagePage ) + + } // if ( usagePage ) + + } // if ( inSearchInfo->usagePage && inSearchInfo->usage ) + // match location ID (+5) + if ( inSearchInfo->device.locID ) { + long locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef); + if ( locID ) { + if ( inSearchInfo->device.locID == locID ) { + deviceScore += 5; + } + } + } + + // iterate over all elements of this device + gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0); + if ( gElementCFArrayRef ) { + CFIndex eleIndex, eleCount = CFArrayGetCount(gElementCFArrayRef); + for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) { + IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, eleIndex); + if ( !tIOHIDElementRef ) { + continue; + } + + long score = deviceScore; + // match usage page, usage & cookie + if ( inSearchInfo->element.usagePage && inSearchInfo->element.usage ) { + uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); + if ( inSearchInfo->element.usagePage == usagePage ) { + uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); + if ( inSearchInfo->element.usage == usage ) { + score += 5; + IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); + if ( inSearchInfo->element.cookie == cookie ) { + score += 4; + } // cookies match + + } else { + score = 0; + } // usages match + + } else { + score = 0; + } // usage pages match + + } // if ( search usage page & usage ) + +#if LOG_SCORING + if ( kHIDPage_KeyboardOrKeypad != tElementRef->usagePage ) { // skip keyboards here + printf("%s: ( %ld:%ld )-I-Debug, score: %ld\t", + __PRETTY_FUNCTION__, + inSearchInfo->element.usagePage, + inSearchInfo->element.usage, + score); + HIDPrintElement(tIOHIDElementRef); + } + +#endif // LOG_SCORING + if ( score > bestScore ) { + bestIOHIDDeviceRef = tIOHIDDeviceRef; + bestIOHIDElementRef = tIOHIDElementRef; + bestScore = score; +#if LOG_SCORING + printf("%s: ( %ld:%ld )-I-Debug, better score: %ld\t", + __PRETTY_FUNCTION__, + inSearchInfo->element.usagePage, + inSearchInfo->element.usage, + score); + HIDPrintElement(bestIOHIDElementRef); +#endif // LOG_SCORING + } + } // for elements... + + CFRelease(gElementCFArrayRef); + gElementCFArrayRef = NULL; + } // if ( gElementCFArrayRef ) + + } // for ( devIndex = 0; devIndex < devCount; devIndex++ ) + if ( bestIOHIDDeviceRef || bestIOHIDElementRef ) { + *outFoundDevice = bestIOHIDDeviceRef; + *outFoundElement = bestIOHIDElementRef; +#if LOG_SCORING + printf("%s: ( %ld:%ld )-I-Debug, best score: %ld\t", + __PRETTY_FUNCTION__, + inSearchInfo->element.usagePage, + inSearchInfo->element.usage, + bestScore); + HIDPrintElement(bestIOHIDElementRef); +#endif // LOG_SCORING + result = TRUE; + } + + return (result); +} // HIDFindDeviceAndElement + +// --------------------------------- + +// takes input records, save required info +// assume file is open and at correct position. +// will always write to file (if file exists) size of HID_info_rec, even if device and or element is bad + +void HIDSaveElementConfig(FILE *fileRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef, int actionCookie) { + // must save: + // actionCookie + // Device: serial,vendorID, productID, location, usagePage, usage + // Element: cookie, usagePage, usage, + HID_info_rec hidInfoRec; + HIDSetElementConfig(&hidInfoRec, inIOHIDDeviceRef, inIOHIDElementRef, actionCookie); + // write to file + if ( fileRef ) { + fwrite( (void *)&hidInfoRec, sizeof(HID_info_rec), 1, fileRef ); + } +} // HIDSaveElementConfig + +// --------------------------------- + +// take file, read one record (assume file position is correct and file is open) +// search for matching device +// return pDevice, pElement and cookie for action + +int HIDRestoreElementConfig(FILE *fileRef, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef) { + // Device: serial,vendorID, productID, location, usagePage, usage + // Element: cookie, usagePage, usage, + + HID_info_rec hidInfoRec; + fread( (void *) &hidInfoRec, 1, sizeof(HID_info_rec), fileRef ); + return ( HIDGetElementConfig(&hidInfoRec, outIOHIDDeviceRef, outIOHIDElementRef) ); +} // HIDRestoreElementConfig + +// --------------------------------- + +// Set up a config record for saving +// takes an input records, returns record user can save as they want +// Note: the save rec must be pre-allocated by the calling app and will be filled out +void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr, + IOHIDDeviceRef inIOHIDDeviceRef, + IOHIDElementRef inIOHIDElementRef, + int actionCookie) { + // must save: + // actionCookie + // Device: serial,vendorID, productID, location, usagePage, usage + // Element: cookie, usagePage, usage, + inHIDInfoPtr->actionCookie = actionCookie; + // device + // need to add serial number when I have a test case + if ( inIOHIDDeviceRef && inIOHIDElementRef ) { + inHIDInfoPtr->device.vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); + inHIDInfoPtr->device.productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); + inHIDInfoPtr->device.locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); + inHIDInfoPtr->device.usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); + inHIDInfoPtr->device.usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); + + inHIDInfoPtr->element.usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); + inHIDInfoPtr->element.usage = IOHIDElementGetUsage(inIOHIDElementRef); + inHIDInfoPtr->element.minReport = IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef); + inHIDInfoPtr->element.maxReport = IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef); + inHIDInfoPtr->element.cookie = IOHIDElementGetCookie(inIOHIDElementRef); + } else { + inHIDInfoPtr->device.vendorID = 0; + inHIDInfoPtr->device.productID = 0; + inHIDInfoPtr->device.locID = 0; + inHIDInfoPtr->device.usage = 0; + inHIDInfoPtr->device.usagePage = 0; + + inHIDInfoPtr->element.usagePage = 0; + inHIDInfoPtr->element.usage = 0; + inHIDInfoPtr->element.minReport = 0; + inHIDInfoPtr->element.maxReport = 0; + inHIDInfoPtr->element.cookie = 0; + } +} // HIDSetElementConfig + +// --------------------------------- +#if 0 // debug utility function to dump config record +void HIDDumpConfig(HID_info_ptr inHIDInfoPtr) { + printf( + "Config Record for action: %d\n\t vendor: %d product: %d location: %d\n\t usage: %d usagePage: %d\n\t element.usagePage: %d element.usage: %d\n\t minReport: %d maxReport: %d\n\t cookie: %d\n", + inHIDInfoPtr->actionCookie, + inHIDInfoPtr->device.vendorID, + inHIDInfoPtr->device.productID, + inHIDInfoPtr->locID, + inHIDInfoPtr->usage, + inHIDInfoPtr->usagePage, + inHIDInfoPtr->element.usagePage, + inHIDInfoPtr->element.usage, + inHIDInfoPtr->minReport, + inHIDInfoPtr->maxReport, + inHIDInfoPtr->cookie); +} // HIDDumpConfig +#endif // 0 +// --------------------------------- + +// Get matching element from config record +// takes a pre-allocated and filled out config record +// search for matching device +// return pDevice, pElement and cookie for action +int HIDGetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef) { + if ( !inHIDInfoPtr->device.locID && !inHIDInfoPtr->device.vendorID && !inHIDInfoPtr->device.productID && !inHIDInfoPtr->device.usage + && !inHIDInfoPtr->device.usagePage ) // + { // + // early out + *outIOHIDDeviceRef = NULL; + *outIOHIDElementRef = NULL; + return (inHIDInfoPtr->actionCookie); + } + + IOHIDDeviceRef tIOHIDDeviceRef, foundIOHIDDeviceRef = NULL; + IOHIDElementRef tIOHIDElementRef, foundIOHIDElementRef = NULL; + + CFIndex devIdx, devCnt, idx, cnt; + // compare to current device list for matches + // look for device + if ( inHIDInfoPtr->device.locID && inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID ) { // look for specific device + // type plug in to same port + devCnt = CFArrayGetCount(gDeviceCFArrayRef); + for ( devIdx = 0; devIdx < devCnt; devIdx++ ) { + tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIdx); + if ( !tIOHIDDeviceRef ) { + continue; // skip this device + } + + long locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef); + long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); + long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); + if ( (inHIDInfoPtr->device.locID == locID) + && (inHIDInfoPtr->device.vendorID == vendorID) + && (inHIDInfoPtr->device.productID == productID) ) + { + foundIOHIDDeviceRef = tIOHIDDeviceRef; + } + if ( foundIOHIDDeviceRef ) { + break; + } + } // next devIdx + if ( foundIOHIDDeviceRef ) { + CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + if ( elementCFArrayRef ) { + cnt = CFArrayGetCount(elementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; // skip this element + } + + IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); + if ( inHIDInfoPtr->element.cookie == cookie ) { + foundIOHIDElementRef = tIOHIDElementRef; + } + if ( foundIOHIDElementRef ) { + break; + } + } + if ( !foundIOHIDElementRef ) { + cnt = CFArrayGetCount(elementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; // skip this element + } + + uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); + uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); + if ( (inHIDInfoPtr->element.usage == usage) && (inHIDInfoPtr->element.usagePage == usagePage) ) { + foundIOHIDElementRef = tIOHIDElementRef; + } + if ( foundIOHIDElementRef ) { + break; + } + } // next idx + + } // if ( !foundIOHIDElementRef ) + if ( foundIOHIDElementRef ) { // if same device + // setup the calibration + IOHIDElement_SetupCalibration(tIOHIDElementRef); + + IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef, inHIDInfoPtr->element.minReport); + IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef, inHIDInfoPtr->element.maxReport); + } + + CFRelease(elementCFArrayRef); + } // if ( elementCFArrayRef ) + + } // if ( foundIOHIDDeviceRef ) + // if we have not found a match, look at just vendor and product + if ( (!foundIOHIDDeviceRef) && (inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID) ) { + devCnt = CFArrayGetCount(gDeviceCFArrayRef); + for ( devIdx = 0; devIdx < devCnt; devIdx++ ) { + tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIdx); + if ( !tIOHIDDeviceRef ) { + continue; // skip this device + } + + long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); + long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); + if ( (inHIDInfoPtr->device.vendorID == vendorID) + && (inHIDInfoPtr->device.productID == productID) ) + { + foundIOHIDDeviceRef = tIOHIDDeviceRef; + } + if ( foundIOHIDDeviceRef ) { + break; + } + } + // match elements by cookie since same device type + if ( foundIOHIDDeviceRef ) { + CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + if ( elementCFArrayRef ) { + cnt = CFArrayGetCount(elementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; // skip this element + } + + IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); + if ( inHIDInfoPtr->element.cookie == cookie ) { + foundIOHIDElementRef = tIOHIDElementRef; + } + if ( foundIOHIDElementRef ) { + break; + } + } + // if no cookie match (should NOT occur) match on usage + if ( !foundIOHIDElementRef ) { + cnt = CFArrayGetCount(elementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; // skip this element + } + + uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); + uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); + if ( (inHIDInfoPtr->element.usage == usage) + && (inHIDInfoPtr->element.usagePage == usagePage) ) + { + foundIOHIDElementRef = tIOHIDElementRef; + } + if ( foundIOHIDElementRef ) { + break; + } + } // next idx + + } // if ( !foundIOHIDElementRef ) + if ( foundIOHIDElementRef ) { // if same device + // setup the calibration + IOHIDElement_SetupCalibration(tIOHIDElementRef); + IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef, inHIDInfoPtr->element.minReport); + IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef, inHIDInfoPtr->element.maxReport); + } + + CFRelease(elementCFArrayRef); + } // if ( elementCFArrayRef ) + + } // if ( foundIOHIDDeviceRef ) + + } // if ( device not found & vendorID & productID ) + + } // if ( inHIDInfoPtr->locID && inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID ) + // can't find matching device return NULL, do not return first device + if ( (!foundIOHIDDeviceRef) || (!foundIOHIDElementRef) ) { + // no HID device + *outIOHIDDeviceRef = NULL; + *outIOHIDElementRef = NULL; + return (inHIDInfoPtr->actionCookie); + } else { + // HID device + *outIOHIDDeviceRef = foundIOHIDDeviceRef; + *outIOHIDElementRef = foundIOHIDElementRef; + return (inHIDInfoPtr->actionCookie); + } +} // HIDGetElementConfig diff --git a/src/cocoa/HID_Error_Handler.c b/src/cocoa/HID_Error_Handler.c new file mode 100755 index 000000000..8aaca7f36 --- /dev/null +++ b/src/cocoa/HID_Error_Handler.c @@ -0,0 +1,101 @@ +// File: HID_Error_Handler.c +// Abstract: Implementation of the HID utilities error handlers +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#ifdef DEBUG // not used in release +#if !defined (kBuildingLibrary) +#define kVerboseErrors + +// system includes ---------------------------------------------------------- + +#ifdef kVerboseErrors +//#include +#endif +#endif // not kBuildingLibrary +#endif // DEBUG + +#include + +// project includes --------------------------------------------------------- + +#include "HID_Utilities_External.h" + +// globals (internal/private) ----------------------------------------------- + +// prototypes (internal/private) -------------------------------------------- + +// functions (internal/private) --------------------------------------------- + +#pragma mark - +// ------------------------------------- + +// central error reporting + +void HIDReportErrorNum(const char *strError, int numError) { + char errMsgCStr[256]; + + sprintf(errMsgCStr, "%s #%d (0x%x)", strError, numError, numError); + + // out as debug string +#ifdef kVerboseErrors + { + fputs(errMsgCStr, stderr); + } +#endif // kVerboseErrors +} // HIDReportErrorNum + +// ------------------------------------- + +void HIDReportError(const char *strError) { + char errMsgCStr[256]; + + sprintf(errMsgCStr, "%s", strError); + + // out as debug string +#ifdef kVerboseErrors + { + fputs(errMsgCStr, stderr); + } +#endif // kVerboseErrors +} // HIDReportError diff --git a/src/cocoa/HID_Name_Lookup.c b/src/cocoa/HID_Name_Lookup.c new file mode 100755 index 000000000..4e4b023bd --- /dev/null +++ b/src/cocoa/HID_Name_Lookup.c @@ -0,0 +1,1203 @@ +// 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) 2009 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 0 // currently unused +static SInt32 hu_SaveToXMLFile(CFPropertyListRef inCFPRef, CFURLRef inCFURLRef); +static SInt32 hu_XMLSave(CFPropertyListRef inCFPropertyListRef, CFStringRef inResourceName, CFStringRef inResourceExtension); +#endif +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 0 // 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 +//***************************************************** +#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 + 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 0 // 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 0 // 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 ( 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 +/************************************************************************* + * + * 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 + +//************************************************************************* +// +// 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 + 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 0 // 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 +/************************************************************************* + * + * 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 0 // 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 +/************************************************************************* + * + * 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 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 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 + } + + // 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 + } + + 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 + } + + CFRelease(productKeyCFStringRef); + } + +#if FAKE_MISSING_NAMES + if ( vendorCFStringRef ) { + CFRelease(vendorCFStringRef); + } + +#endif + } + + CFRelease(vendorKeyCFStringRef); + } + } + + // ++ CFRelease( gUsageCFPropertyListRef ); // Leak this ! + } + + return (results); +} // hu_XMLSearchForProductNameByVendorProductID + +/************************************************************************* + * + * hu_XMLSearchForElementNameByCookie( inVendorID, inProductID, inCookie, outCStr ) + * + * Purpose: Find an element string in the 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("%ld"), inCookie); + if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, cookieKeyCFStringRef, + (const void **) &cookieCFStringRef) ) + { +#if VERBOSE_ELEMENT_NAMES + fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( + "%@ %@ %@"), vendorCFStringRef, productCFStringRef, + cookieCFStringRef); +#else + 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 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 + 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 0 // 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 diff --git a/src/cocoa/HID_Queue_Utilities.c b/src/cocoa/HID_Queue_Utilities.c new file mode 100755 index 000000000..586609d7f --- /dev/null +++ b/src/cocoa/HID_Queue_Utilities.c @@ -0,0 +1,354 @@ +// File: HID_Queue_Utilities.c +// Abstract: HID Queue 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#include "HID_Utilities_External.h" + +// ================================== +// private functions + +// creates a queue for a device, creates and opens device interface if required +static IOReturn HIDCreateQueue(IOHIDDeviceRef inIOHIDDeviceRef) { + IOReturn result = kIOReturnSuccess; + if ( inIOHIDDeviceRef ) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + + // do we already have a queue? + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( tIOHIDQueueRef ) { // (yes) + assert( IOHIDQueueGetTypeID() == CFGetTypeID(tIOHIDQueueRef) ); + } else { + tIOHIDQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, inIOHIDDeviceRef, kDeviceQueueSize, kIOHIDOptionsTypeNone); + if ( tIOHIDQueueRef ) { // did that work + IOHIDDevice_SetQueue(inIOHIDDeviceRef, tIOHIDQueueRef); + result = kIOReturnSuccess; + } else { + HIDReportErrorNum("Failed to create queue via create", result); + } + } + } else { + HIDReportErrorNum("HID device ref does not exist for queue creation", result); + } + + return (result); +} /* HIDCreateQueue */ + +// --------------------------------- +// returns true if queue is empty false otherwise +// error if no device, empty if no queue +static unsigned char HIDIsDeviceQueueEmpty(IOHIDDeviceRef inIOHIDDeviceRef) { + if ( inIOHIDDeviceRef ) { // need device and queue + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( tIOHIDQueueRef ) { + IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO); + + while ( tIOHIDElementRef ) { + if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) { + return (false); + } + + tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO); + } + } else { + HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty."); + } + } else { + HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty."); + } + + return (true); +} /* HIDIsDeviceQueueEmpty */ + +// --------------------------------- + +// disposes and releases queue, sets queue to NULL,. +// Note: will have no effect if device or queue do not exist +static IOReturn HIDDisposeReleaseQueue(IOHIDDeviceRef inIOHIDDeviceRef) { + IOReturn result = kIOReturnSuccess; + if ( inIOHIDDeviceRef ) { + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( tIOHIDQueueRef ) { + // stop queue + IOHIDQueueStop(tIOHIDQueueRef); + + // release the queue + CFRelease(tIOHIDQueueRef); + } + } else { + HIDReportError("NULL device passed to HIDDisposeReleaseQueue."); + } + + return (result); +} /* HIDDisposeReleaseQueue */ + +// ================================== +// public functions +// ---------------------------------- + +// queues specific element, performing any device queue set up required +// queue is started and ready to return events on exit from this function +int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) { + IOReturn result = kIOReturnSuccess; + if ( inIOHIDDeviceRef ) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + if ( inIOHIDElementRef ) { + assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) ); + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( !tIOHIDQueueRef ) { // if no queue create queue + result = HIDCreateQueue(inIOHIDDeviceRef); + if ( kIOReturnSuccess == result ) { + tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + } + } + if ( tIOHIDQueueRef ) { + // stop queue + IOHIDQueueStop(tIOHIDQueueRef); + // queue element + if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) { + IOHIDQueueAddElement(tIOHIDQueueRef, inIOHIDElementRef); + } + + // restart queue + IOHIDQueueStart(tIOHIDQueueRef); + } else { + HIDReportError("No queue for device passed to HIDQueueElement."); + if ( kIOReturnSuccess == result ) { + result = kIOReturnError; + } + } + } else { + HIDReportError("NULL element passed to HIDQueueElement."); + result = kIOReturnBadArgument; + } + } else { + HIDReportError("NULL device passed to HIDQueueElement."); + result = kIOReturnBadArgument; + } + + return (result); +} /* HIDQueueElement */ +// --------------------------------- + +// adds all elements to queue, performing any device queue set up required +// queue is started and ready to return events on exit from this function +int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef) { + IOReturn result = kIOReturnSuccess; + // error checking + if ( !inIOHIDDeviceRef ) { + HIDReportError("Device does not exist, cannot queue device."); + return (kIOReturnBadArgument); + } + if ( !inIOHIDDeviceRef ) { // must have interface + HIDReportError("Device does not have hid device ref, cannot queue device."); + return (kIOReturnError); + } + + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( !tIOHIDQueueRef ) { // if no queue create queue + result = HIDCreateQueue(inIOHIDDeviceRef); + if ( kIOReturnSuccess == result ) { + tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + } + } + if ( (kIOReturnSuccess != result) || (!tIOHIDQueueRef) ) { + HIDReportErrorNum("Could not queue device due to problem creating queue.", result); + if ( kIOReturnSuccess != result ) { + return (result); + } else { + return (kIOReturnError); + } + } + + // stop queue + IOHIDQueueStop(tIOHIDQueueRef); + + // queue element + IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO); + + while ( tIOHIDElementRef ) { + if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) { + IOHIDQueueAddElement(tIOHIDQueueRef, tIOHIDElementRef); + } + + tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO); + } + + // restart queue + IOHIDQueueStart(tIOHIDQueueRef); + + return (result); +} /* HIDQueueDevice */ + +// --------------------------------- +// removes element for queue, if last element in queue will release queue and closes device interface +int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) { + IOReturn result = kIOReturnSuccess; + if ( inIOHIDDeviceRef ) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + if ( inIOHIDElementRef ) { + assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) ); + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( tIOHIDQueueRef ) { + // stop queue + IOHIDQueueStop(tIOHIDQueueRef); + // de-queue element + if ( IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) { + IOHIDQueueRemoveElement(tIOHIDQueueRef, inIOHIDElementRef); + } + // release device queue and close interface if queue empty + if ( HIDIsDeviceQueueEmpty(inIOHIDDeviceRef) ) { + result = HIDDisposeReleaseQueue(inIOHIDDeviceRef); + if ( kIOReturnSuccess != result ) { + HIDReportErrorNum("Failed to dispose and release queue.", result); + } + } else { // not empty so restart queue + IOHIDQueueStart(tIOHIDQueueRef); + } + } else { + HIDReportError("No queue for device passed to HIDDequeueElement."); + if ( kIOReturnSuccess == result ) { + result = kIOReturnError; + } + } + } else { + HIDReportError("NULL element passed to HIDDequeueElement."); + result = kIOReturnBadArgument; + } + } else { + HIDReportError("NULL device passed to HIDDequeueElement."); + result = kIOReturnBadArgument; + } + + return (result); +} /* HIDDequeueElement */ + +// --------------------------------- +// completely removes all elements from queue and releases queue and closes device interface +// does not release device interfaces, application must call ReleaseHIDDeviceList on exit +int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef) { + IOReturn result = kIOReturnSuccess; + // error checking + if ( !inIOHIDDeviceRef ) { + HIDReportError("Device does not exist, cannot queue device."); + return (kIOReturnBadArgument); + } + if ( !inIOHIDDeviceRef ) { // must have interface + HIDReportError("Device does not have hid device ref, cannot queue device."); + return (kIOReturnError); + } + + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( tIOHIDQueueRef ) { + // iterate through elements and if queued, remove + IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO); + + while ( tIOHIDElementRef ) { + // de-queue element + if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) { + IOHIDQueueRemoveElement(tIOHIDQueueRef, tIOHIDElementRef); + } + + tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO); + } + + // ensure queue is disposed and released + result = HIDDisposeReleaseQueue(inIOHIDDeviceRef); + if ( kIOReturnSuccess != result ) { + HIDReportErrorNum("Failed to dispose and release queue.", result); + } + } else { + HIDReportError("No queue for device passed to HIDDequeueElement."); + if ( kIOReturnSuccess == result ) { + result = kIOReturnError; + } + } + + return (result); +} /* HIDDequeueDevice */ +// --------------------------------- + +// releases all device queues for quit or rebuild (must be called) +// does not release device interfaces, application must call ReleaseHIDDeviceList on exit +IOReturn HIDReleaseAllDeviceQueues(void) { + IOReturn result = kIOReturnSuccess; + IOHIDDeviceRef tIOHIDDeviceRef = HIDGetFirstDevice(); + + while ( tIOHIDDeviceRef ) { + result = HIDDequeueDevice(tIOHIDDeviceRef); + if ( kIOReturnSuccess != result ) { + HIDReportErrorNum("Could not dequeue device.", result); + } + + tIOHIDDeviceRef = HIDGetNextDevice(tIOHIDDeviceRef); + } + + return (result); +} /* HIDReleaseAllDeviceQueues */ + +// --------------------------------- +// Get the next event in the queue for a device +// elements or entire device should be queued prior to calling this with HIDQueueElement or HIDQueueDevice +// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise +// Note: kIOReturnUnderrun returned from getNextEvent indicates an empty queue not an error condition +// Note: application should pass in a pointer to a IOHIDEventStruct cast to a void (for CFM compatibility) +unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef) { + if ( inIOHIDDeviceRef ) { + IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( tIOHIDQueueRef ) { + if ( pIOHIDValueRef ) { + *pIOHIDValueRef = IOHIDQueueCopyNextValueWithTimeout(tIOHIDQueueRef, 0.0); + if ( *pIOHIDValueRef ) { + return (true); + } + } + } else { + HIDReportError("Could not get HID event, hid queue reference does not exist."); + } + } else { + HIDReportError("Could not get HID event, device does not exist."); + } + + return (false); // did not get event +} /* HIDGetEvent */ diff --git a/src/cocoa/HID_Utilities.c b/src/cocoa/HID_Utilities.c new file mode 100755 index 000000000..2beb6ca02 --- /dev/null +++ b/src/cocoa/HID_Utilities.c @@ -0,0 +1,1061 @@ +// File: HID_Utilities.c +// Abstract: Implementation of the HID 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) 2009 Apple Inc. All Rights Reserved. +// +//*************************************************** +#pragma mark - includes & imports +//----------------------------------------------------- + +#include + +#include "HID_Utilities_External.h" + +//*************************************************** +#pragma mark - typedefs, enums, defines, etc. +//----------------------------------------------------- +#define FAKE_MISSING_NAMES 1 // set this to true while debuging to get more explicit element names; false for +// the +// generic ones + +#define kPercentMove 10 // precent of overall range a element must move to register +#define kNameKeyCFStringRef CFSTR("Name") // dictionary key + +//*************************************************** +#pragma mark - local ( static ) function prototypes +//----------------------------------------------------- + +static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context); +static CFComparisonResult CFDeviceArrayComparatorFunction(const void *val1, const void *val2, void *context); +static CFMutableDictionaryRef hu_SetUpMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage); + +//*************************************************** +#pragma mark - exported globals +//----------------------------------------------------- + +IOHIDManagerRef gIOHIDManagerRef = NULL; +CFMutableArrayRef gDeviceCFArrayRef = NULL; +CFIndex gDeviceIndex; +CFArrayRef gElementCFArrayRef = NULL; + +//*************************************************** +#pragma mark - local ( static ) globals +//----------------------------------------------------- + +//*************************************************** +#pragma mark - exported function implementations +//----------------------------------------------------- + +//************************************************************************* +// +// HIDBuildMultiDeviceList( inUsagePages, inUsages, inNumDeviceTypes ) +// +// Purpose: builds list of devices with elements +// +// Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages +// inUsages - inNumDeviceTypes sized array of matching usages +// inNumDeviceTypes - number of usage pages & usages +// +// Returns: Boolean - if successful +// +Boolean HIDBuildMultiDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes) { + Boolean result = FALSE; // assume failure ( pessimist! ) + Boolean first = (!gIOHIDManagerRef); // not yet created? + if ( first ) { + // create the manager + gIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + } + if ( gIOHIDManagerRef ) { + CFMutableArrayRef hidMatchingCFMutableArrayRef = NULL; + if ( inUsages && inUsagePages && inNumDeviceTypes ) { + hidMatchingCFMutableArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + if ( hidMatchingCFMutableArrayRef ) { + int idx; + for ( idx = 0; idx < inNumDeviceTypes; idx++ ) { // for all usage and usage page types + // Set up matching dictionary. returns NULL on error. + CFMutableDictionaryRef hidMatchingCFDictRef = hu_SetUpMatchingDictionary(inUsagePages[idx], inUsages[idx]); + if ( hidMatchingCFDictRef ) { + CFArrayAppendValue(hidMatchingCFMutableArrayRef, (void *) hidMatchingCFDictRef); + CFRelease(hidMatchingCFDictRef); + } else { + fprintf(stderr, "%s: Couldnā€™t create a matching dictionary.", __PRETTY_FUNCTION__); + } + } + } else { + fprintf(stderr, "%s: Couldnā€™t create a matching array.", __PRETTY_FUNCTION__); + } + } + + // set it for IOHIDManager to use to match against + IOHIDManagerSetDeviceMatchingMultiple(gIOHIDManagerRef, hidMatchingCFMutableArrayRef); + if ( hidMatchingCFMutableArrayRef ) { + CFRelease(hidMatchingCFMutableArrayRef); + } + if ( first ) { + // open it + IOReturn tIOReturn = IOHIDManagerOpen(gIOHIDManagerRef, kIOHIDOptionsTypeNone); + if ( kIOReturnSuccess != tIOReturn ) { + fprintf(stderr, "%s: Couldnā€™t open IOHIDManager.", __PRETTY_FUNCTION__); + goto Oops; + } + } + + HIDRebuildDevices(); + result = TRUE; + } else { + fprintf(stderr, "%s: Couldnā€™t create a IOHIDManager.", __PRETTY_FUNCTION__); + } + +Oops: ; + return (result); +} // HIDBuildMultiDeviceList + +/************************************************************************* + * + * HIDBuildDeviceList( inUsagePage, inUsage ) + * + * Purpose: builds list of devices with elements + * + * Notes: same as above but this uses a single inUsagePage and usage + * allocates memory and captures devices + * list is allocated internally within HID Utilites and can be accessed via accessor functions + * structures within list are considered flat and user accessable, but not user modifiable + * can be called again to rebuild list to account for new devices + * ( will do the right thing in case of disposing existing list ) + * + * Inputs: inUsagePage - usage page + * inUsage - usages + * + * Returns: Boolean - if successful + */ + +Boolean HIDBuildDeviceList(UInt32 inUsagePage, UInt32 inUsage) { + return ( HIDBuildMultiDeviceList(&inUsagePage, &inUsage, 1) ); // call HIDBuildMultiDeviceList with a single usage +} + +/************************************************************************* + * + * HIDUpdateDeviceList( inUsagePages, inUsages, inNumDeviceTypes ) + * + * Purpose: updates the current device list for any new/removed devices + * + * Notes: if this is called before HIDBuildDeviceList then it functions like HIDBuildMultiDeviceList + * inUsagePage & inUsage are each a inNumDeviceTypes sized array of matching usage and usage pages + * + * Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages + * inUsages - inNumDeviceTypes sized array of matching usages + * inNumDeviceTypes - number of usage pages & usages + * + * Returns: Boolean - TRUE if the device config changed + */ + +Boolean HIDUpdateDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes) { + return ( HIDBuildMultiDeviceList(inUsagePages, inUsages, inNumDeviceTypes) ); +} + +/************************************************************************* + * + * HIDReleaseDeviceList( void ) + * + * Purpose: release list built by above functions + * + * Notes: MUST be called prior to application exit to properly release devices + * if not called( or app crashes ) devices can be recovered by pluging into different location in USB chain + * + * Inputs: none + * + * Returns: none + */ + +void HIDReleaseDeviceList(void) { + if ( gDeviceCFArrayRef ) { + CFRelease(gDeviceCFArrayRef); + gDeviceCFArrayRef = NULL; + } +} // HIDReleaseDeviceList + +/************************************************************************* + * + * HIDHaveDeviceList( void ) + * + * Purpose: does a device list exist? + * + * Inputs: none + * + * Returns: Boolean - TRUE if we have previously built a device list + */ + +Boolean HIDHaveDeviceList(void) { + return (NULL != gDeviceCFArrayRef); +} + +//************************************************************************* +// +// HIDRebuildDevices( ) +// +// Purpose: rebuilds the (internal) list of IOHIDDevices +// +// Inputs: none +// +// Returns: none +// + +void HIDRebuildDevices(void) { + // get the set of devices from the IOHID manager + CFSetRef devCFSetRef = IOHIDManagerCopyDevices(gIOHIDManagerRef); + if ( devCFSetRef ) { + // if the existing array isn't empty... + if ( gDeviceCFArrayRef ) { + // release it + CFRelease(gDeviceCFArrayRef); + } + + // create an empty array + gDeviceCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + // now copy the set to the array + CFSetApplyFunction(devCFSetRef, CFSetApplierFunctionCopyToCFArray, (void *) gDeviceCFArrayRef); + // now sort the array by location ID's + CFIndex cnt = CFArrayGetCount(gDeviceCFArrayRef); + CFArraySortValues(gDeviceCFArrayRef, CFRangeMake(0, cnt), CFDeviceArrayComparatorFunction, NULL); + + // and release the set we copied from the IOHID manager + CFRelease(devCFSetRef); + } +} // HIDRebuildDevices + +// --------------------------------- + +// how many HID devices have been found +// returns 0 if no device list exist + +UInt32 HIDCountDevices(void) { + return ( CFArrayGetCount(gDeviceCFArrayRef) ); +} + +// --------------------------------- + +// how many elements does a specific device have +// returns 0 if device is invlaid or NULL + +UInt32 HIDCountDeviceElements(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask) { + int count = 0; + if ( inIOHIDDeviceRef ) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + + gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + if ( gElementCFArrayRef ) { + CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; + } + + IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef); + + switch ( type ) { + case kIOHIDElementTypeInput_Misc: + case kIOHIDElementTypeInput_Button: + case kIOHIDElementTypeInput_Axis: + case kIOHIDElementTypeInput_ScanCodes: + { + if ( typeMask & kHIDElementTypeInput ) { + count++; + } + + break; + } + + case kIOHIDElementTypeOutput: + { + if ( typeMask & kHIDElementTypeOutput ) { + count++; + } + + break; + } + + case kIOHIDElementTypeFeature: + { + if ( typeMask & kHIDElementTypeFeature ) { + count++; + } + + break; + } + + case kIOHIDElementTypeCollection: + { + if ( typeMask & kHIDElementTypeCollection ) { + count++; + } + + break; + } + default: { + break; + } + } // switch ( type ) + + } // next idx + + CFRelease(gElementCFArrayRef); + gElementCFArrayRef = NULL; + } // if ( gElementCFArrayRef ) + + } // if ( inIOHIDDeviceRef ) + + return (count); +} /* HIDCountDeviceElements */ + +// --------------------------------- + +// get the first device in the device list +// returns NULL if no list exists or it's empty + +IOHIDDeviceRef HIDGetFirstDevice(void) { + IOHIDDeviceRef result = NULL; + + gDeviceIndex = 0; + if ( gDeviceCFArrayRef ) { + CFIndex count = CFArrayGetCount(gDeviceCFArrayRef); + if ( (gDeviceIndex >= 0) && (gDeviceIndex < count) ) { + result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, gDeviceIndex); + } + } + + return (result); +} /* HIDGetFirstDevice */ + +// --------------------------------- + +// get next device in list given current device as parameter +// returns NULL if end of list + +IOHIDDeviceRef HIDGetNextDevice(IOHIDDeviceRef inIOHIDDeviceRef) { + IOHIDDeviceRef result = NULL; + if ( gDeviceCFArrayRef && inIOHIDDeviceRef ) { + CFIndex idx, cnt = CFArrayGetCount(gDeviceCFArrayRef); + // quick case to verify the current device index is valid for current device + if ( (gDeviceIndex >= 0) && (gDeviceIndex < cnt) ) { + result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, gDeviceIndex); + if ( result && (result == inIOHIDDeviceRef) ) { + result = NULL; + gDeviceIndex++; // bump index + } else { + // previous index was invalid; + gDeviceIndex = -1; + // search for current device's index + for ( idx = 0; idx < cnt; idx++ ) { + result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, idx); + if ( (result) && (result == inIOHIDDeviceRef) ) { + gDeviceIndex = idx + 1; // found valid index; bump to next one + break; + } + } + + result = NULL; + } + if ( (gDeviceIndex >= 0) && (gDeviceIndex < cnt) ) { + result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, gDeviceIndex); + } + } // if valid index + + } // if ( gDeviceCFArrayRef && inIOHIDDeviceRef ) + + return (result); +} /* HIDGetNextDevice */ + +// --------------------------------- + +// get the first element of device passed in as parameter +// returns NULL if no list exists or device does not exists or is NULL +IOHIDElementRef HIDGetFirstDeviceElement(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask) { + IOHIDElementRef result = NULL; + if ( inIOHIDDeviceRef ) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + + gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + if ( gElementCFArrayRef ) { + CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; + } + + IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef); + + switch ( type ) { + case kIOHIDElementTypeInput_Misc: + case kIOHIDElementTypeInput_Button: + case kIOHIDElementTypeInput_Axis: + case kIOHIDElementTypeInput_ScanCodes: + { + if ( typeMask & kHIDElementTypeInput ) { + result = tIOHIDElementRef; + } + + break; + } + + case kIOHIDElementTypeOutput: + { + if ( typeMask & kHIDElementTypeOutput ) { + result = tIOHIDElementRef; + } + + break; + } + + case kIOHIDElementTypeFeature: + { + if ( typeMask & kHIDElementTypeFeature ) { + result = tIOHIDElementRef; + } + + break; + } + + case kIOHIDElementTypeCollection: + { + if ( typeMask & kHIDElementTypeCollection ) { + result = tIOHIDElementRef; + } + + break; + } + default: { + break; + } + } // switch ( type ) + if ( result ) { + break; // DONE! + } + } // next idx + + CFRelease(gElementCFArrayRef); + gElementCFArrayRef = NULL; + } // if ( gElementCFArrayRef ) + + } // if ( inIOHIDDeviceRef ) + + return (result); +} /* HIDGetFirstDeviceElement */ + +// --------------------------------- + +// get next element of given device in list given current element as parameter +// will walk down each collection then to next element or collection (depthwise traverse) +// returns NULL if end of list +// uses mask of HIDElementTypeMask to restrict element found +// use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality +IOHIDElementRef HIDGetNextDeviceElement(IOHIDElementRef inIOHIDElementRef, HIDElementTypeMask typeMask) { + IOHIDElementRef result = NULL; + if ( inIOHIDElementRef ) { + assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) ); + + IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef); + if ( tIOHIDDeviceRef ) { + Boolean found = FALSE; + + gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); + if ( gElementCFArrayRef ) { + CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); + for ( idx = 0; idx < cnt; idx++ ) { + IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, idx); + if ( !tIOHIDElementRef ) { + continue; + } + if ( !found ) { + if ( inIOHIDElementRef == tIOHIDElementRef ) { + found = TRUE; + } + + continue; // next element + } else { + // we've found the current element; now find the next one of the right type + IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef); + + switch ( type ) { + case kIOHIDElementTypeInput_Misc: + case kIOHIDElementTypeInput_Button: + case kIOHIDElementTypeInput_Axis: + case kIOHIDElementTypeInput_ScanCodes: + { + if ( typeMask & kHIDElementTypeInput ) { + result = tIOHIDElementRef; + } + + break; + } + + case kIOHIDElementTypeOutput: + { + if ( typeMask & kHIDElementTypeOutput ) { + result = tIOHIDElementRef; + } + + break; + } + + case kIOHIDElementTypeFeature: + { + if ( typeMask & kHIDElementTypeFeature ) { + result = tIOHIDElementRef; + } + + break; + } + + case kIOHIDElementTypeCollection: + { + if ( typeMask & kHIDElementTypeCollection ) { + result = tIOHIDElementRef; + } + + break; + } + default: { + break; + } + } // switch ( type ) + if ( result ) { + break; // DONE! + } + } // if ( !found ) + + } // next idx + + CFRelease(gElementCFArrayRef); + gElementCFArrayRef = NULL; + } // if ( gElementCFArrayRef ) + + } // if ( inIOHIDDeviceRef ) + + } // if ( inIOHIDElementRef ) + + return (result); +} /* HIDGetNextDeviceElement */ + +#if 0 +// --------------------------------- +// get previous element of given device in list given current element as parameter +// this wlaks directly up the tree to the top element and does not search at each level +// returns NULL if beginning of list +// uses mask of HIDElementTypeMask to restrict element found +// use kHIDElementTypeIO to get non-collection elements +IOHIDElementRef HIDGetPreviousDeviceElement(IOHIDElementRef pElement, HIDElementTypeMask typeMask) { + IOHIDElementRef pPreviousElement = pElement->pPrevious; + + // walk back up tree to element prior + while ( pPreviousElement && !HIDMatchElementTypeMask(pPreviousElement->type, typeMask) ) { + pElement = pPreviousElement; // look at previous element + pPreviousElement = pElement->pPrevious; + } + + return (pPreviousElement); // return this element +} /* HIDGetPreviousDeviceElement */ + +#endif + +// utility routine to dump device info +void HIDDumpDeviceInfo(IOHIDDeviceRef inIOHIDDeviceRef) { + char cstring[256]; + + printf("Device: %p = { ", inIOHIDDeviceRef); + + char manufacturer[256] = ""; // name of manufacturer + CFStringRef tCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef); + if ( tCFStringRef ) { + verify( CFStringGetCString(tCFStringRef, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8) ); + } + + char product[256] = ""; // name of product + tCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef); + if ( tCFStringRef ) { + verify( CFStringGetCString(tCFStringRef, product, sizeof(product), kCFStringEncodingUTF8) ); + } + + printf("%s - %s, ", manufacturer, product); + + long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); + if ( vendorID ) { +#if 1 + printf(" vendorID: 0x%04lX, ", vendorID); +#else + if ( HIDGetVendorNameFromVendorID(vendorID, cstring) ) { + printf(" vendorID: 0x%04lX (\"%s\"), ", vendorID, cstring); + } else { + printf(" vendorID: 0x%04lX, ", vendorID); + } + +#endif + } + + long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); + if ( productID ) { +#if 1 + printf(" productID: 0x%04lX, ", productID); +#else + if ( HIDGetProductNameFromVendorProductID(vendorID, productID, cstring) ) { + printf(" productID: 0x%04lX (\"%s\"), ", productID, cstring); + } else { + printf(" productID: 0x%04lX, ", productID); + } + +#endif + } + + uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); + uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); + if ( !usagePage || !usage ) { + usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); + usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef); + } + + printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); + +#if 1 + tCFStringRef = HIDCopyUsageName(usagePage, usage); + if ( tCFStringRef ) { + verify( CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8) ); + printf("\"%s\", ", cstring); + CFRelease(tCFStringRef); + } + +#endif + +#if 1 + tCFStringRef = IOHIDDevice_GetTransport(inIOHIDDeviceRef); + if ( tCFStringRef ) { + verify( CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8) ); + printf("Transport: \"%s\", ", cstring); + } + + long vendorIDSource = IOHIDDevice_GetVendorIDSource(inIOHIDDeviceRef); + if ( vendorIDSource ) { + printf("VendorIDSource: %ld, ", vendorIDSource); + } + + long version = IOHIDDevice_GetVersionNumber(inIOHIDDeviceRef); + if ( version ) { + printf("version: %ld, ", version); + } + + tCFStringRef = IOHIDDevice_GetSerialNumber(inIOHIDDeviceRef); + if ( tCFStringRef ) { + verify( CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8) ); + printf("SerialNumber: \"%s\", ", cstring); + } + + long country = IOHIDDevice_GetCountryCode(inIOHIDDeviceRef); + if ( country ) { + printf("CountryCode: %ld, ", country); + } + + long locationID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); + if ( locationID ) { + printf("locationID: 0x%08lX, ", locationID); + } + +#if 0 + CFArrayRef pairs = IOHIDDevice_GetUsagePairs(inIOHIDDeviceRef); + if ( pairs ) { + CFIndex idx, cnt = CFArrayGetCount(pairs); + for ( idx = 0; idx < cnt; idx++ ) { + const void *pair = CFArrayGetValueAtIndex(pairs, idx); + CFShow(pair); + } + } + +#endif + long maxInputReportSize = IOHIDDevice_GetMaxInputReportSize(inIOHIDDeviceRef); + if ( maxInputReportSize ) { + printf("MaxInputReportSize: %ld, ", maxInputReportSize); + } + + long maxOutputReportSize = IOHIDDevice_GetMaxOutputReportSize(inIOHIDDeviceRef); + if ( maxOutputReportSize ) { + printf("MaxOutputReportSize: %ld, ", maxOutputReportSize); + } + + long maxFeatureReportSize = IOHIDDevice_GetMaxFeatureReportSize(inIOHIDDeviceRef); + if ( maxFeatureReportSize ) { + printf("MaxFeatureReportSize: %ld, ", maxOutputReportSize); + } + + long reportInterval = IOHIDDevice_GetReportInterval(inIOHIDDeviceRef); + if ( reportInterval ) { + printf("ReportInterval: %ld, ", reportInterval); + } + + IOHIDQueueRef queueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); + if ( queueRef ) { + printf("queue: %p, ", queueRef); + } + + IOHIDTransactionRef transactionRef = IOHIDDevice_GetTransaction(inIOHIDDeviceRef); + if ( transactionRef ) { + printf("transaction: %p, ", transactionRef); + } + +#endif + printf("}\n"); + fflush(stdout); +} // HIDDumpDeviceInfo + +// utility routine to dump element info +void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef) { + if ( inIOHIDElementRef ) { + printf(" Element: %p = { ", inIOHIDElementRef); +#if 0 + IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef); + printf("Device: %p, ", tIOHIDDeviceRef); +#endif + IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent(inIOHIDElementRef); + printf("parent: %p, ", parentIOHIDElementRef); +#if 0 + CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren(inIOHIDElementRef); + printf("children: %p: { ", childrenCFArrayRef); + fflush(stdout); + CFShow(childrenCFArrayRef); + fflush(stdout); + printf(" }, "); +#endif + IOHIDElementCookie tIOHIDElementCookie = IOHIDElementGetCookie(inIOHIDElementRef); + printf("cookie: %p, ", tIOHIDElementCookie); + + IOHIDElementType tIOHIDElementType = IOHIDElementGetType(inIOHIDElementRef); + + switch ( tIOHIDElementType ) { + case kIOHIDElementTypeInput_Misc: + { + printf("type: Misc, "); + break; + } + + case kIOHIDElementTypeInput_Button: + { + printf("type: Button, "); + break; + } + + case kIOHIDElementTypeInput_Axis: + { + printf("type: Axis, "); + break; + } + + case kIOHIDElementTypeInput_ScanCodes: + { + printf("type: ScanCodes, "); + break; + } + + case kIOHIDElementTypeOutput: + { + printf("type: Output, "); + break; + } + + case kIOHIDElementTypeFeature: + { + printf("type: Feature, "); + break; + } + + case kIOHIDElementTypeCollection: + { + IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType(inIOHIDElementRef); + + switch ( tIOHIDElementCollectionType ) { + case kIOHIDElementCollectionTypePhysical: + { + printf("type: Physical Collection, "); + break; + } + + case kIOHIDElementCollectionTypeApplication: + { + printf("type: Application Collection, "); + break; + } + + case kIOHIDElementCollectionTypeLogical: + { + printf("type: Logical Collection, "); + break; + } + + case kIOHIDElementCollectionTypeReport: + { + printf("type: Report Collection, "); + break; + } + + case kIOHIDElementCollectionTypeNamedArray: + { + printf("type: Named Array Collection, "); + break; + } + + case kIOHIDElementCollectionTypeUsageSwitch: + { + printf("type: Usage Switch Collection, "); + break; + } + + case kIOHIDElementCollectionTypeUsageModifier: + { + printf("type: Usage Modifier Collection, "); + break; + } + + default: + { + printf("type: %p Collection, ", (void *) tIOHIDElementCollectionType); + break; + } + } // switch + + break; + } + + default: + { + printf("type: %p, ", (void *) tIOHIDElementType); + break; + } + } /* switch */ + + uint32_t usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); + uint32_t usage = IOHIDElementGetUsage(inIOHIDElementRef); + printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); +#if 1 + CFStringRef tCFStringRef = HIDCopyUsageName(usagePage, usage); + if ( tCFStringRef ) { + char usageString[256] = ""; + verify( CFStringGetCString(tCFStringRef, usageString, sizeof(usageString), kCFStringEncodingUTF8) ); + printf("\"%s\", ", usageString); + CFRelease(tCFStringRef); + } + +#endif + CFStringRef nameCFStringRef = IOHIDElementGetName(inIOHIDElementRef); + char buffer[256]; + if ( nameCFStringRef && CFStringGetCString(nameCFStringRef, buffer, sizeof(buffer), kCFStringEncodingUTF8) ) { + printf("name: %s, ", buffer); + } + + uint32_t reportID = IOHIDElementGetReportID(inIOHIDElementRef); + uint32_t reportSize = IOHIDElementGetReportSize(inIOHIDElementRef); + uint32_t reportCount = IOHIDElementGetReportCount(inIOHIDElementRef); + printf("report: { ID: %lu, Size: %lu, Count: %lu }, ", + (long unsigned int) reportID, (long unsigned int) reportSize, (long unsigned int) reportCount); + + uint32_t unit = IOHIDElementGetUnit(inIOHIDElementRef); + uint32_t unitExp = IOHIDElementGetUnitExponent(inIOHIDElementRef); + if ( unit || unitExp ) { + printf("unit: %lu * 10^%lu, ", (long unsigned int) unit, (long unsigned int) unitExp); + } + + CFIndex logicalMin = IOHIDElementGetLogicalMin(inIOHIDElementRef); + CFIndex logicalMax = IOHIDElementGetLogicalMax(inIOHIDElementRef); + if ( logicalMin != logicalMax ) { + printf("logical: {min: %ld, max: %ld}, ", logicalMin, logicalMax); + } + + CFIndex physicalMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef); + CFIndex physicalMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef); + if ( physicalMin != physicalMax ) { + printf("physical: {min: %ld, max: %ld}, ", physicalMin, physicalMax); + } + + Boolean isVirtual = IOHIDElementIsVirtual(inIOHIDElementRef); + if ( isVirtual ) { + printf("isVirtual, "); + } + + Boolean isRelative = IOHIDElementIsRelative(inIOHIDElementRef); + if ( isRelative ) { + printf("isRelative, "); + } + + Boolean isWrapping = IOHIDElementIsWrapping(inIOHIDElementRef); + if ( isWrapping ) { + printf("isWrapping, "); + } + + Boolean isArray = IOHIDElementIsArray(inIOHIDElementRef); + if ( isArray ) { + printf("isArray, "); + } + + Boolean isNonLinear = IOHIDElementIsNonLinear(inIOHIDElementRef); + if ( isNonLinear ) { + printf("isNonLinear, "); + } + + Boolean hasPreferredState = IOHIDElementHasPreferredState(inIOHIDElementRef); + if ( hasPreferredState ) { + printf("hasPreferredState, "); + } + + Boolean hasNullState = IOHIDElementHasNullState(inIOHIDElementRef); + if ( hasNullState ) { + printf("hasNullState, "); + } + + printf(" }\n"); + } +} // HIDDumpElementInfo + +void HIDDumpElementCalibrationInfo(IOHIDElementRef inIOHIDElementRef) { + printf(" Element: %p = { ", inIOHIDElementRef); + + CFIndex calMin = IOHIDElement_GetCalibrationMin(inIOHIDElementRef); + CFIndex calMax = IOHIDElement_GetCalibrationMax(inIOHIDElementRef); + printf("cal: {min: %ld, max: %ld}, ", calMin, calMax); + + CFIndex satMin = IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef); + CFIndex satMax = IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef); + printf("sat: {min: %ld, max: %ld}, ", satMin, satMax); + + CFIndex deadMin = IOHIDElement_GetCalibrationDeadZoneMin(inIOHIDElementRef); + CFIndex deadMax = IOHIDElement_GetCalibrationDeadZoneMax(inIOHIDElementRef); + printf("dead: {min: %ld, max: %ld}, ", deadMin, deadMax); + + double_t granularity = IOHIDElement_GetCalibrationGranularity(inIOHIDElementRef); + printf("granularity: %6.2f }\n", granularity); +} // HIDDumpElementCalibrationInfo + +//*************************************************** +#pragma mark - local ( static ) function implementations +//----------------------------------------------------- + +//************************************************************************* +// +// CFSetApplierFunctionCopyToCFArray( value, context ) +// +// Purpose: CFSetApplierFunction to copy the CFSet to a CFArray +// +// Notes: called one time for each item in the CFSet +// +// Inputs: value - the current element of the CFSet +// context - the CFMutableArrayRef we're adding the CFSet elements to +// +// Returns: nothing +// +static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context) { + // printf( "%s: 0x%08lX\n", __PRETTY_FUNCTION__, (long unsigned int) value ); + CFArrayAppendValue( (CFMutableArrayRef) context, value ); +} // CFSetApplierFunctionCopyToCFArray + +// --------------------------------- +// used to sort the CFDevice array after copying it from the (unordered) (CF)set. +// we compare based on the location ID's since they're consistant (across boots & launches). +// +static CFComparisonResult CFDeviceArrayComparatorFunction(const void *val1, const void *val2, void *context) { +#pragma unused( context ) + CFComparisonResult result = kCFCompareEqualTo; + + long loc1 = IOHIDDevice_GetLocationID( (IOHIDDeviceRef) val1 ); + long loc2 = IOHIDDevice_GetLocationID( (IOHIDDeviceRef) val2 ); + if ( loc1 < loc2 ) { + result = kCFCompareLessThan; + } else if ( loc1 > loc2 ) { + result = kCFCompareGreaterThan; + } + + return (result); +} // CFDeviceArrayComparatorFunction + +//************************************************************************* +// +// hu_SetUpMatchingDictionary( inUsagePage, inUsage ) +// +// Purpose: builds a matching dictionary based on usage page and usage +// +// Notes: Only called by HIDBuildMultiDeviceList +// +// Inputs: inUsagePage - usage page +// inUsage - usages +// +// Returns: CFMutableDictionaryRef - the matching dictionary +// + +static CFMutableDictionaryRef hu_SetUpMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage) { + // create a dictionary to add usage page/usages to + CFMutableDictionaryRef refHIDMatchDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if ( refHIDMatchDictionary ) { + if ( inUsagePage ) { + // Add key for device type to refine the matching dictionary. + CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage); + if ( pageCFNumberRef ) { + CFDictionarySetValue(refHIDMatchDictionary, + CFSTR(kIOHIDPrimaryUsagePageKey), pageCFNumberRef); + CFRelease(pageCFNumberRef); + // note: the usage is only valid if the usage page is also defined + if ( inUsage ) { + CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage); + if ( usageCFNumberRef ) { + CFDictionarySetValue(refHIDMatchDictionary, + CFSTR(kIOHIDPrimaryUsageKey), usageCFNumberRef); + CFRelease(usageCFNumberRef); + } else { + fprintf(stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__); + } + } + } else { + fprintf(stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__); + } + } + } else { + fprintf(stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__); + } + + return (refHIDMatchDictionary); +} // hu_SetUpMatchingDictionary diff --git a/src/cocoa/HID_Utilities_External.h b/src/cocoa/HID_Utilities_External.h new file mode 100755 index 000000000..bd498bc51 --- /dev/null +++ b/src/cocoa/HID_Utilities_External.h @@ -0,0 +1,417 @@ +// File: HID_Utilities_External.h +// Abstract: External interface for HID Utilities, can be used with either library or source. +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#ifndef _HID_Utilities_External_h_ +#define _HID_Utilities_External_h_ + +// ================================== + +#ifdef __cplusplus +extern "C" { +#endif + +// ================================== + +//includes + +#include +#include "IOHIDLib_.h" + +// ================================== + +#ifndef _IOKIT_HID_IOHIDKEYS_H_ +/*! + @typedef IOHIDElementCookie + @abstract Abstract data type used as a unique identifier for an element. + */ +#ifdef __LP64__ +typedef uint32_t IOHIDElementCookie; +#else +typedef void *IOHIDElementCookie; +#endif +#endif + +// Device and Element Interfaces + +enum HIDElementTypeMask { + kHIDElementTypeInput = 1 << 1, + kHIDElementTypeOutput = 1 << 2, + kHIDElementTypeFeature = 1 << 3, + kHIDElementTypeCollection = 1 << 4, + kHIDElementTypeIO = kHIDElementTypeInput | kHIDElementTypeOutput | kHIDElementTypeFeature, + kHIDElementTypeAll = kHIDElementTypeIO | kHIDElementTypeCollection +}; +typedef enum HIDElementTypeMask HIDElementTypeMask; + +// ================================== + +//***************************************************** +#pragma mark - exported globals +//----------------------------------------------------- + +extern IOHIDManagerRef gIOHIDManagerRef; +extern CFMutableArrayRef gDeviceCFArrayRef; +extern CFArrayRef gElementCFArrayRef; + +//************************************************************************* +// +// HIDBuildMultiDeviceList( inUsagePages, inUsages, inNumDeviceTypes ) +// +// Purpose: builds list of devices with elements (allocates memory and captures devices) in which +// the devices could be of different types/usages list is allocated internally within HID +// Utilites and can be accessed via accessor functions structures within list are considered +// flat and user accessable, but not user modifiable can be called again to rebuild list to +// account for new devices (will do the right thing in case of disposing existing list) +// usagePage, usage are each a numDeviceTypes sized array of matching usage and usage pages +// returns true if succesful +// +// Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages +// inUsages - inNumDeviceTypes sized array of matching usages +// inNumDeviceTypes - number of usage pages & usages +// +// Returns: Boolean - if successful +// +extern Boolean HIDBuildMultiDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes); + +// same as above but this uses a single usagePage and usage +extern Boolean HIDBuildDeviceList(UInt32 usagePage, UInt32 usage); + +// updates the current device list for any new/removed devices +// if this is called before HIDBuildDeviceList the it functions like HIDBuildMultiDeviceList +// usagePage, usage are each a numDeviceTypes sized array of matching usage and usage pages +// returns true if successful which means if any device were added or removed (the device config changed) +extern Boolean HIDUpdateDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes); + +// release list built by above function +// MUST be called prior to application exit to properly release devices +// if not called (or app crashes) devices can be recovered by pluging into different location in USB chain +extern void HIDReleaseDeviceList(void); + +//************************************************************************* +// +// HIDRebuildDevices( ) +// +// Purpose: rebuilds the (internal) list of devices +// +// Inputs: none +// +// Returns: none +// + +extern void HIDRebuildDevices(void); + +// does a device list exist +extern unsigned char HIDHaveDeviceList(void); + +// how many HID devices have been found +// returns 0 if no device list exist +extern UInt32 HIDCountDevices(void); + +// how many elements does a specific device have +// returns 0 if device is invalid or NULL +// uses mask of HIDElementTypeMask to restrict element found +// use kHIDElementTypeIO to get non-collection elements +extern UInt32 HIDCountDeviceElements(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask); + +// get the first device in the device list +// returns NULL if no list exists +extern IOHIDDeviceRef HIDGetFirstDevice(void); + +// get next device in list given current device as parameter +// returns NULL if end of list +extern IOHIDDeviceRef HIDGetNextDevice(IOHIDDeviceRef inIOHIDDeviceRef); + +// get the first element of device passed in as parameter +// returns NULL if no list exists or device does not exists or is NULL +// uses mask of HIDElementTypeMask to restrict element found +// use kHIDElementTypeIO to get previous HIDGetFirstDeviceElement functionality +extern IOHIDElementRef HIDGetFirstDeviceElement(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask); + +// get next element of given device in list given current element as parameter +// will walk down each collection then to next element or collection (depthwise traverse) +// returns NULL if end of list +// uses mask of HIDElementTypeMask to restrict element found +// use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality +extern IOHIDElementRef HIDGetNextDeviceElement(IOHIDElementRef inIOHidElementRef, HIDElementTypeMask typeMask); + +// get previous element of given device in list given current element as parameter +// this walks directly up the tree to the top element and does not search at each level +// returns NULL if beginning of list +// uses mask of HIDElementTypeMask to restrict element found +// use kHIDElementTypeIO to get non-collection elements +extern IOHIDElementRef HIDGetPreviousDeviceElement(IOHIDElementRef inIOHidElementRef, HIDElementTypeMask typeMask); + +// returns C string type name given a type enumeration passed in as parameter( see IOHIDKeys.h ) +// returns empty string for invalid types +extern void HIDGetTypeName(IOHIDElementType inIOHIDElementType, char *outCStrName); + +//************************************************************************* +// +// 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 +// + +extern CFStringRef HIDCopyUsageName(long inUsagePage, long inUsage); + +// ================================== + +// Element Event Queue and Value Interfaces + +enum { + kDefaultUserMin = 0, // default user min and max used for scaling + kDefaultUserMax = 255 +}; + +enum { + kDeviceQueueSize = 50 // this is wired kernel memory so should be set to as small as possible + // but should account for the maximum possible events in the queue + // USB updates will likely occur at 100 Hz so one must account for this rate of + // if states change quickly (updates are only posted on state changes) +}; + +// ================================== + +// queues specific element, performing any device queue set up required +extern int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef); + +// adds all elements to queue, performing any device queue set up required +extern int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef); + +// removes element for queue, if last element in queue will release queue and device +extern int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef); + +// completely removes all elements from queue and releases queue and device +extern int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef); + +// releases all device queues for quit or rebuild (must be called) +extern int HIDReleaseAllDeviceQueues(void); + +// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise +// pHIDEvent is a poiner to a IOHIDEventStruct, using void here for compatibility, users can cast a required +extern unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef); + +// ================================== + +// Conguration and Save Interfaces + +enum { + kPercentMove = 10 // precent of overall range a element must move to register +}; + +typedef struct HID_info_struct { + int actionCookie; + // device + // need to add serial number when I have a test case + struct { + int vendorID, productID; + int locID; + uint32_t usagePage, usage; + } device; + // elements + struct { + uint32_t usagePage, usage; + int minReport, maxReport; + IOHIDElementCookie cookie; // always 32 bits + } element; +}HID_info_rec, *HID_info_ptr; + +// get vendor name from vendor ID +extern Boolean HIDGetVendorNameFromVendorID(long inVendorID, char *outCStrName); + +// get product name from vendor/product ID +extern Boolean HIDGetProductNameFromVendorProductID(long inVendorID, long inProductID, char *outCStrName); + +// get element name from vendor id/product id look up ( using element cookie ) +extern Boolean HIDGetElementNameFromVendorProductCookie(int inVendorID, + int inProductID, + IOHIDElementCookie inCookie, + char * outCStrName); + +// get element name from vendor id/product id look up ( using element usage page & usage ) +extern Boolean HIDGetElementNameFromVendorProductUsage(long inVendorID, + long inProductID, + long inUsagePage, + long inUsage, + char *inCStrName); + +// utility routines to dump device or element info +extern void HIDDumpDeviceInfo(IOHIDDeviceRef inIOHIDDeviceRef); +extern void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef); +extern void HIDDumpElementCalibrationInfo(IOHIDElementRef inIOHIDElementRef); + +// polls single device's elements for a change greater than kPercentMove. Times out after given time +// returns 1 and pointer to element if found +// returns 0 and NULL for both parameters if not found +extern unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef inIOHIDDeviceRef, + IOHIDElementRef *outIOHIDElementRef, + float timeout); + +//************************************************************************* +// +// HIDConfigureAction( outDeviceRef, outElementRef, inTimeout ) +// +// Purpose: polls all devices and elements for a change greater than kPercentMove. +// Times out after given time returns 1 and pointer to device and element +// if found; returns 0 and NULL for both parameters if not found +// +// Inputs: outDeviceRef - address where to store the device +// outElementRef - address where to store the element +// inTimeout - the timeout +// Returns: Boolean - TRUE if successful +// outDeviceRef - the device +// outElementRef - the element +// + +extern Boolean HIDConfigureAction(IOHIDDeviceRef *outDeviceRef, IOHIDElementRef *outElementRef, float inTimeout); + +//************************************************************************* +// +// HIDSaveElementPref( inKeyCFStringRef, inAppCFStringRef, inDeviceRef, inElementRef ) +// +// Purpose: Save the device & element values into the specified key in the specified applications preferences +// +// Inputs: inKeyCFStringRef - the preference key +// inAppCFStringRef - the application identifier +// inDeviceRef - the device +// inElementRef - the element +// Returns: Boolean - if successful +// + +extern Boolean HIDSaveElementPref(const CFStringRef inKeyCFStringRef, + CFStringRef inAppCFStringRef, + IOHIDDeviceRef inDeviceRef, + IOHIDElementRef inElementRef); + +//************************************************************************* +// +// HIDRestoreElementPref( inKeyCFStringRef, inAppCFStringRef, outDeviceRef, outElementRef ) +// +// Purpose: Find the specified preference in the specified application +// +// Inputs: inKeyCFStringRef - the preference key +// inAppCFStringRef - the application identifier +// outDeviceRef - address where to restore the device +// outElementRef - address where to restore the element +// Returns: Boolean - if successful +// outDeviceRef - the device +// outElementRef - the element +// + +extern Boolean HIDRestoreElementPref(CFStringRef inKeyCFStringRef, + CFStringRef inAppCFStringRef, + IOHIDDeviceRef * outDeviceRef, + IOHIDElementRef *outElementRef); + +//************************************************************************* +// +// HIDFindDeviceAndElement( inSearchInfo, outFoundDevice, outFoundElement ) +// +// Purpose: find the closest matching device and element for this action +// +// Notes: matches device: serial, vendorID, productID, location, inUsagePage, usage +// matches element: cookie, inUsagePage, usage, +// +// Inputs: inSearchInfo - the device & element info we searching for +// outFoundDevice - the address of the best matching device +// outFoundElement - the address of the best matching element +// +// Returns: Boolean - TRUE if we find a match +// outFoundDevice - the best matching device +// outFoundElement - the best matching element +// + +extern Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo, + IOHIDDeviceRef * outFoundDevice, + IOHIDElementRef * outFoundElement); + +// -- These are routines to use if the applcationwants HID Utilities to do the file handling -- +// Note: the FILE * is a MachO posix FILE and will not likely work directly with MW MSL FILE * type. + +// take input records, save required info +// assume file is open and at correct position. +void HIDSaveElementConfig(FILE *fileRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef, int actionCookie); + +// takes a file, reads one record (assume file position is correct and file is open) +// search for matching device +// return tIOHIDDeviceRef, tIOHIDElementRef and cookie for action +int HIDRestoreElementConfig(FILE *fileRef, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef); + +// -- These are routines to use if the client wants to use their own file handling -- + +// Set up a config record for saving +// takes an input records, returns record user can save as they want +// Note: the save rec must be pre-allocated by the calling app and will be filled out +void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr, + IOHIDDeviceRef inIOHIDDeviceRef, + IOHIDElementRef inIOHidElementRef, + int actionCookie); + +// Get matching element from config record +// takes a pre-allocated and filled out config record +// search for matching device +// return tIOHIDDeviceRef, tIOHIDElementRef and cookie for action +int HIDGetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef); + +// ================================== + +// Error reporter, can be set to report however the application desires +extern void HIDReportError(const char *strError); + +// Error with numeric code reporter, can be set to report however the application desires +extern void HIDReportErrorNum(const char *strError, int numError); + +#ifdef __cplusplus +} +#endif + +#endif // _HID_Utilities_External_h_ diff --git a/src/cocoa/IOHIDDevice_.c b/src/cocoa/IOHIDDevice_.c new file mode 100755 index 000000000..c1e2d12cf --- /dev/null +++ b/src/cocoa/IOHIDDevice_.c @@ -0,0 +1,544 @@ +// File: IOHIDDevice_.c +// Abstract: convieance functions for IOHIDDeviceGetProperty +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#pragma mark - includes & imports +//----------------------------------------------------- + +#include "IOHIDDevice_.h" + +//***************************************************** +#pragma mark - typedef's, struct's, enums, defines, etc. +//----------------------------------------------------- + +#define kIOHIDDevice_TransactionKey "DeviceTransactionRef" +#define kIOHIDDevice_QueueKey "DeviceQueueRef" + +//***************************************************** +#pragma mark - local (static) function prototypes +//----------------------------------------------------- + +static Boolean IOHIDDevice_GetLongProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, long *outValue); +static void IOHIDDevice_SetLongProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, long inValue); + +//***************************************************** +#pragma mark - exported globals +//----------------------------------------------------- + +//***************************************************** +#pragma mark - local (static) globals +//----------------------------------------------------- + +//***************************************************** +#pragma mark - exported function implementations +//----------------------------------------------------- + +//************************************************************************* +// +// HIDIsValidDevice( inIOHIDDeviceRef ) +// +// Purpose: validate this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: Boolean - TRUE if we find the device in our( internal ) device list +// + +Boolean HIDIsValidDevice(IOHIDDeviceRef inIOHIDDeviceRef) { + Boolean result = FALSE; // assume failure (pessimist!) + if ( inIOHIDDeviceRef ) { + if ( CFGetTypeID(inIOHIDDeviceRef) ==IOHIDDeviceGetTypeID() ) { + result = TRUE; + } + } + + return (result); +} // HIDIsValidDevice + +//************************************************************************* +// +// IOHIDDevice_GetTransport( inIOHIDDeviceRef ) +// +// Purpose: get the Transport CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the Transport for this device +// + +CFStringRef IOHIDDevice_GetTransport(IOHIDDeviceRef inIOHIDDeviceRef) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDTransportKey) ) ); +} + +//************************************************************************* +// +// IOHIDDevice_GetVendorID( inIOHIDDeviceRef ) +// +// Purpose: get the vendor ID for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the vendor ID for this device +// + +long IOHIDDevice_GetVendorID(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey), &result); + return (result); +} // IOHIDDevice_GetVendorID + +//************************************************************************* +// +// IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef ) +// +// Purpose: get the VendorIDSource for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the VendorIDSource for this device +// + +long IOHIDDevice_GetVendorIDSource(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDSourceKey), &result); + return (result); +} // IOHIDDevice_GetVendorIDSource + +//************************************************************************* +// +// IOHIDDevice_GetProductID( inIOHIDDeviceRef ) +// +// Purpose: get the product ID for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the product ID for this device +// + +long IOHIDDevice_GetProductID(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey), &result); + return (result); +} // IOHIDDevice_GetProductID + +//************************************************************************* +// +// IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef ) +// +// Purpose: get the VersionNumber CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the VersionNumber for this device +// + +long IOHIDDevice_GetVersionNumber(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVersionNumberKey), &result); + return (result); +} // IOHIDDevice_GetVersionNumber + +//************************************************************************* +// +// IOHIDDevice_GetManufacturer( inIOHIDDeviceRef ) +// +// Purpose: get the Manufacturer CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the Manufacturer for this device +// + +CFStringRef IOHIDDevice_GetManufacturer(IOHIDDeviceRef inIOHIDDeviceRef) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDManufacturerKey) ) ); +} // IOHIDDevice_GetManufacturer + +//************************************************************************* +// +// IOHIDDevice_GetProduct( inIOHIDDeviceRef ) +// +// Purpose: get the Product CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the Product for this device +// + +CFStringRef IOHIDDevice_GetProduct(IOHIDDeviceRef inIOHIDDeviceRef) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDProductKey) ) ); +} // IOHIDDevice_GetProduct + +//************************************************************************* +// +// IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef ) +// +// Purpose: get the SerialNumber CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the SerialNumber for this device +// + +CFStringRef IOHIDDevice_GetSerialNumber(IOHIDDeviceRef inIOHIDDeviceRef) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDSerialNumberKey) ) ); +} + +//************************************************************************* +// +// IOHIDDevice_GetCountryCode( inIOHIDDeviceRef ) +// +// Purpose: get the CountryCode CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the CountryCode for this device +// + +long IOHIDDevice_GetCountryCode(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDCountryCodeKey), &result); + return (result); +} // IOHIDDevice_GetCountryCode + +//************************************************************************* +// +// IOHIDDevice_GetLocationID( inIOHIDDeviceRef ) +// +// Purpose: get the location ID for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the location ID for this device +// + +long IOHIDDevice_GetLocationID(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey), &result); + return (result); +} // IOHIDDevice_GetLocationID + +//************************************************************************* +// +// IOHIDDevice_GetUsage( inIOHIDDeviceRef ) +// +// Purpose: get the usage for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: uint32_t - the usage for this device +// + +uint32_t IOHIDDevice_GetUsage(IOHIDDeviceRef inIOHIDDeviceRef) { + uint32_t result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsageKey), (long *) &result); + return (result); +} // IOHIDDevice_GetUsage + +//************************************************************************* +// +// IOHIDDevice_GetUsagePage( inIOHIDDeviceRef ) +// +// Purpose: get the usage page for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: uint32_t - the usage page for this device +// + +uint32_t IOHIDDevice_GetUsagePage(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsagePageKey), &result); + return (result); +} // IOHIDDevice_GetUsagePage + +//************************************************************************* +// +// IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef ) +// +// Purpose: get the UsagePairs CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFArrayRef - the UsagePairs for this device +// + +CFArrayRef IOHIDDevice_GetUsagePairs(IOHIDDeviceRef inIOHIDDeviceRef) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsagePairsKey) ) ); +} + +//************************************************************************* +// +// IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef ) +// +// Purpose: get the PrimaryUsage CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the PrimaryUsage for this device +// + +uint32_t IOHIDDevice_GetPrimaryUsage(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsageKey), &result); + return (result); +} // IOHIDDevice_GetPrimaryUsage + +//************************************************************************* +// +// IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef ) +// +// Purpose: get the PrimaryUsagePage CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: CFStringRef - the PrimaryUsagePage for this device +// + +uint32_t IOHIDDevice_GetPrimaryUsagePage(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey), &result); + return (result); +} // IOHIDDevice_GetPrimaryUsagePage + +//************************************************************************* +// +// IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef ) +// +// Purpose: get the MaxInputReportSize CFString for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the MaxInputReportSize for this device +// + +long IOHIDDevice_GetMaxInputReportSize(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDMaxInputReportSizeKey), &result); + return (result); +} // IOHIDDevice_GetMaxInputReportSize + +//************************************************************************* +// +// IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef ) +// +// Purpose: get the MaxOutputReportSize for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the MaxOutput for this device +// + +long IOHIDDevice_GetMaxOutputReportSize(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDMaxOutputReportSizeKey), &result); + return (result); +} // IOHIDDevice_GetMaxOutputReportSize + +//************************************************************************* +// +// IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef ) +// +// Purpose: get the MaxFeatureReportSize for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the MaxFeatureReportSize for this device +// + +long IOHIDDevice_GetMaxFeatureReportSize(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDMaxFeatureReportSizeKey), &result); + return (result); +} // IOHIDDevice_GetMaxFeatureReportSize + +//************************************************************************* +// +// IOHIDDevice_GetReportInterval( inIOHIDDeviceRef ) +// +// Purpose: get the ReportInterval for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: long - the ReportInterval for this device +// +#ifndef kIOHIDReportIntervalKey +#define kIOHIDReportIntervalKey "ReportInterval" +#endif +long IOHIDDevice_GetReportInterval(IOHIDDeviceRef inIOHIDDeviceRef) { + long result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDReportIntervalKey), &result); + return (result); +} // IOHIDDevice_GetReportInterval + +//************************************************************************* +// +// IOHIDDevice_GetQueue( inIOHIDDeviceRef ) +// +// Purpose: get the Queue for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: IOHIDQueueRef - the Queue for this device +// + +IOHIDQueueRef IOHIDDevice_GetQueue(IOHIDDeviceRef inIOHIDDeviceRef) { + IOHIDQueueRef result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_QueueKey), (long *) &result); + if ( result ) { + assert( IOHIDQueueGetTypeID() == CFGetTypeID(result) ); + } + + return (result); +} // IOHIDDevice_GetQueue + +//************************************************************************* +// +// IOHIDDevice_SetQueue( inIOHIDDeviceRef, inQueueRef ) +// +// Purpose: Set the Queue for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// inQueueRef - the Queue reference +// +// Returns: nothing +// + +void IOHIDDevice_SetQueue(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDQueueRef inQueueRef) { + IOHIDDevice_SetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_QueueKey), (long) inQueueRef); +} + +//************************************************************************* +// +// IOHIDDevice_GetTransaction( inIOHIDDeviceRef ) +// +// Purpose: get the Transaction for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// +// Returns: IOHIDTransactionRef - the Transaction for this device +// + +IOHIDTransactionRef IOHIDDevice_GetTransaction(IOHIDDeviceRef inIOHIDDeviceRef) { + IOHIDTransactionRef result = 0; + (void) IOHIDDevice_GetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_TransactionKey), (long *) &result); + return (result); +} // IOHIDDevice_GetTransaction + +//************************************************************************* +// +// IOHIDDevice_SetTransaction( inIOHIDDeviceRef, inTransactionRef ) +// +// Purpose: Set the Transaction for this device +// +// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device +// inTransactionRef - the Transaction reference +// +// Returns: nothing +// + +void IOHIDDevice_SetTransaction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDTransactionRef inTransactionRef) { + IOHIDDevice_SetLongProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_TransactionKey), (long) inTransactionRef); +} + +//***************************************************** +#pragma mark - local (static) function implementations +//----------------------------------------------------- + +//************************************************************************* +// +// IOHIDDevice_GetLongProperty( inIOHIDDeviceRef, inKey, outValue ) +// +// Purpose: convieance function to return a long property of a device +// +// Inputs: inIOHIDDeviceRef - the device +// inKey - CFString for the +// outValue - address where to restore the element +// Returns: the action cookie +// outValue - the device +// + +static Boolean IOHIDDevice_GetLongProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, long *outValue) { + Boolean result = FALSE; + if ( inIOHIDDeviceRef ) { + assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); + + CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey); + if ( tCFTypeRef ) { + // if this is a number + if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) { + // get it's value + result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue ); + } + } + } + + return (result); +} // IOHIDDevice_GetLongProperty + +//************************************************************************* +// +// IOHIDDevice_SetLongProperty( inIOHIDDeviceRef, inKey, inValue ) +// +// Purpose: convieance function to set a long property of an Device +// +// Inputs: inIOHIDDeviceRef - the Device +// inKey - CFString for the key +// inValue - the value to set it to +// Returns: nothing +// + +static void IOHIDDevice_SetLongProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, long inValue) { + CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue); + if ( tCFNumberRef ) { + IOHIDDeviceSetProperty(inIOHIDDeviceRef, inKey, tCFNumberRef); + CFRelease(tCFNumberRef); + } +} // IOHIDDevice_SetLongProperty + +//***************************************************** diff --git a/src/cocoa/IOHIDDevice_.h b/src/cocoa/IOHIDDevice_.h new file mode 100755 index 000000000..739352844 --- /dev/null +++ b/src/cocoa/IOHIDDevice_.h @@ -0,0 +1,422 @@ +// File: IOHIDDevice_.h +// Abstract: convieance functions for IOHIDDeviceGetProperty +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#ifndef __IOHIDDevice__ +#define __IOHIDDevice__ + +//***************************************************** +#pragma mark - includes & imports + +#include + +#include "IOHIDLib_.h" + +//***************************************************** +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if PRAGMA_IMPORT +#pragma import on +#endif + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH +#pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK +#pragma pack(2) +#endif + + //***************************************************** +#pragma mark - typedef's, struct's, enums, defines, etc. + //----------------------------------------------------- + + //***************************************************** +#pragma mark - exported globals + //----------------------------------------------------- + + //***************************************************** +#pragma mark - exported function prototypes + //----------------------------------------------------- + + //************************************************************************* + // + // HIDIsValidDevice( inIOHIDDeviceRef ) + // + // Purpose: validate this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: Boolean - TRUE if we find the device in our( internal ) device list + // + + extern Boolean HIDIsValidDevice(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetTransport( inIOHIDDeviceRef ) + // + // Purpose: get the Transport CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFStringRef - the Transport CFString for this device + // + + extern CFStringRef IOHIDDevice_GetTransport(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetVendorID( inIOHIDDeviceRef ) + // + // Purpose: get the vendor ID for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the vendor ID for this device + // + + extern long IOHIDDevice_GetVendorID(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef ) + // + // Purpose: get the VendorIDSource for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the VendorIDSource for this device + // + + extern long IOHIDDevice_GetVendorIDSource(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetProductID( inIOHIDDeviceRef ) + // + // Purpose: get the product ID for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the product ID for this device + // + + extern long IOHIDDevice_GetProductID(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef ) + // + // Purpose: get the VersionNumber CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the VersionNumber for this device + // + + extern long IOHIDDevice_GetVersionNumber(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetManufacturer( inIOHIDDeviceRef ) + // + // Purpose: get the Manufacturer CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFStringRef - the Manufacturer CFString for this device + // + + extern CFStringRef IOHIDDevice_GetManufacturer(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetProduct( inIOHIDDeviceRef ) + // + // Purpose: get the Product CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFStringRef - the Product CFString for this device + // + + extern CFStringRef IOHIDDevice_GetProduct(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef ) + // + // Purpose: get the SerialNumber CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFStringRef - the SerialNumber CFString for this device + // + + extern CFStringRef IOHIDDevice_GetSerialNumber(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetCountryCode( inIOHIDDeviceRef ) + // + // Purpose: get the CountryCode CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the CountryCode for this device + // + + extern long IOHIDDevice_GetCountryCode(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetLocationID( inIOHIDDeviceRef ) + // + // Purpose: get the location ID for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the location ID for this device + // + + extern long IOHIDDevice_GetLocationID(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetUsage( inIOHIDDeviceRef ) + // + // Purpose: get the usage for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: uint32_t - the usage for this device + // + + extern uint32_t IOHIDDevice_GetUsage(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetUsagePage( inIOHIDDeviceRef ) + // + // Purpose: get the usage page for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: uint32_t - the usage page for this device + // + + extern uint32_t IOHIDDevice_GetUsagePage(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef ) + // + // Purpose: get the UsagePairs CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFArrayRef - the UsagePairs for this device + // + + extern CFArrayRef IOHIDDevice_GetUsagePairs(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef ) + // + // Purpose: get the PrimaryUsage CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFStringRef - the PrimaryUsage CFString for this device + // + + extern uint32_t IOHIDDevice_GetPrimaryUsage(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef ) + // + // Purpose: get the PrimaryUsagePage CFString for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: CFStringRef - the PrimaryUsagePage CFString for this device + // + + extern uint32_t IOHIDDevice_GetPrimaryUsagePage(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef ) + // + // Purpose: get the MaxInputReportSize for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the MaxInputReportSize for this device + // + + extern long IOHIDDevice_GetMaxInputReportSize(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef ) + // + // Purpose: get the MaxOutputReportSize for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the MaxOutputReportSize for this device + // + + extern long IOHIDDevice_GetMaxOutputReportSize(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef ) + // + // Purpose: get the MaxFeatureReportSize for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the MaxFeatureReportSize for this device + // + + extern long IOHIDDevice_GetMaxFeatureReportSize(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetReportInterval( inIOHIDDeviceRef ) + // + // Purpose: get the ReportInterval for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: long - the ReportInterval for this device + // + + extern long IOHIDDevice_GetReportInterval(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_GetQueue( inIOHIDDeviceRef ) + // + // Purpose: get the Queue for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: IOHIDQueueRef - the Queue for this device + // + + extern IOHIDQueueRef IOHIDDevice_GetQueue(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_SetQueue( inIOHIDDeviceRef, inQueueRef ) + // + // Purpose: Set the Queue for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // inQueueRef - the Queue + // + // Returns: nothing + // + + extern void IOHIDDevice_SetQueue(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDQueueRef inQueueRef); + + //************************************************************************* + // + // IOHIDDevice_GetTransaction( inIOHIDDeviceRef ) + // + // Purpose: get the Transaction for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // + // Returns: IOHIDTransactionRef - the Transaction for this device + // + + extern IOHIDTransactionRef IOHIDDevice_GetTransaction(IOHIDDeviceRef inIOHIDDeviceRef); + + //************************************************************************* + // + // IOHIDDevice_SetTransaction( inIOHIDDeviceRef, inTransactionRef ) + // + // Purpose: Set the Transaction for this device + // + // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device + // inTransactionRef - the Transaction + // + // Returns: nothing + // + + extern void IOHIDDevice_SetTransaction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDTransactionRef inTransactionRef); + + //***************************************************** +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH +#pragma pack(pop) +#elif PRAGMA_STRUCT_PACK +#pragma pack() +#endif + +#ifdef PRAGMA_IMPORT_OFF +#pragma import off +#elif PRAGMA_IMPORT +#pragma import reset +#endif + +#ifdef __cplusplus +} +#endif + +#endif // __IOHIDDevice__ // diff --git a/src/cocoa/IOHIDElement_.c b/src/cocoa/IOHIDElement_.c new file mode 100755 index 000000000..f4d8be9eb --- /dev/null +++ b/src/cocoa/IOHIDElement_.c @@ -0,0 +1,502 @@ +// File: IOHIDElement_.c +// Abstract: convieance functions for IOHIDElementGetProperty +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#pragma mark - includes & imports +//----------------------------------------------------- + +#include "IOHIDElement_.h" + +//***************************************************** +#pragma mark - typedef's, struct's, enums, defines, etc. +//----------------------------------------------------- + +//***************************************************** +#pragma mark - local (static) function prototypes +//----------------------------------------------------- + +// static Boolean IOHIDElement_GetLongProperty( IOHIDElementRef inElementRef, CFStringRef inKey, long * outValue ); +// static void IOHIDElement_SetLongProperty( IOHIDElementRef inElementRef, CFStringRef inKey, long inValue ); + +//***************************************************** +#pragma mark - exported globals +//----------------------------------------------------- + +//***************************************************** +#pragma mark - local (static) globals +//----------------------------------------------------- + +//***************************************************** +#pragma mark - exported function implementations +//----------------------------------------------------- + +//************************************************************************* +// +// HIDIsValidElement( inIOHIDElementRef ) +// +// Purpose: validate this element +// +// Inputs: inIOHIDElementRef - the element +// +// Returns: Boolean - TRUE if this is a valid element ref +// +Boolean HIDIsValidElement(IOHIDElementRef inIOHIDElementRef) { + Boolean result = FALSE; // assume failure (pessimist!) + if ( inIOHIDElementRef ) { + if ( CFGetTypeID(inIOHIDElementRef) ==IOHIDElementGetTypeID() ) { + result = TRUE; + } + } + + return (result); +} // HIDIsValidElement + +//************************************************************************* +// +// IOHIDElement_GetValue( inElementRef, inIOHIDValueScaleType ) +// +// Purpose: returns the current value for an element( polling ) +// +// Notes: will return 0 on error conditions which should be accounted for by application +// +// Inputs: inElementRef - the element +// inIOHIDValueScaleType - scale type ( calibrated or physical ) +// +// Returns: double - current value for element +// +double IOHIDElement_GetValue(IOHIDElementRef inElementRef, IOHIDValueScaleType inIOHIDValueScaleType) { + long result = 0; + IOHIDValueRef tIOHIDValueRef; + if ( kIOReturnSuccess == IOHIDDeviceGetValue(IOHIDElementGetDevice(inElementRef), inElementRef, &tIOHIDValueRef) ) { + result = IOHIDValueGetScaledValue(tIOHIDValueRef, inIOHIDValueScaleType); + } + + return (result); +} // IOHIDElement_GetValue + +//************************************************************************* +// +// IOHIDElement_GetCalibrationMin( inElementRef ) +// +// Purpose: get the minimum bounds for a calibrated value for this element +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: CFIndex - the minimum Calibration value for this element +// + +CFIndex IOHIDElement_GetCalibrationMin(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMaxKey), &result) ) { + result = 0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationMin + +//************************************************************************* +// +// IOHIDElement_SetCalibrationMin( inElementRef, inValue ) +// +// Purpose: set the minimum bounds for a calibrated value for this element +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the minimum bounds for a calibrated value for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationMin(IOHIDElementRef inElementRef, CFIndex inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), inValue); +} // IOHIDElement_SetCalibrationMin + +//************************************************************************* +// +// IOHIDElement_GetCalibrationMax( inElementRef ) +// +// Purpose: get the maximum bounds for a calibrated value for this element +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: CFIndex - the maximum Calibration value for this element +// + +CFIndex IOHIDElement_GetCalibrationMax(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { + result = -0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationMax + +//************************************************************************* +// +// IOHIDElement_SetCalibrationMax( inElementRef, inValue ) +// +// Purpose: set the maximum bounds for a calibrated value for this element +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the maximum Calibration value for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationMax(IOHIDElementRef inElementRef, CFIndex inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), inValue); +} // IOHIDElement_SetCalibrationMax + +//************************************************************************* +// +// IOHIDElement_GetCalibrationSaturationMin( inElementRef ) +// +// Purpose: get the mininum tolerance to be used when calibrating a logical element value +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: CFIndex - the maximum Calibration value for this element +// + +CFIndex IOHIDElement_GetCalibrationSaturationMin(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { + result = -0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationSaturationMin + +//************************************************************************* +// +// IOHIDElement_SetCalibrationSaturationMin( inElementRef, inValue ) +// +// Purpose: set the mininum tolerance to be used when calibrating a logical element value +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the maximum Calibration value for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationSaturationMin(IOHIDElementRef inElementRef, CFIndex inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), inValue); +} // IOHIDElement_SetCalibrationSaturationMin + +//************************************************************************* +// +// IOHIDElement_GetCalibrationSaturationMax( inElementRef ) +// +// Purpose: get the maximum tolerance to be used when calibrating a logical element value +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: CFIndex - the maximum Calibration value for this element +// + +CFIndex IOHIDElement_GetCalibrationSaturationMax(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { + result = -0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationSaturationMax + +//************************************************************************* +// +// IOHIDElement_SetCalibrationSaturationMax( inElementRef, inValue ) +// +// Purpose: set the maximum tolerance to be used when calibrating a logical element value +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the maximum Calibration value for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationSaturationMax(IOHIDElementRef inElementRef, CFIndex inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), inValue); +} // IOHIDElement_SetCalibrationSaturationMax + +//************************************************************************* +// +// IOHIDElement_GetCalibrationDeadZoneMin( inElementRef ) +// +// Purpose: get the minimum bounds near the midpoint of a logical value in which the value is ignored +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: CFIndex - the maximum Calibration value for this element +// + +CFIndex IOHIDElement_GetCalibrationDeadZoneMin(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { + result = -0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationDeadZoneMin + +//************************************************************************* +// +// IOHIDElement_SetCalibrationDeadZoneMin( inElementRef, inValue ) +// +// Purpose: set the minimum bounds near the midpoint of a logical value in which the value is ignored +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the maximum Calibration value for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationDeadZoneMin(IOHIDElementRef inElementRef, CFIndex inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), inValue); +} // IOHIDElement_SetCalibrationDeadZoneMin + +//************************************************************************* +// +// IOHIDElement_GetCalibrationDeadZoneMax( inElementRef ) +// +// Purpose: get the maximum bounds near the midpoint of a logical value in which the value is ignored +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: CFIndex - the maximum Calibration value for this element +// + +CFIndex IOHIDElement_GetCalibrationDeadZoneMax(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { + result = -0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationDeadZoneMax + +//************************************************************************* +// +// IOHIDElement_SetCalibrationDeadZoneMax( inElementRef, inValue ) +// +// Purpose: set the maximum bounds near the midpoint of a logical value in which the value is ignored +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the maximum Calibration value for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationDeadZoneMax(IOHIDElementRef inElementRef, CFIndex inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), inValue); +} // IOHIDElement_SetCalibrationDeadZoneMax + +//************************************************************************* +// +// IOHIDElement_GetCalibrationGranularity( inElementRef ) +// +// Purpose: get the level of detail returned for a calibrated element value +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: double_t - the maximum Calibration value for this element +// + +double_t IOHIDElement_GetCalibrationGranularity(IOHIDElementRef inElementRef) { + CFIndex result; + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), &result) ) { + if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { + result = -0x7FFFFFFF; + } + + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), result); + } + + return (result); +} // IOHIDElement_GetCalibrationGranularity + +//************************************************************************* +// +// IOHIDElement_SetCalibrationGranularity( inElementRef, inValue ) +// +// Purpose: set the level of detail returned for a calibrated element value +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// inValue - the the level of detail for this element +// +// Returns: nothing +// + +void IOHIDElement_SetCalibrationGranularity(IOHIDElementRef inElementRef, double_t inValue) { + IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), inValue); +} // IOHIDElement_SetCalibrationGranularity + +//************************************************************************* +// +// IOHIDElement_SetupCalibration( inElementRef ) +// +// Purpose: set default values for the element calibration parameters +// +// Inputs: inElementRef - the IOHIDElementRef for this element +// +// Returns: nothing +// +void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef) { + // these are the min/max values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated ); + IOHIDElement_SetCalibrationMin( inIOHIDElementRef, IOHIDElementGetLogicalMin(inIOHIDElementRef) ); + IOHIDElement_SetCalibrationMax( inIOHIDElementRef, IOHIDElementGetLogicalMax(inIOHIDElementRef) ); + + // this is the granularity of the values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated ); + // for example if set to 0.1 the values returned will be multiples of 0.1 ( 0.1, 0.2, 0.3, etc. ) + IOHIDElement_SetCalibrationGranularity(inIOHIDElementRef, 0.); + + // these define the dead zone (like in the middel of joystick axis) + IOHIDElement_SetCalibrationDeadZoneMin(inIOHIDElementRef, 0); + IOHIDElement_SetCalibrationDeadZoneMax(inIOHIDElementRef, 0); +#if 1 + // get the current value of this element + double value = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical); + // use it as our min/mas saturation + IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, value); + IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, value); +#else + // calculate the middle physical value we would expect from this element + CFIndex valueMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef); + CFIndex valueMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef); + CFIndex valueMid = (valueMin + valueMax) / 2; + + // use it as our min/mas saturation + // this value determines the min/max values that have been recieved from the device element + IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, valueMid); + IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, valueMid); + + // get the current value of this element + double value = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical); + // and use it to adjust the current saturation values if it's outside their range + if ( value < IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef) ) { + IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, value); + } + if ( value > IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef) ) { + IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, value); + } + +#endif +} // IOHIDElement_SetupCalibration +//***************************************************** +#pragma mark - local (static) function implementations +//----------------------------------------------------- + +//************************************************************************* +// +// IOHIDElement_GetLongProperty( inElementRef, inKey, outValue ) +// +// Purpose: convieance function to return a long property of an element +// +// Inputs: inElementRef - the element +// inKey - CFString for the key +// outValue - address where to store the value +// Returns: Boolean - TRUE if successful +// outValue - the long property's value +// + +Boolean IOHIDElement_GetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long *outValue) { + Boolean result = FALSE; + + CFTypeRef tCFTypeRef = IOHIDElementGetProperty(inElementRef, inKey); + if ( tCFTypeRef ) { + // if this is a number + if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) { + // get it's value + result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue ); + } + } + + return (result); +} /* IOHIDElement_GetLongProperty */ + +//************************************************************************* +// +// IOHIDElement_SetLongProperty( inElementRef, inKey, inValue ) +// +// Purpose: convieance function to set a long property of an element +// +// Inputs: inElementRef - the element +// inKey - CFString for the key +// inValue - the value to set it to +// +// Returns: nothing +// + +void IOHIDElement_SetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long inValue) { + CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue); + if ( tCFNumberRef ) { + IOHIDElementSetProperty(inElementRef, inKey, tCFNumberRef); + CFRelease(tCFNumberRef); + } +} // IOHIDElement_SetLongProperty + +//***************************************************** diff --git a/src/cocoa/IOHIDElement_.h b/src/cocoa/IOHIDElement_.h new file mode 100755 index 000000000..a8a631668 --- /dev/null +++ b/src/cocoa/IOHIDElement_.h @@ -0,0 +1,339 @@ +// File: IOHIDElement_.h +// Abstract: convieance functions for IOHIDElementGetProperty +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#ifndef __IOHIDElement___ +#define __IOHIDElement___ + +//***************************************************** +#pragma mark - includes & imports + +#include + +#include "IOHIDLib_.h" +//***************************************************** +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if PRAGMA_IMPORT +#pragma import on +#endif + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH +#pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK +#pragma pack(2) +#endif + + //***************************************************** +#pragma mark - typedef's, struct's, enums, defines, etc. + //----------------------------------------------------- + + //***************************************************** +#pragma mark - exported globals + //----------------------------------------------------- + + //***************************************************** +#pragma mark - exported function prototypes + //----------------------------------------------------- + + //************************************************************************* + // + // HIDIsValidElement( inIOHIDElementRef ) + // + // Purpose: validate this element + // + // Inputs: inIOHIDElementRef - the element + // + // Returns: Boolean - TRUE if this is a valid element ref + // + extern Boolean HIDIsValidElement(IOHIDElementRef inIOHIDElementRef); + + //************************************************************************* + // + // IOHIDElement_GetValue( inElementRef, inIOHIDValueScaleType ) + // + // Purpose: returns the current value for an element( polling ) + // + // Notes: will return 0 on error conditions which should be accounted for by application + // + // Inputs: inElementRef - the element + // inIOHIDValueScaleType - scale type ( calibrated or physical ) + // + // Returns: double - current value for element + // + extern double IOHIDElement_GetValue(IOHIDElementRef inElementRef, IOHIDValueScaleType inIOHIDValueScaleType); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationMin( inElementRef ) + // + // Purpose: get the minimum bounds for a calibrated value for this element + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: CFIndex - the minimum Calibration value for this element + // + + extern CFIndex IOHIDElement_GetCalibrationMin(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationMin( inElementRef, inValue ) + // + // Purpose: set the minimum bounds for a calibrated value for this element + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the minimum bounds for a calibrated value for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationMin(IOHIDElementRef inElementRef, CFIndex inValue); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationMax( inElementRef ) + // + // Purpose: get the maximum bounds for a calibrated value for this element + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: CFIndex - the maximum Calibration value for this element + // + + extern CFIndex IOHIDElement_GetCalibrationMax(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationMax( inElementRef, inValue ) + // + // Purpose: set the maximum bounds for a calibrated value for this element + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the maximum Calibration value for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationMax(IOHIDElementRef inElementRef, CFIndex inValue); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationSaturationMin( inElementRef ) + // + // Purpose: get the mininum tolerance to be used when calibrating a logical element value + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: CFIndex - the maximum Calibration value for this element + // + + extern CFIndex IOHIDElement_GetCalibrationSaturationMin(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationSaturationMin( inElementRef, inValue ) + // + // Purpose: set the mininum tolerance to be used when calibrating a logical element value + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the maximum Calibration value for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationSaturationMin(IOHIDElementRef inElementRef, CFIndex inValue); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationSaturationMax( inElementRef ) + // + // Purpose: get the maximum tolerance to be used when calibrating a logical element value + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: CFIndex - the maximum Calibration value for this element + // + + extern CFIndex IOHIDElement_GetCalibrationSaturationMax(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationSaturationMax( inElementRef, inValue ) + // + // Purpose: set the maximum tolerance to be used when calibrating a logical element value + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the maximum Calibration value for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationSaturationMax(IOHIDElementRef inElementRef, CFIndex inValue); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationDeadZoneMin( inElementRef ) + // + // Purpose: get the minimum bounds near the midpoint of a logical value in which the value is ignored + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: CFIndex - the maximum Calibration value for this element + // + + extern CFIndex IOHIDElement_GetCalibrationDeadZoneMin(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationDeadZoneMin( inElementRef, inValue ) + // + // Purpose: set the minimum bounds near the midpoint of a logical value in which the value is ignored + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the maximum Calibration value for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationDeadZoneMin(IOHIDElementRef inElementRef, CFIndex inValue); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationDeadZoneMax( inElementRef ) + // + // Purpose: get the maximum bounds near the midpoint of a logical value in which the value is ignored + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: CFIndex - the maximum Calibration value for this element + // + + extern CFIndex IOHIDElement_GetCalibrationDeadZoneMax(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationDeadZoneMax( inElementRef, inValue ) + // + // Purpose: set the maximum bounds near the midpoint of a logical value in which the value is ignored + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the maximum Calibration value for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationDeadZoneMax(IOHIDElementRef inElementRef, CFIndex inValue); + + //************************************************************************* + // + // IOHIDElement_GetCalibrationGranularity( inElementRef ) + // + // Purpose: get the level of detail returned for a calibrated element value + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: double_t - the maximum Calibration value for this element + // + + extern double_t IOHIDElement_GetCalibrationGranularity(IOHIDElementRef inElementRef); + + //************************************************************************* + // + // IOHIDElement_SetCalibrationGranularity( inElementRef, inValue ) + // + // Purpose: set the level of detail returned for a calibrated element value + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // inValue - the the level of detail for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetCalibrationGranularity(IOHIDElementRef inElementRef, double_t inValue); + + //************************************************************************* + // + // IOHIDElement_SetupCalibration( inElementRef ) + // + // Purpose: set default values for the element calibration parameters + // + // Inputs: inElementRef - the IOHIDElementRef for this element + // + // Returns: nothing + // + + extern void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef); + + extern Boolean IOHIDElement_GetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long *outValue); + extern void IOHIDElement_SetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long inValue); + + //***************************************************** +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH +#pragma pack(pop) +#elif PRAGMA_STRUCT_PACK +#pragma pack() +#endif + +#ifdef PRAGMA_IMPORT_OFF +#pragma import off +#elif PRAGMA_IMPORT +#pragma import reset +#endif + +#ifdef __cplusplus +} +#endif + +#endif // __IOHIDElement___ // diff --git a/src/cocoa/IOHIDLib_.h b/src/cocoa/IOHIDLib_.h new file mode 100755 index 000000000..38c6248ac --- /dev/null +++ b/src/cocoa/IOHIDLib_.h @@ -0,0 +1,111 @@ +// File: IOHIDLib_.h +// Abstract: Single include file for all header files of IOHIDLib +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#ifndef __IOHIDLib___ +#define __IOHIDLib___ + +//***************************************************** +#pragma mark - includes & imports +//----------------------------------------------------- +#include + +#include "IOHIDDevice_.h" +#include "IOHIDElement_.h" + +#include "ImmrHIDUtilAddOn.h" + +//***************************************************** +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if PRAGMA_IMPORT +#pragma import on +#endif + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH +#pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK +#pragma pack(2) +#endif + + //***************************************************** +#pragma mark - typedef's, struct's, enums, defines, etc. + //----------------------------------------------------- + + //***************************************************** +#pragma mark - exported globals + //----------------------------------------------------- + + //***************************************************** +#pragma mark - exported function prototypes + //----------------------------------------------------- + + //***************************************************** +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH +#pragma pack(pop) +#elif PRAGMA_STRUCT_PACK +#pragma pack() +#endif + +#ifdef PRAGMA_IMPORT_OFF +#pragma import off +#elif PRAGMA_IMPORT +#pragma import reset +#endif + +#ifdef __cplusplus +} +#endif + +#endif // __IOHIDLib___ diff --git a/src/cocoa/ImmrHIDUtilAddOn.c b/src/cocoa/ImmrHIDUtilAddOn.c new file mode 100755 index 000000000..07e6a31b1 --- /dev/null +++ b/src/cocoa/ImmrHIDUtilAddOn.c @@ -0,0 +1,101 @@ +// File: ImmrHIDUtilAddOn.c +// Abstract: Glue code to convert IOHIDDeviceRef's to (FFB) io_object_t's +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#include +#include + +#include "ImmrHIDUtilAddOn.h" + +//--------------------------------------------------------------------------------- +// +// AllocateHIDObjectFromIOHIDDeviceRef( ) +// +// returns: +// NULL, or acceptable io_object_t +// +//--------------------------------------------------------------------------------- +io_service_t AllocateHIDObjectFromIOHIDDeviceRef(IOHIDDeviceRef inIOHIDDeviceRef) { + io_service_t result = 0L; + if ( inIOHIDDeviceRef ) { + // Set up the matching criteria for the devices we're interested in. + // We are interested in instances of class IOHIDDevice. + // matchingDict is consumed below( in IOServiceGetMatchingService ) + // so we have no leak here. + CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOHIDDeviceKey); + if ( matchingDict ) { + // Add a key for locationID to our matching dictionary. This works for matching to + // IOHIDDevices, so we will only look for a device attached to that particular port + // on the machine. + CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey) ); + if ( tCFTypeRef ) { + CFDictionaryAddValue(matchingDict, CFSTR(kIOHIDLocationIDKey), tCFTypeRef); + // CFRelease( tCFTypeRef ); // don't release objects that we "Get". + + // IOServiceGetMatchingService assumes that we already know that there is only one device + // that matches. This way we don't have to do the whole iteration dance to look at each + // device that matches. This is a new API in 10.2 + result = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); + } + + // Note: We're not leaking the matchingDict. + // One reference is consumed by IOServiceGetMatchingServices + } + } + + return (result); +} // AllocateHIDObjectFromIOHIDDeviceRef + +//--------------------------------------------------------------------------------- +// +// FreeHIDObject( ) +// +//--------------------------------------------------------------------------------- +bool FreeHIDObject(io_service_t inHIDObject) { + kern_return_t kr; + + kr = IOObjectRelease(inHIDObject); + + return (kIOReturnSuccess == kr); +} // FreeHIDObject diff --git a/src/cocoa/ImmrHIDUtilAddOn.h b/src/cocoa/ImmrHIDUtilAddOn.h new file mode 100755 index 000000000..72de752e3 --- /dev/null +++ b/src/cocoa/ImmrHIDUtilAddOn.h @@ -0,0 +1,50 @@ +// File: ImmrHIDUtilAddOn.h +// Abstract: Glue code to convert IOHIDDeviceRef's to (FFB) io_object_t's +// 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) 2009 Apple Inc. All Rights Reserved. +// +//***************************************************** +#include +#include + +extern io_service_t AllocateHIDObjectFromIOHIDDeviceRef(IOHIDDeviceRef inIOHIDDeviceRef); +extern bool FreeHIDObject(io_object_t inHIDObject);