From 6b2aa4a4a7816d604ee63c974131c03fed9a4b7c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 28 Jan 2010 00:37:54 +0000 Subject: first working version of hidio+HIDUtilities build on Mac OS X using autotools, still needs work svn path=/trunk/externals/io/hidio/; revision=13107 --- HID_Utilities_Source/HID_Config_Utilities.c | 425 ++++++++++++++++++++++++++++ 1 file changed, 425 insertions(+) create mode 100644 HID_Utilities_Source/HID_Config_Utilities.c (limited to 'HID_Utilities_Source/HID_Config_Utilities.c') diff --git a/HID_Utilities_Source/HID_Config_Utilities.c b/HID_Utilities_Source/HID_Config_Utilities.c new file mode 100644 index 0000000..a8e97b2 --- /dev/null +++ b/HID_Utilities_Source/HID_Config_Utilities.c @@ -0,0 +1,425 @@ +/* + File: HID_Config_Utilities.c + + Contains: Implementation of the HID configuration utilities for the HID utilities. + + DRI: George Warner + + Copyright: Copyright © 2002 Apple Computer, Inc., All Rights Reserved + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, 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 Computer, 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. + +*/ + +#include // malloc +#include // clock + +#include + +#include "HID_Utilities_Internal.h" +#include "HID_Utilities_External.h" + +// --------------------------------- +// 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 + +unsigned char HIDConfigureAction (pRecDevice * ppDevice, pRecElement * ppElement, float timeout) +{ + long numDevices, maxElements = 0; + long * saveValueArray; + pRecDevice pDevice = NULL; + pRecElement pElement = NULL; + short deviceNum = 0; + unsigned char found = 0, done = 0; + clock_t start = clock (), end; + + if (!HIDHaveDeviceList ()) // if we do not have a device list + if (0 == HIDBuildDeviceList (kHIDPage_GenericDesktop, 0)) // if we could not build another list (use generic page) + return 0; // return 0 + + // build list of device and elements to save current values + numDevices = HIDCountDevices (); + pDevice = HIDGetFirstDevice (); + while (pDevice) + { + long numElements = HIDCountDeviceElements (pDevice, kHIDElementTypeInput); + if (numElements > maxElements) + maxElements = numElements; + pDevice = HIDGetNextDevice (pDevice); + } + saveValueArray = (long *) malloc (sizeof (long) * numDevices * maxElements); // 2D array to save values + bzero(saveValueArray,sizeof (long) * numDevices * maxElements); // clear array + + // store current values + deviceNum = 0; + pDevice = HIDGetFirstDevice (); + while (pDevice) + { + short elementNum = 0; + pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeInput); + while (pElement) + { + *(saveValueArray + (deviceNum * maxElements) + elementNum) = HIDGetElementValue (pDevice, pElement); + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeInput); + elementNum++; + } + pDevice = HIDGetNextDevice (pDevice); + deviceNum++; + } + + // poll all devices and elements, compare current value to save +/- kPercentMove + while ((!found) && (!done)) + { + double secs; + // are we done? + end = clock(); + secs = (double)(end - start) / CLOCKS_PER_SEC; + if (secs > timeout) + done = 1; + deviceNum = 0; + pDevice = HIDGetFirstDevice (); + while (pDevice) + { + short elementNum = 0; + pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeInput); + while (pElement) + { + // ignore force feedback devices AND arrays + if ((kHIDPage_PID != pElement->usagePage) && (-1 != pElement->usage)) + { + long initialValue = *(saveValueArray + (deviceNum * maxElements) + elementNum); + long value = HIDGetElementValue (pDevice, pElement); + long delta = (float)(pElement->max - pElement->min) * kPercentMove * 0.01; + + if (((initialValue + delta) < value) || ((initialValue - delta) > value)) + { + found = 1; + break; + } + } + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeInput); + elementNum++; + } + if (found) + break; + pDevice = HIDGetNextDevice (pDevice); + deviceNum++; + } + } + + // return device and element moved + if (found) + { + *ppDevice = pDevice; + *ppElement = pElement; + return 1; + } + else + { + *ppDevice = NULL; + *ppElement = NULL; + return 0; + } +} + +// --------------------------------- +// takes input records, save required info +// assume file is open and at correct position. +// will always write to file (if file exists) size of recSaveHID, even if device and or element is bad + +void HIDSaveElementConfig (FILE * fileRef, pRecDevice pDevice, pRecElement pElement, long actionCookie) +{ + recSaveHID saveRec; + + if (HIDIsValidElement(pDevice,pElement)) + { + // clear rec + bzero(&saveRec,sizeof(recSaveHID)); + + saveRec.actionCookie = actionCookie; + + // must save + // actionCookie + // Device: serial,vendorID, productID, location, usagePage, usage + // Element: cookie, usagePage, usage, + // need to add serial number when I have a test case + + saveRec.vendorID = pDevice->vendorID; + saveRec.productID = pDevice->productID; + saveRec.locID = pDevice->locID; + saveRec.usage = pDevice->usage; + saveRec.usagePage = pDevice->usagePage; + + saveRec.usagePageE = pElement->usagePage; + saveRec.usageE = pElement->usage; + saveRec.cookie = pElement->cookie; + + // write to file + if (fileRef) + fwrite ((void *)&saveRec, sizeof (recSaveHID), 1, fileRef); + } +} + +// --------------------------------- +// 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 + +long HIDRestoreElementConfig (FILE * fileRef, pRecDevice * ppDevice, pRecElement * ppElement) +{ + // Device: serial,vendorID, productID, location, usagePage, usage + // Element: cookie, usagePage, usage, + + pRecDevice pDevice, pFoundDevice = NULL; + pRecElement pElement, pFoundElement = NULL; + + recSaveHID restoreRec; + + fread ((void *) &restoreRec, 1, sizeof (recSaveHID), fileRef); + + // compare to current device list for matches + // look for device + if (restoreRec.locID && restoreRec.vendorID && restoreRec.productID) + { // look for specific device type plug in to same port + pDevice = HIDGetFirstDevice (); + while (pDevice) + { + if ((restoreRec.locID == pDevice->locID) && + (restoreRec.vendorID == pDevice->vendorID) && + (restoreRec.productID == pDevice->productID)) + pFoundDevice = pDevice; + if (pFoundDevice) + break; + pDevice = HIDGetNextDevice (pDevice); + } + if (pFoundDevice) + { + pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); + while (pElement) + { + if (restoreRec.cookie == pElement->cookie) + pFoundElement = pElement; + if (pFoundElement) + break; + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); + } + // if no cookie match (should NOT occur) match on usage + pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); + while (pElement) + { + if ((restoreRec.usageE == pElement->usage) && + (restoreRec.usagePageE == pElement->usagePage)) + pFoundElement = pElement; + if (pFoundElement) + break; + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); + } + } + } + // if we have not found a match, look at just vendor and product + if ((NULL == pFoundDevice) && + (restoreRec.vendorID && restoreRec.productID)) + { + pDevice = HIDGetFirstDevice (); + while (pDevice) + { + if ((restoreRec.vendorID == pDevice->vendorID) && + (restoreRec.productID == pDevice->productID)) + pFoundDevice = pDevice; + if (pFoundDevice) + break; + pDevice = HIDGetNextDevice (pDevice); + } + // match elements by cookie since same device type + if (pFoundDevice) + { + pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); + while (pElement) + { + if (restoreRec.cookie == pElement->cookie) + pFoundElement = pElement; + if (pFoundElement) + break; + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); + } + // if no cookie match (should NOT occur) match on usage + pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); + while (pElement) + { + if ((restoreRec.usageE == pElement->usage) && + (restoreRec.usagePageE == pElement->usagePage)) + pFoundElement = pElement; + if (pFoundElement) + break; + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); + } + } + } + // if we have not found a match look for just same type of device + if ((NULL == pFoundDevice) && (restoreRec.usage && restoreRec.usagePage)) + { + pDevice = HIDGetFirstDevice (); + while (pDevice) + { + if ((restoreRec.usage == pDevice->usage) && (restoreRec.usagePage == pDevice->usagePage)) + pFoundDevice = pDevice; + if (pFoundDevice) + break; + pDevice = HIDGetNextDevice (pDevice); + } + // match elements by type + if (pFoundDevice) + { + pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); + while (pElement) + { + if ((restoreRec.usageE == pElement->usage) && + (restoreRec.usagePageE == pElement->usagePage)) + pFoundElement = pElement; + if (pFoundElement) + break; + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); + } + } + } + // if still not found just get first device + if (NULL == pFoundDevice) + { + pFoundDevice = HIDGetFirstDevice (); + // match elements by type + if (pFoundDevice) + { + pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); + while (pElement) + { + if ((restoreRec.usageE == pElement->usage) && + (restoreRec.usagePageE == pElement->usagePage)) + pFoundElement = pElement; + if (pFoundElement) + break; + pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); + } + } + } + if ((NULL == pFoundDevice) || (NULL == pFoundElement)) + { + // no HID device + *ppDevice = NULL; + *ppElement = NULL; + return restoreRec.actionCookie; + } + else + { + // no HID device + *ppDevice = pFoundDevice; + *ppElement = pFoundElement; + return restoreRec.actionCookie; + } + +} + +// --------------------------------- +// Find the specified preference in the specified application +// search for matching device and element +// return pDevice, pElement that matches + +Boolean HIDRestoreElementPref (CFStringRef keyCFStringRef, CFStringRef appCFStringRef, pRecDevice * ppDevice, pRecElement * ppElement) +{ + Boolean found = false; + + if ((NULL != keyCFStringRef) && (NULL != appCFStringRef) && (NULL != ppDevice) && (NULL != ppElement)) + { + CFPropertyListRef prefCFPropertyListRef = CFPreferencesCopyAppValue(keyCFStringRef, appCFStringRef); + + if (NULL != prefCFPropertyListRef) + { + if (CFStringGetTypeID() == CFGetTypeID(prefCFPropertyListRef)) + { + char buffer[256]; + + if (CFStringGetCString((CFStringRef) prefCFPropertyListRef, buffer, sizeof(buffer), kCFStringEncodingASCII)) + { + recDevice searchDevice; + recElement searchElement; + int count = sscanf(buffer, "d:{v:%ld, p:%ld, l:%ld, p:%ld, u:%ld}, e:{t:%ld, p:%ld, u:%ld, c:%ld}", + &searchDevice.vendorID, &searchDevice.productID, &searchDevice.locID, &searchDevice.usagePage, &searchDevice.usage, + &searchElement.type, &searchElement.usagePage, &searchElement.usage, (long*) &searchElement.cookie); + + if (9 == count) // if we found all nine parametersÉ + { // and can find a device & element that matches theseÉ + if (HIDFindActionDeviceAndElement(&searchDevice, &searchElement,ppDevice, ppElement)) + { + found = true; + } + } + } + } + else + { + // We found the entry with this key but it's the wrong type; delete it. + CFPreferencesSetAppValue(keyCFStringRef, NULL, appCFStringRef); + (void) CFPreferencesAppSynchronize(appCFStringRef); + } + CFRelease(prefCFPropertyListRef); + } + } + return found; +} + +// --------------------------------- +// Save the device & element values into the specified key in the specified applications preferences + +Boolean HIDSaveElementPref (const CFStringRef keyCFStringRef, CFStringRef appCFStringRef, pRecDevice pDevice, pRecElement pElement) +{ + Boolean success = false; + + if ((NULL != keyCFStringRef) && (NULL != appCFStringRef) && HIDIsValidElement(pDevice,pElement)) + { + CFStringRef prefCFStringRef = + CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("d:{v:%ld, p:%ld, l:%ld, p:%ld, u:%ld}, e:{t:%ld, p:%ld, u:%ld, c:%ld}"), + pDevice->vendorID, pDevice->productID, pDevice->locID, pDevice->usagePage, pDevice->usage, + pElement->type, pElement->usagePage, pElement->usage, pElement->cookie); + + if (NULL != prefCFStringRef) + { + CFPreferencesSetAppValue(keyCFStringRef, prefCFStringRef, kCFPreferencesCurrentApplication); + CFRelease(prefCFStringRef); + success = true; + } + } + return success; +} -- cgit v1.2.1