// 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 (pRecSaveHID pConfigRec, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef, int actionCookie)
{
	// must save:
    // actionCookie
    // Device: serial,vendorID, productID, location, usagePage, usage
    // Element: cookie, usagePage, usage,
    pConfigRec->actionCookie = actionCookie;
    // device
    // need to add serial number when I have a test case
	if (inIOHIDDeviceRef && inIOHIDElementRef) {
		pConfigRec->device.vendorID = IOHIDDevice_GetVendorID( inIOHIDDeviceRef );
		pConfigRec->device.productID = IOHIDDevice_GetProductID( inIOHIDDeviceRef );
		pConfigRec->device.locID = IOHIDDevice_GetLocationID( inIOHIDDeviceRef );
		pConfigRec->device.usage = IOHIDDevice_GetUsage( inIOHIDDeviceRef );
		pConfigRec->device.usagePage = IOHIDDevice_GetUsagePage( inIOHIDDeviceRef );
		
		pConfigRec->element.usagePage = IOHIDElementGetUsagePage( inIOHIDElementRef );
		pConfigRec->element.usage = IOHIDElementGetUsage( inIOHIDElementRef );
		pConfigRec->element.minReport = IOHIDElement_GetCalibrationSaturationMin( inIOHIDElementRef );
		pConfigRec->element.maxReport = IOHIDElement_GetCalibrationSaturationMax( inIOHIDElementRef );
		pConfigRec->element.cookie = IOHIDElementGetCookie( inIOHIDElementRef );
	} else {
		pConfigRec->device.vendorID = 0;
		pConfigRec->device.productID = 0;
		pConfigRec->device.locID = 0;
		pConfigRec->device.usage = 0;
		pConfigRec->device.usagePage = 0;
		
		pConfigRec->element.usagePage = 0;
		pConfigRec->element.usage = 0;
		pConfigRec->element.minReport = 0;
		pConfigRec->element.maxReport = 0;
		pConfigRec->element.cookie = 0;
	}
}
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
Example #3
0
/*
    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;
        if (IOHIDDevice_GetUsagePage(currentDevice) == usagePage && IOHIDDevice_GetUsage(currentDevice) == usage) {
            deviceRecords[*numDeviceIndices] = currentDevice;
            deviceIndices[*numDeviceIndices] = currentDeviceIndex;  //the array is 0-indexed, devices are 1-indexed.
            ++(*numDeviceIndices);
        }
    }
}
// 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
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
void PsychHIDOSKbTriggerWait(int deviceIndex, int numScankeys, int* scanKeys)
{
    pRecDevice	deviceRecord;
    int			i, numDeviceIndices;
    long		KeysUsagePage;			// This is the usage page of the target element: A key on a keyboard/keypad or a button.
	long		KeysUsage;				// This will contain the key code of the trigger key
	long		KbDeviceUsagePages[NUMDEVICEUSAGES]= {kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop};
	long		KbDeviceUsages[NUMDEVICEUSAGES]={kHIDUsage_GD_Keyboard, kHIDUsage_GD_Keypad, kHIDUsage_GD_Mouse, kHIDUsage_GD_Pointer, kHIDUsage_GD_Joystick, kHIDUsage_GD_GamePad, kHIDUsage_GD_MultiAxisController};
    int 		numDeviceUsages=NUMDEVICEUSAGES;
    int			deviceIndices[PSYCH_HID_MAX_KEYBOARD_DEVICES]; 
    pRecDevice	deviceRecords[PSYCH_HID_MAX_KEYBOARD_DEVICES];
    psych_bool	isDeviceSpecified, foundUserSpecifiedDevice;
    double		*timeValueOutput;
	
	IOHIDQueueInterface **queue;
	HRESULT result;
	IOHIDDeviceInterface122** interface=NULL;	// This requires Mac OS X 10.3 or higher
	IOReturn success;	
	IOHIDElementCookie triggerCookie;
    uint32_t usage;

    // Assign single supported trigger key:
    if (numScankeys != 1) PsychErrorExitMsg(PsychError_user, "Sorry, the OS/X version of KbTriggerWait only supports one trigger key.");
    KeysUsage = (long) scanKeys[0];

    // Optional deviceIndex specified?
    isDeviceSpecified = (deviceIndex >= 0) ? TRUE : FALSE;
    
    PsychHIDVerifyInit();	
	if(hidDataRef!=NULL) PsychErrorExitMsg(PsychError_user, "A queue is already running, you must call KbQueueRelease() before invoking KbTriggerWait.");

    //Choose the device index and its record
    PsychHIDGetDeviceListByUsages(numDeviceUsages, KbDeviceUsagePages, KbDeviceUsages, &numDeviceIndices, deviceIndices, deviceRecords);  
    
    if(isDeviceSpecified){  //make sure that the device number provided by the user is really a keyboard or keypad.
        for(i=0;i<numDeviceIndices;i++){
            if(foundUserSpecifiedDevice=(deviceIndices[i]==deviceIndex))
                break;
        }
        if(!foundUserSpecifiedDevice)
            PsychErrorExitMsg(PsychError_user, "Specified device number is not a keyboard or keypad device.");
    }else{ // set the keyboard or keypad device to be the first keyboard device or, if no keyboard, the first keypad
        i=0;
        if(numDeviceIndices==0)
            PsychErrorExitMsg(PsychError_user, "No keyboard or keypad devices detected.");
        else{
            deviceIndex=deviceIndices[i];
        }
    }
    deviceRecord=deviceRecords[i]; 
#ifndef __LP64__
    usage = deviceRecord->usage;
#else
    usage = IOHIDDevice_GetUsage(deviceRecord);
#endif

	KeysUsagePage = ((usage == kHIDUsage_GD_Keyboard) || (usage == kHIDUsage_GD_Keypad)) ? kHIDPage_KeyboardOrKeypad : kHIDPage_Button;

    //Allocate and init out return arguments.
    PsychAllocOutDoubleArg(1, FALSE, &timeValueOutput);
	if(!timeValueOutput)
		PsychErrorExitMsg(PsychError_system, "Failed to allocate memory for output.");

	interface = PsychHIDGetDeviceInterfacePtrFromIndex(deviceIndex);
	if(!interface)
		PsychErrorExitMsg(PsychError_system, "Could not get interface to device.");
	
	// The following bracketed clause will get a cookie corresponding to the
	// trigger. If multiple keys were of interest, the code could be modified
	// trivially to iterate over an array of KeysUsage to generate an array of 
	// corresponding cookies
	{
		CFArrayRef elements=NULL;
		psych_bool usedDictionary=FALSE;
		{
			CFDictionaryRef dict=NULL;
		
			// The next few lines define a dictionary describing the key of interest
			// If they are omitted, the code will still work, but all elements will match
			// initially rather than just the one key of interest, so the code will be
			// slower since it will iterate through hundreds of keys
			CFStringRef keys[2] = {CFSTR("UsagePage"), CFSTR("Usage")};
			CFNumberRef values[2];
			values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &KeysUsagePage);
			values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &KeysUsage);
			if(values[0]!=NULL && values[1]!=NULL){
				// Even if they are NULL, it will be ok since dict can be NULL at the expense of some loss of efficiency
				dict = CFDictionaryCreate(kCFAllocatorDefault, (const void**)keys, (const void**)values, 2, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
			}
	
			// copyMatchinfElements requires IOHIDDeviceInterface122, thus Mac OS X 10.3 or higher
			// elements would have to be obtained directly from IORegistry for 10.2 or earlier
			// If dict==NULL, all elements will match, leading to some inefficiency
			success = (*interface)->copyMatchingElements(interface, dict, &elements);
		
			if(dict){
				usedDictionary=TRUE;
				CFRelease(dict);
			}

			if(values[0]) CFRelease(values[0]);
			if(values[1]) CFRelease(values[1]);
			
			if(!elements){
				PsychErrorExitMsg(PsychError_user, "Specified key code not found on device (I).");
			}
		}
		{
			// elements will only contain one element in this implementation, but has the
			// advantage of generalizing to future derived implementations that listen
			// for multiple keys
			CFIndex i;
			for (i=0; i<CFArrayGetCount(elements); i++)
			{
				long number;
				CFDictionaryRef element= CFArrayGetValueAtIndex(elements, i);
				CFTypeRef object;
				
				if(!element) continue;
				
				if(!usedDictionary){
				
					// Verify tht we are dealing with a keypad or keyboard
					object = CFDictionaryGetValue(element, CFSTR(kIOHIDElementUsageKey));
					if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue;
					if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType,&number)) continue;
					if(number!=KeysUsage) continue;
				
					// See if element corresponds to the desired key
					object = CFDictionaryGetValue(element, CFSTR(kIOHIDElementUsagePageKey));
					if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue;
					if (!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, &number)) continue;
					if(number!=KeysUsagePage) continue;
				}
				
				// Get the cookie for this element
				object= (CFDictionaryGetValue(element, CFSTR(kIOHIDElementCookieKey)));
				if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue;
				if(!CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, &number)) continue;
				triggerCookie = (IOHIDElementCookie) number;
				
				break;
			}
			if(CFArrayGetCount(elements)==i){
				CFRelease(elements);
				PsychErrorExitMsg(PsychError_user, "Specified key code not found on device (II).");
			}
			CFRelease(elements);
		}
	}

	// Allocate for the queue
	queue=(*interface)->allocQueue(interface);
	if(!queue){
		PsychErrorExitMsg(PsychError_system, "Failed to allocate event queue for detecting key press.");
	}
	
	// Create the queue
	result = (*queue)->create(queue, 0, 8);		// 8 events can be stored before the earliest event is lost
	if (kIOReturnSuccess != result){
		(*queue)->Release(queue);
		(*queue)=NULL;
		PsychErrorExitMsg(PsychError_system, "Failed to create event queue for detecting key press.");
	}
	
	// Add the trigger to the queue
	// If multiple keys were of interest, their cookies could be added in turn
	result = (*queue)->addElement(queue, triggerCookie, 0);
	if (kIOReturnSuccess != result){
		result = (*queue)->dispose(queue);
		(*queue)->Release(queue);
		(*queue)=NULL;
		PsychErrorExitMsg(PsychError_system, "Failed to add trigger key to event queues.");
	}
	
	// Start the queue
	result = (*queue)->start(queue);
	if (kIOReturnSuccess != result){
		result = (*queue)->dispose(queue);
		(*queue)->Release(queue);
		(*queue)=NULL;
		PsychErrorExitMsg(PsychError_system, "Failed to start event queues.");
	}
	 
	// Watch for the trigger
	{
		IOHIDEventStruct event;
		while(1){
			
			AbsoluteTime zeroTime = {0,0};
			result = (*queue)->getNextEvent(queue, &event, zeroTime, 0);
			if(kIOReturnSuccess==result) break;
			PsychWaitIntervalSeconds((double)0.004);  //surrender some time to other processes	
		
			// If it were of interest to trigger selectively on key press or key release,
			// this could be evaluated by checking event.value (zero versus non-zero)
			// but this would put more code inside the loop
			
			// If multiple keys are registered via addElement (not the case here), the
			// cookie for the key responsible for the event can be obtained from 
			// event.elementCookie
		}
		
		// If event.longValue is not NULL, the documentation indicates that it is up
		// to the caller to deallocate it. The circumstances under which a non-NULL
		// value would be generated are not specified. My guess is that some devices 
		// might return a 64-bit value (e.g., a tracking device coordinate).
		// Keys, having only two states, shouldn't need this, but check and free to
		// be safe		
		if ((event.longValueSize != 0) && (event.longValue != NULL)) free(event.longValue);
		
		// Set the time, using the same strategy as PsychTimeGlue's PsychGetPrecisionTimerSeconds
		// For code maintainability, it would be better if this conversion were performed
		// by a function in PsychTimeGlue
		{
			Nanoseconds timeNanoseconds=AbsoluteToNanoseconds(event.timestamp);
			UInt64 timeUInt64=UnsignedWideToUInt64(timeNanoseconds);
			double timeDouble=(double)timeUInt64;
			*timeValueOutput=timeDouble / 1000000000;
		}
	}
	
	// Clean up
	result = (*queue)->stop(queue);
	// Code from Apple sometimes removes elements from queue before disposing and sometimes does not
	// I can't see any reason to do so for a queue that's one line of code away from destruction
	// and therefore haven't
	result = (*queue)->dispose(queue);
	(*queue)->Release(queue);
	(*queue)=NULL;				// Just in case queue is redefined as static in the future
	
    return;
}
Example #7
0
// 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
Example #8
0
/*
    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
    }
}