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
// 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, IOHIDElementCookie 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); if (!inHIDInfoPtr->device.usagePage || !inHIDInfoPtr->device.usage) { inHIDInfoPtr->device.usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); inHIDInfoPtr->device.usage = IOHIDDevice_GetPrimaryUsage(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
/* PsychHIDGetDeviceListByUsages() */ void PsychHIDGetDeviceListByUsages(int numUsages, long *usagePages, long *usages, int *numDeviceIndices, int *deviceIndices, pRecDevice *deviceRecords) { pRecDevice currentDevice; int currentDeviceIndex; int currentUsage; long *usagePage; long *usage; PsychHIDVerifyInit(); *numDeviceIndices = 0; for (usagePage = usagePages, usage = usages, currentUsage = 0; currentUsage < numUsages; usagePage++, usage++, currentUsage++) { currentDeviceIndex = 0; for (currentDevice = HIDGetFirstDevice(); currentDevice != NULL; currentDevice = HIDGetNextDevice(currentDevice)) { ++currentDeviceIndex; if (IOHIDDevice_GetPrimaryUsagePage(currentDevice) == *usagePage && IOHIDDevice_GetPrimaryUsage(currentDevice) == *usage) { deviceRecords[*numDeviceIndices] = currentDevice; deviceIndices[*numDeviceIndices] = currentDeviceIndex; //the array is 0-indexed, devices are 1-indexed. ++(*numDeviceIndices); } } } }
Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo, IOHIDDeviceRef * outFoundDevice, IOHIDElementRef * outFoundElement) { Boolean result = false; IOHIDDeviceRef bestIOHIDDeviceRef = NULL; IOHIDElementRef bestIOHIDElementRef = NULL; int bestScore = 0; CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef); for (devIndex = 0; devIndex < devCount; devIndex++) { int deviceScore = 1; IOHIDDeviceRef tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); if (!tIOHIDDeviceRef) { continue; } // match vendorID, productID (+10, +8) if (inSearchInfo->device.vendorID) { uint32_t vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); if (vendorID) { if (inSearchInfo->device.vendorID == vendorID) { deviceScore += 10; if (inSearchInfo->device.productID) { uint32_t 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) { uint32_t 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; } int 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
// 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) { (void) CFStringGetCString(tCFStringRef, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8); } char product[256] = ""; // name of product tCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, product, sizeof(product), kCFStringEncodingUTF8); } printf("%s - %s, ", manufacturer, product); long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); if (vendorID) { if ( HIDGetVendorNameFromVendorID(vendorID, cstring) ) { printf(" vendorID: 0x%04lX (\"%s\"), ", vendorID, cstring); } else { printf(" vendorID: 0x%04lX, ", vendorID); } } long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); if (productID) { if ( HIDGetProductNameFromVendorProductID(vendorID, productID, cstring) ) { printf(" productID: 0x%04lX (\"%s\"), ", productID, cstring); } else { printf(" productID: 0x%04lX, ", productID); } } 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); tCFStringRef = HIDCopyUsageName(usagePage, usage); if (tCFStringRef) { (void) CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8); printf("\"%s\", ", cstring); CFRelease(tCFStringRef); } tCFStringRef = IOHIDDevice_GetTransport(inIOHIDDeviceRef); if (tCFStringRef) { (void) 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) { (void) 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 false 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 // if false 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); } printf("}\n"); fflush(stdout); } // HIDDumpDeviceInfo
/* PsychHIDGetDeviceListByUsage() */ void PsychHIDGetDeviceListByUsage(long usagePage, long usage, int *numDeviceIndices, int *deviceIndices, pRecDevice *deviceRecords) { pRecDevice currentDevice; int currentDeviceIndex; PsychHIDVerifyInit(); currentDeviceIndex=0; *numDeviceIndices=0; for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){ ++currentDeviceIndex; #ifndef __LP64__ if(currentDevice->usagePage==usagePage && currentDevice->usage==usage){ #else if(IOHIDDevice_GetUsagePage(currentDevice) == usagePage && IOHIDDevice_GetUsage(currentDevice) == usage){ #endif deviceRecords[*numDeviceIndices]=currentDevice; deviceIndices[*numDeviceIndices]=currentDeviceIndex; //the array is 0-indexed, devices are 1-indexed. ++(*numDeviceIndices); } } } /* PsychHIDGetDeviceListByUsages() */ void PsychHIDGetDeviceListByUsages(int numUsages, long *usagePages, long *usages, int *numDeviceIndices, int *deviceIndices, pRecDevice *deviceRecords) { pRecDevice currentDevice; int currentDeviceIndex; int currentUsage; long *usagePage; long *usage; PsychHIDVerifyInit(); *numDeviceIndices=0; for(usagePage=usagePages, usage=usages, currentUsage=0; currentUsage<numUsages; usagePage++, usage++, currentUsage++){ currentDeviceIndex=0; for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){ ++currentDeviceIndex; #ifndef __LP64__ if(currentDevice->usagePage==*usagePage && currentDevice->usage==*usage){ #else if(IOHIDDevice_GetPrimaryUsagePage(currentDevice) == *usagePage && IOHIDDevice_GetPrimaryUsage(currentDevice) == *usage){ #endif deviceRecords[*numDeviceIndices]=currentDevice; deviceIndices[*numDeviceIndices]=currentDeviceIndex; //the array is 0-indexed, devices are 1-indexed. ++(*numDeviceIndices); } } } } /* PsychHIDGetIndexFromRecord() The inverse of PsychHIDGetDeviceRecordPtrFromIndex. This O(n) where n is the number of device elements. We could make it O(1) if we modified the element structure in the HID Utilities library to include a field specifying the index of the element or collection. Note that if PsychHIDGetIndexFromRecord() is O(n) then its caller, PsychHIDGetCollections, is O(n^2) for each device, whereas if PsychHIDGetIndexFromRecord() is O(1) then psychHIDGetCollections becomes O(n) for each device. */ int PsychHIDGetIndexFromRecord(pRecDevice deviceRecord, pRecElement elementRecord, HIDElementTypeMask typeMask) { int elementIndex; pRecElement currentElement; if(elementRecord==NULL) return(0); elementIndex=1; for(currentElement=HIDGetFirstDeviceElement(deviceRecord, typeMask); currentElement != elementRecord && currentElement != NULL; currentElement=HIDGetNextDeviceElement(currentElement, typeMask)) ++elementIndex; if(currentElement==elementRecord) return(elementIndex); else{ PsychErrorExitMsg(PsychError_internal, "Element record not found within device record"); return(0); //make the compiler happy } }