PsychError PSYCHHIDGiveMeReports(void)
{
    PsychGenericScriptType *outErr;
    const char *fieldNames[] = {"n", "name", "description"};

    char *name = "", *description = "";
    long error = 0;
    int deviceIndex;
    int reportBytes = 1024;

    PsychPushHelp(useString,synopsisString,seeAlsoString);
    if (PsychIsGiveHelp()) { PsychGiveHelp(); return(PsychError_none); };

    PsychErrorExit(PsychCapNumOutputArgs(2));
    PsychErrorExit(PsychCapNumInputArgs(2));

    PsychCopyInIntegerArg(1,TRUE,&deviceIndex);
    PsychCopyInIntegerArg(2,false,&reportBytes);

    PsychHIDVerifyInit();

    // Returns 1st return argument 'reports':
    error = GiveMeReports(deviceIndex,reportBytes); // PsychHIDReceiveReports.c

    // Return 2nd return argument 'err' struct:
    PsychHIDErrors(NULL, error, &name, &description);
    PsychAllocOutStructArray(2, kPsychArgOptional, -1, 3, fieldNames, &outErr);
    PsychSetStructArrayStringElement("name", 0, name, outErr);
    PsychSetStructArrayStringElement("description", 0, description, outErr);
    PsychSetStructArrayDoubleElement("n", 0, (double) error, outErr);

    return(PsychError_none);
}
Exemplo n.º 2
0
/* 
    PsychHIDGetDeviceRecordPtrFromIndex()
    
    The inverse of PsychHIDGetIndexFromRecord()
    
    Accept the index from the list of device records and return a pointer to the indicated record.  Externally the list is one-indexed.  
*/
pRecDevice PsychHIDGetDeviceRecordPtrFromIndex(int deviceIndex)
{
    int				i;
    pRecDevice 		currentDevice=NULL;

    PsychHIDVerifyInit();
    i=1;
    for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){    
        if(i==deviceIndex) {
            #if PSYCH_SYSTEM != PSYCH_OSX
                if (!currentDevice->interface) {
                    currentDevice->interface = (void*) hid_open_path(currentDevice->transport);
                    if (!currentDevice->interface) PsychErrorExitMsg(PsychError_system, "HIDLIB Failed to open USB device!");

                    // Set read ops on device to non-blocking:
                    hid_set_nonblocking((hid_device*) currentDevice->interface, 1);
                }
            #endif
            return(currentDevice);
        }
        ++i;
    }
    
    PsychErrorExitMsg(PsychError_user, "Invalid device index specified. Has a device been unplugged? Try rebuilding the device list");
    return(NULL);  //make the compiler happy.
}
Exemplo n.º 3
0
/*
        PsychHIDQueryOpenDeviceInterfaceFromDeviceIndex()

        Check the interface field of the libHIDUtilities device structure for NULLness.  libHIDUtilities.h seems to indicate that it is neccessary for application
        to invoke HIDCreateOpenDeviceInterface() before accessing a device.  However,
        1) libHIDUtilities provides no way to obtain a value for the required first argument to HIDCreateOpenDeviceInterface().  
        2) Apple's example HID Explorer application does not call HIDCreateOpenDeviceInterface().   
        3) Internally, libHIDUtilities invokes HIDCreateOpenDeviceInterface() itself when HIDBuildDeviceList() is called.
        
        Because the call lies within mysterious conditionals there is some uncertainty about whether HIDCreateOpenDeviceInterface() will always 
        invoke HIDBuildDeviceList().  Therefore, PsychHID verifies that the device interface has been opened before accessing the elements of a device.
        
*/ 
boolean PsychHIDQueryOpenDeviceInterfaceFromDeviceIndex(int deviceIndex)
{
    pRecDevice 			deviceRecord;

    PsychHIDVerifyInit();
    deviceRecord=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
    return(deviceRecord->interface != NULL);    
}
PsychError ReceiveReportsStop(int deviceIndex)
{
	pRecDevice device;

	PsychHIDVerifyInit();
	device = PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	last_hid_device = (hid_device*) device->interface;

	if (device->interface) hid_close((hid_device*) device->interface);
	device->interface = NULL;
    
	return 0;
}
PsychError PSYCHHIDGetDevices(void) 
{
    pRecDevice 			currentDevice=NULL;
    
    const char *deviceFieldNames[]={"usagePageValue", "usageValue", "usageName", "index", "transport", "vendorID", "productID", "version", 
                                    "manufacturer", "product", "serialNumber", "locationID", "totalElements", "features", "inputs", 
                                    "outputs", "collections", "axes", "buttons", "hats", "sliders", "dials", "wheels"};
    int numDeviceStructElements, numDeviceStructFieldNames=23, deviceIndex;
    PsychGenericScriptType	*deviceStruct;		
    char usageName[PSYCH_HID_MAX_DEVICE_ELEMENT_USAGE_NAME_LENGTH];


    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(0));
    PsychHIDVerifyInit();
    numDeviceStructElements=(int)HIDCountDevices();
    PsychAllocOutStructArray(1, FALSE, numDeviceStructElements, numDeviceStructFieldNames, deviceFieldNames, &deviceStruct);
    deviceIndex=0;
    for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){
        PsychSetStructArrayDoubleElement("usagePageValue",	deviceIndex, 	(double)currentDevice->usagePage,	deviceStruct);
        PsychSetStructArrayDoubleElement("usageValue",		deviceIndex, 	(double)currentDevice->usage, 		deviceStruct);
        HIDGetUsageName (currentDevice->usagePage, currentDevice->usage, usageName);
        PsychSetStructArrayStringElement("usageName",		deviceIndex, 	usageName, 				deviceStruct);
        PsychSetStructArrayDoubleElement("index",		deviceIndex, 	(double)deviceIndex+1, 			deviceStruct);
        PsychSetStructArrayStringElement("transport",		deviceIndex, 	currentDevice->transport, 		deviceStruct);
        PsychSetStructArrayDoubleElement("vendorID",		deviceIndex, 	(double)currentDevice->vendorID, 	deviceStruct);
        PsychSetStructArrayDoubleElement("productID",		deviceIndex, 	(double)currentDevice->productID, 	deviceStruct);
        PsychSetStructArrayDoubleElement("version",		deviceIndex, 	(double)currentDevice->version, 	deviceStruct);
        PsychSetStructArrayStringElement("manufacturer",	deviceIndex, 	currentDevice->manufacturer, 		deviceStruct);
        PsychSetStructArrayStringElement("product",		deviceIndex, 	currentDevice->product, 		deviceStruct);
        PsychSetStructArrayStringElement("serialNumber",	deviceIndex, 	currentDevice->serial, 			deviceStruct);
        PsychSetStructArrayDoubleElement("locationID",		deviceIndex, 	(double)currentDevice->locID, 		deviceStruct);
        PsychSetStructArrayDoubleElement("totalElements",	deviceIndex, 	(double)currentDevice->totalElements, 	deviceStruct);
        PsychSetStructArrayDoubleElement("features",		deviceIndex, 	(double)currentDevice->features, 	deviceStruct);
        PsychSetStructArrayDoubleElement("inputs",		deviceIndex, 	(double)currentDevice->inputs, 		deviceStruct);
        PsychSetStructArrayDoubleElement("outputs",		deviceIndex, 	(double)currentDevice->outputs, 	deviceStruct);
        PsychSetStructArrayDoubleElement("collections",		deviceIndex, 	(double)currentDevice->collections, 	deviceStruct);
        PsychSetStructArrayDoubleElement("axes",		deviceIndex, 	(double)currentDevice->axis, 		deviceStruct);
        PsychSetStructArrayDoubleElement("buttons",		deviceIndex, 	(double)currentDevice->buttons, 	deviceStruct);
        PsychSetStructArrayDoubleElement("hats",		deviceIndex, 	(double)currentDevice->hats, 		deviceStruct);
        PsychSetStructArrayDoubleElement("sliders",		deviceIndex, 	(double)currentDevice->sliders, 	deviceStruct);
        PsychSetStructArrayDoubleElement("dials",		deviceIndex, 	(double)currentDevice->dials, 		deviceStruct);
        PsychSetStructArrayDoubleElement("wheels",		deviceIndex, 	(double)currentDevice->wheels, 		deviceStruct);
        ++deviceIndex; 
    }

    return(PsychError_none);	
}
Exemplo n.º 6
0
/* 
    PsychHIDGetDeviceRecordPtrFromIndex()
    
    The inverse of PsychHIDGetIndexFromRecord()
    
    Accept the index from the list of device records and return a pointer to the indicated record.  Externally the list is one-indexed.  
*/
pRecDevice PsychHIDGetDeviceRecordPtrFromIndex(int deviceIndex)
{
    int				i;
    pRecDevice 			currentDevice=NULL;

    PsychHIDVerifyInit();
    i=1;
    for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){    
        if(i==deviceIndex)
            return(currentDevice);
        ++i;
    }
    PsychErrorExitMsg(PsychError_internal, "Invalid device index specified.  Has a device has been unplugged? Try rebuilding the device list");
    return(NULL);  //make the compiler happy.
}
PsychError PSYCHHIDGetNumDevices(void) 
{
    psych_uint32 numDevices;
    
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    	 
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(0));
    
    PsychHIDVerifyInit();
    numDevices=HIDCountDevices();
    PsychCopyOutDoubleArg(1, FALSE, (double)numDevices);
    
    return(PsychError_none);	
}
Exemplo n.º 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;     
        if(currentDevice->usagePage==usagePage && currentDevice->usage==usage){
            deviceRecords[*numDeviceIndices]=currentDevice;
            deviceIndices[*numDeviceIndices]=currentDeviceIndex;  //the array is 0-indexed, devices are 1-indexed.   
            ++(*numDeviceIndices);
        }
    }
}
PsychError ReceiveReportsStop(int deviceIndex)
{
	pRecDevice device;

	PsychHIDVerifyInit();
    
    // Disable HID report reception:
    ready[deviceIndex] = FALSE;

	device = PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	last_hid_device = (hid_device*) device->interface;

	if (device->interface) hid_close((hid_device*) device->interface);
	device->interface = NULL;
    
	return 0;
}
PsychError PsychHIDOSGamePadAxisQuery(int deviceIndex, int axisId, double* min, double* max, double* val, char* axisLabel)
{
    double          elementValue;
    pRecDevice      deviceRecord;
    pRecElement		elementRecord;
    int             elementIndex = axisId;

    PsychHIDVerifyInit();
    deviceRecord= PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
    elementRecord= PsychHIDGetElementRecordFromDeviceRecordAndElementIndex(deviceRecord, elementIndex);
#ifndef __LP64__
    elementValue = (double) HIDGetElementValue(deviceRecord, elementRecord);
#else
    elementValue = IOHIDElement_GetValue(elementRecord, kIOHIDValueScaleTypePhysical);
#endif
    if (val) *val = elementValue;
    return(PsychError_none);
}
Exemplo n.º 11
0
pRecElement PsychHIDGetCollectionRecordFromDeviceRecordAndCollectionIndex(pRecDevice deviceRecord, int elementIndex)
{
    int				i;
    pRecElement			currentElement;

    PsychHIDVerifyInit();
    i=1;
    for(currentElement=HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeCollection); 
        currentElement != NULL; 
        currentElement=HIDGetNextDeviceElement (currentElement, kHIDElementTypeCollection))
    {    
        if(i==elementIndex)
            return(currentElement);
        ++i;
    }
    PsychErrorExitMsg(PsychError_internal, "Invalid collection index specified.  Has a device has been unplugged? Try rebuilding the device list");
    return(NULL);  //make the compiler happy.

}
PsychError PSYCHHIDGiveMeReports(void) 
{
	long error=0;
	int deviceIndex;
	int reportBytes=1024;
	mxArray **outErr;
	pRecDevice device;

    PsychPushHelp(useString,synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    PsychErrorExit(PsychCapNumOutputArgs(2));
    PsychErrorExit(PsychCapNumInputArgs(2));
	PsychCopyInIntegerArg(1,TRUE,&deviceIndex);
	PsychCopyInIntegerArg(2,false,&reportBytes);

	PsychHIDVerifyInit();
    device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	if(!HIDIsValidDevice(device))PrintfExit("PsychHID:GiveMeReports: Invalid device.\n");

	// reports
	error=GiveMeReports(deviceIndex,reportBytes); // PsychHIDReceiveReports.c
	
	// err
	outErr=PsychGetOutArgMxPtr(2); // outErr==NULL if optional argument is absent.
	if(outErr!=NULL){
		const char *fieldNames[]={"n", "name", "description"};
		mxArray *fieldValue;
		char *name="",*description="";

		PsychHIDErrors(error,&name,&description); // Get error name and description, if available.
		*outErr=mxCreateStructMatrix(1,1,3,fieldNames);
		fieldValue=mxCreateString(name);
		mxSetField(*outErr,0,"name",fieldValue);
		fieldValue=mxCreateString(description);
		mxSetField(*outErr,0,"description",fieldValue);
		fieldValue=mxCreateDoubleMatrix(1,1,mxREAL);
		*mxGetPr(fieldValue)=(double)error;
		mxSetField(*outErr,0,"n",fieldValue);
	}
    return(PsychError_none);	
}
Exemplo n.º 13
0
/*
    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);
            }
        }
    }
}
Exemplo n.º 14
0
PsychError PsychHIDOSKbCheck(int deviceIndex, double* scanList)
{
    pRecDevice			deviceRecord;
    pRecElement			currentElement, lastElement = NULL;
    int					i, debuglevel = 0;
    static int			numDeviceIndices = -1;
    int					numDeviceUsages=NUMDEVICEUSAGES;
	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};
    static int			deviceIndices[PSYCH_HID_MAX_KEYBOARD_DEVICES]; 
    static pRecDevice	deviceRecords[PSYCH_HID_MAX_KEYBOARD_DEVICES];
    psych_bool			isDeviceSpecified, foundUserSpecifiedDevice;
    double				*timeValueOutput, *isKeyDownOutput, *keyArrayOutput;
    int					m, n, p, nout;
    double				dummyKeyDown;
    double				dummykeyArrayOutput[256];
    uint32_t            usage, usagePage;
    int                 value;

    // We query keyboard and keypad devices only on first invocation, then cache and recycle the data:
    if (numDeviceIndices == -1) {
        PsychHIDVerifyInit();
        PsychHIDGetDeviceListByUsages(numDeviceUsages, KbDeviceUsagePages, KbDeviceUsages, &numDeviceIndices, deviceIndices, deviceRecords);
    }
	
    // Choose the device index and its record
    isDeviceSpecified = (deviceIndex != INT_MAX);
    if(isDeviceSpecified){  //make sure that the device number provided by the user is really a keyboard or keypad.
        if (deviceIndex < 0) {
            debuglevel = 1;
            deviceIndex = -deviceIndex;
        }

        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]; 

    // Allocate and init out return arguments.

    // Either alloc out the arguments, or redirect to
    // internal dummy variables. This to avoid mxMalloc() call overhead
    // inside the PsychAllocOutXXX() routines:
    nout = PsychGetNumNamedOutputArgs();

    // keyDown flag:
    if (nout >= 1) {
       PsychAllocOutDoubleArg(1, FALSE, &isKeyDownOutput);
    } else {
       isKeyDownOutput = &dummyKeyDown;
    }
    *isKeyDownOutput= (double) FALSE;

    // key state vector:
    if (nout >= 3) {
        PsychAllocOutDoubleMatArg(3, FALSE, 1, 256, 1, &keyArrayOutput);
    }
    else {
        keyArrayOutput = &dummykeyArrayOutput[0];
    }
    memset((void*) keyArrayOutput, 0, sizeof(double) * 256);

    // Query timestamp:
    if (nout >= 2) {
        PsychAllocOutDoubleArg(2, FALSE, &timeValueOutput);

        // Get query timestamp:
        PsychGetPrecisionTimerSeconds(timeValueOutput);
    }

    // Make sure our keyboard query mechanism is not blocked for security reasons, e.g.,
    // secure password entry field active in another process, i.e., EnableSecureEventInput() active.
    if (PsychHIDWarnInputDisabled("PsychHID('KbCheck')")) return(PsychError_none);

    //step through the elements of the device.  Set flags in the return array for down keys.
    for(currentElement=HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeInput | kHIDElementTypeCollection); 
        (currentElement != NULL) && (currentElement != lastElement);
        currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput | kHIDElementTypeCollection))
    {
        // Keep track of last queried element:
        lastElement = currentElement;
        
        #ifndef __LP64__
        usage = currentElement->usage;
        usagePage = currentElement->usagePage;
        #else
        usage = IOHIDElementGetUsage(currentElement);
        usagePage = IOHIDElementGetUsagePage(currentElement);
        // printf("PTB-DEBUG: [KbCheck]: ce %p page %d usage: %d isArray: %d\n", currentElement, usagePage, usage, IOHIDElementIsArray(currentElement));

        if (IOHIDElementGetType(currentElement) == kIOHIDElementTypeCollection) {
            CFArrayRef children = IOHIDElementGetChildren(currentElement);
            if (!children) continue;
            
            CFIndex idx, cnt = CFArrayGetCount(children);
            for ( idx = 0; idx < cnt; idx++ ) {
                IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(children, idx);
                if (tIOHIDElementRef && ((IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_Button) ||
                                         (IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_ScanCodes))) {
                    usage = IOHIDElementGetUsage(tIOHIDElementRef);
                    if ((usage <= 256) && (usage >= 1) && ( (scanList == NULL) || (scanList[usage - 1] > 0) )) {
                        value = (int) IOHIDElement_GetValue(tIOHIDElementRef, kIOHIDValueScaleTypePhysical);
                        if (debuglevel > 0) printf("PTB-DEBUG: [KbCheck]: usage: %x value: %d \n", usage, value);
                        keyArrayOutput[usage - 1] = (value || (int) keyArrayOutput[usage - 1]);
                        *isKeyDownOutput = keyArrayOutput[usage - 1] || *isKeyDownOutput;
                    }
                }
            }
            
            // Done with this currentElement, which was a collection of buttons/keys.
            // Iterate to next currentElement:
            continue;
        }
        #endif

        // Classic path, or 64-Bit path for non-collection elements:
        if(((usagePage == kHIDPage_KeyboardOrKeypad) || (usagePage == kHIDPage_Button)) && (usage <= 256) && (usage >= 1) &&
			( (scanList == NULL) || (scanList[usage - 1] > 0) ) ) {
            #ifndef __LP64__
            value = (int) HIDGetElementValue(deviceRecord, currentElement);
            #else
            value = (int) IOHIDElement_GetValue(currentElement, kIOHIDValueScaleTypePhysical);
            #endif

            if (debuglevel > 0) printf("PTB-DEBUG: [KbCheck]: usage: %x value: %d \n", usage, value);
            keyArrayOutput[usage - 1]=(value || (int) keyArrayOutput[usage - 1]);
            *isKeyDownOutput= keyArrayOutput[usage - 1] || *isKeyDownOutput; 
        }
    }

    return(PsychError_none);	
}
PsychError PSYCHHIDGetCollections(void) 
{
    pRecDevice 			specDevice=NULL;
    UInt32                      numDeviceElements;
    
    const char 			*elementFieldNames[]={"typeMaskName", "name", "deviceIndex", "collectionIndex", "typeValue", "typeName", "usagePageValue",
                                                        "usageValue", "usageName", "memberCollectionIndices", "memberElementIndices"};
    int 			i, numElementStructElements, numElementStructFieldNames=11, elementIndex, deviceIndex;
    PsychGenericScriptType	*elementStruct, *memberCollectionIndicesMat, *memberIOElementIndicesMat;	
    pRecElement			currentElement;
    char			elementTypeName[PSYCH_HID_MAX_DEVICE_ELEMENT_TYPE_NAME_LENGTH];	
    char			usageName[PSYCH_HID_MAX_DEVICE_ELEMENT_USAGE_NAME_LENGTH];
    char			*typeMaskName;
    HIDElementTypeMask		typeMask;
    pRecElement			*memberCollectionRecords, *memberIOElementRecords;     
    double			*memberCollectionIndices, *memberIOElementIndices; 
    int				numSubCollections, numSubIOElements;
    
    	 
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
        
    PsychCopyInIntegerArg(1, TRUE, &deviceIndex);
    PsychHIDVerifyInit();
    specDevice= PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
    PsychHIDVerifyOpenDeviceInterfaceFromDeviceRecordPtr(specDevice);
    numDeviceElements= HIDCountDeviceElements(specDevice, kHIDElementTypeCollection);
    numElementStructElements = (int)numDeviceElements;
    PsychAllocOutStructArray(1, FALSE, numElementStructElements, numElementStructFieldNames, elementFieldNames, &elementStruct);
    elementIndex=0;
    for(currentElement=HIDGetFirstDeviceElement(specDevice,kHIDElementTypeCollection); 
        currentElement != NULL; 
        currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeCollection))
        {
        typeMask=HIDConvertElementTypeToMask (currentElement->type);
 	PsychHIDGetTypeMaskStringFromTypeMask(typeMask, &typeMaskName);
        PsychSetStructArrayStringElement("typeMaskName",	elementIndex, 	typeMaskName,	 			elementStruct);
        PsychSetStructArrayStringElement("name",		elementIndex, 	currentElement->name,	 		elementStruct);
        PsychSetStructArrayDoubleElement("deviceIndex",		elementIndex, 	(double)deviceIndex, 			elementStruct);
        PsychSetStructArrayDoubleElement("collectionIndex",	elementIndex, 	(double)elementIndex+1, 		elementStruct);
        PsychSetStructArrayDoubleElement("typeValue",		elementIndex, 	(double)currentElement->type, 		elementStruct);
        HIDGetTypeName(currentElement->type, elementTypeName);
        PsychSetStructArrayStringElement("typeName",		elementIndex, 	elementTypeName,	 		elementStruct);
        PsychSetStructArrayDoubleElement("usagePageValue",	elementIndex, 	(double)currentElement->usagePage, 	elementStruct);
        PsychSetStructArrayDoubleElement("usageValue",		elementIndex, 	(double)currentElement->usage, 		elementStruct);
        HIDGetUsageName (currentElement->usagePage, currentElement->usage, usageName);
        PsychSetStructArrayStringElement("usageName",		elementIndex, 	usageName,	 			elementStruct);
                          
        //find and return the indices of this collection's member collections and indices
        numSubCollections=PsychHIDCountCollectionElements(currentElement, kHIDElementTypeCollection);
        numSubIOElements=PsychHIDCountCollectionElements(currentElement, kHIDElementTypeIO);
        memberCollectionRecords=(pRecElement*)PsychMallocTemp(sizeof(pRecElement) * numSubCollections);
        memberIOElementRecords=(pRecElement*)PsychMallocTemp(sizeof(pRecElement) * numSubIOElements);
        PsychHIDFindCollectionElements(currentElement, kHIDElementTypeCollection, memberCollectionRecords, numSubCollections);
        PsychHIDFindCollectionElements(currentElement, kHIDElementTypeIO, memberIOElementRecords, numSubIOElements);
        memberCollectionIndices=NULL;
        PsychAllocateNativeDoubleMat(1, numSubCollections, 1, &memberCollectionIndices, &memberCollectionIndicesMat);
        memberIOElementIndices=NULL;
        PsychAllocateNativeDoubleMat(1, numSubIOElements, 1, &memberIOElementIndices, &memberIOElementIndicesMat);
        
        for(i=0;i<numSubCollections;i++)
            memberCollectionIndices[i]=PsychHIDGetIndexFromRecord(specDevice, memberCollectionRecords[i], kHIDElementTypeCollection);
        for(i=0;i<numSubIOElements;i++)
            memberIOElementIndices[i]=PsychHIDGetIndexFromRecord(specDevice, memberIOElementRecords[i], kHIDElementTypeIO);
        PsychFreeTemp(memberCollectionRecords);
        PsychFreeTemp(memberIOElementRecords);
        PsychSetStructArrayNativeElement("memberCollectionIndices", 	elementIndex,	memberCollectionIndicesMat,	elementStruct);
        PsychSetStructArrayNativeElement("memberElementIndices", 	elementIndex,	memberIOElementIndicesMat,	elementStruct);

        ++elementIndex; 
    }

    return(PsychError_none);	
}
/* Do all the report processing for all devices: Iterates in a fetch loop
 * until error condition, or a maximum allowable processing time of
 * optionSecs seconds has been exceeded.
 *
 * Calls hidlib function hid_read() to get reports, one at a time, enqueues
 * it in our own reports lists for later retrieval by 'GiveMeReports' or
 * 'GiveMeReport'.
 *
 */
PsychError ReceiveReports(int deviceIndex)
{
    int rateLimit[MAXDEVICEINDEXS] = { 0 };
    double deadline, now;
    pRecDevice device;
    int n, m;
    unsigned int i;
    ReportStruct *r;
    long error = 0;

    PsychHIDVerifyInit();

    if(deviceIndex < 0 || deviceIndex >= MAXDEVICEINDEXS) PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex, (int) MAXDEVICEINDEXS-1);

    // Allocate report buffers if needed:
    PsychHIDAllocateReports(deviceIndex);

    CountReports("ReceiveReports beginning.");
    if (freeReportsPtr[deviceIndex] == NULL) PrintfExit("No free reports.");

    // Enable this device for hid report reception:
    ready[deviceIndex] = TRUE;

    PsychGetAdjustedPrecisionTimerSeconds(&now);
    deadline = now + optionsSecs;
    
    // Iterate until deadline reached or no more pending reports to process:
    while ((error == 0) && (now <= deadline)) {
        // Iterate over all active devices:
        for (deviceIndex = 0; deviceIndex < MAXDEVICEINDEXS; deviceIndex++) {            
            // Test for timeout:
            PsychGetAdjustedPrecisionTimerSeconds(&now);
            if (now > deadline) break;

            // Skip this device if it isn't enabled to receive hid reports:
            if (!ready[deviceIndex]) continue;
            
            // Free target report buffers?
            if(freeReportsPtr[deviceIndex] == NULL) {
                // Darn. We're full. It might be elegant to discard oldest report, but for now, we'll just ignore the new one.
                if (!rateLimit[deviceIndex]) printf("PsychHID: WARNING! ReportCallback warning. No more free reports for deviceIndex %i. Discarding new report.\n", deviceIndex);
                rateLimit[deviceIndex] = 1;
                continue;
            }
            
            // Handle one report for this device:
            CountReports("ReportCallback beginning.");

            device = PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
            last_hid_device = (hid_device*) device->interface;

            // Get a report struct to fill in:
            r = freeReportsPtr[deviceIndex];

            // Fetch the actual data: Bytes fetched, or zero for no reports available, or
            // -1 for error condition.
            r->error = hid_read((hid_device*) device->interface, &(r->report[0]), MaxDeviceReportSize[deviceIndex]);

            // Skip remainder if no data received:
            if (r->error == 0) continue;

            // Ok, we got something, even if it is only an error code. Need
            // to move the (r)eport from the free list to the received list:
            freeReportsPtr[deviceIndex] = r->next;
            r->next=NULL;
            
            // install report into the device's list.
            r->next = deviceReportsPtr[deviceIndex];
            deviceReportsPtr[deviceIndex] = r;
            
            // fill in the rest of the report struct
            r->deviceIndex = deviceIndex;
            
            // Timestamp processing:
            PsychGetPrecisionTimerSeconds(&r->time);

            // Success or error?
            if (r->error > 0) {
                // Success: Reset error, assign size of retrieved report:
                r->bytes = r->error;
                r->error = 0;
            }
            else {
                // Error: No data assigned.
                r->bytes = 0;
                
                // Signal error return code -1:
                error = -1;
                
                // Abort fetch loop:
                break;
            }

            if (optionsPrintReportSummary) {
                // print diagnostic summary of the report
                int serial;
                
                serial = r->report[62] + 256 * r->report[63]; // 32-bit serial number at end of AInScan report from PMD-1208FS
                printf("Got input report %4d: %2ld bytes, dev. %d, %4.0f ms. ", serial, (long) r->bytes, deviceIndex, 1000 * (r->time - AInScanStart));
                if(r->bytes>0) {
                    printf(" report ");
                    n = r->bytes;
                    if (n > 6) n=6;
                    for(i=0; i < (unsigned int) n; i++) printf("%3d ", (int) r->report[i]);
                    m = r->bytes - 2;
                    if (m > (int) i) {
                        printf("... ");
                        i = m;
                    }
                    for(; i < r->bytes; i++) printf("%3d ", (int) r->report[i]);
                }
                printf("\n");
            }
            CountReports("ReportCallback end.");
        }
    }
    
    CountReports("ReceiveReports end.");
    return error;
}
Exemplo n.º 17
0
boolean PsychHIDQueryOpenDeviceInterfaceFromDeviceRecordPtr(pRecDevice deviceRecord)
{
    PsychHIDVerifyInit();
    return(deviceRecord->interface != NULL);
}
Exemplo n.º 18
0
/*
        PsychHIDQueryOpenDeviceInterfaceFromDeviceIndex()

        Check the interface field of the libHIDUtilities device structure for NULLness.  libHIDUtilities.h seems to indicate that it is neccessary for application
        to invoke HIDCreateOpenDeviceInterface() before accessing a device.  However,
        1) libHIDUtilities provides no way to obtain a value for the required first argument to HIDCreateOpenDeviceInterface().  
        2) Apple's example HID Explorer application does not call HIDCreateOpenDeviceInterface().   
        3) Internally, libHIDUtilities invokes HIDCreateOpenDeviceInterface() itself when HIDBuildDeviceList() is called.
        
        Because the call lies within mysterious conditionals there is some uncertainty about whether HIDCreateOpenDeviceInterface() will always 
        invoke HIDBuildDeviceList().  Therefore, PsychHID verifies that the device interface has been opened before accessing the elements of a device.
        
*/ 
psych_bool PsychHIDQueryOpenDeviceInterfaceFromDeviceIndex(int deviceIndex)
{
    PsychHIDVerifyInit();
    return(PsychHIDGetDeviceInterfacePtrFromIndex(deviceIndex) != NULL);
}
Exemplo n.º 19
0
PsychError PSYCHHIDSetReport(void) 
{
	long error;
	pRecDevice device;
	int deviceIndex;
	int reportType; // kIOHIDReportTypeInput=0, kIOHIDReportTypeOutput=1, or kIOHIDReportTypeFeature=2
	int reportID;
	unsigned char *reportBuffer;
	int reportSize;
	const mxArray *report;
	mxArray **outErr;
	int i;
	
    PsychPushHelp(useString,synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(4));
	outErr=PsychGetOutArgMxPtr(1);
	assert(outErr!=NULL);
	PsychCopyInIntegerArg(1,TRUE,&deviceIndex);
	PsychCopyInIntegerArg(2,TRUE,&reportType);
	PsychCopyInIntegerArg(3,TRUE,&reportID);
	report=PsychGetInArgMxPtr(4); 
	reportBuffer=(void *)mxGetPr(report);
	assert(reportBuffer!=NULL);
	switch(mxGetClassID(report)){
		case mxCHAR_CLASS:    
		case mxINT8_CLASS: 
		case mxUINT8_CLASS:   
		case mxINT16_CLASS:  
		case mxUINT16_CLASS:  
		case mxINT32_CLASS:  
		case mxUINT32_CLASS: 
			break;
		default:
			PrintfExit("\"report\" array must be char or integer (8-, 16-, or 32-bit).");
			break;
	}
	reportSize=mxGetElementSize(report)*mxGetNumberOfElements(report);
	PsychHIDVerifyInit();
    device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	if(reportSize>0 && reportID!=0) *reportBuffer=0xff&reportID; // copy low byte of reportID to first byte of report.
																 // Apple defines constants for the reportType with values (0,1,2) that are one less that those specified by USB (1,2,3).
	assert(kIOHIDReportTypeInput==0 && kIOHIDReportTypeOutput==1 && kIOHIDReportTypeFeature==2);
	if(reportType==0){
		printf("SetReport(reportType %d, reportID %d, report ",reportType,reportID);
		for(i=0;i<reportSize;i++)printf("%d ",(int)reportBuffer[i]);
		printf(")\n");
		error=0;
	}else{
		if(1){
			IOHIDDeviceInterface122 **interface;
			interface=(IOHIDDeviceInterface122 **)(device->interface);
			if(interface)error=(*interface)->setReport(interface,reportType-1,reportID,reportBuffer,(UInt32)reportSize,50,NULL,NULL,NULL);
			else PrintfExit("PsychHID SetReport: Bad interface.\n");
		}else error=HIDSetReport(device,reportType-1,reportID,reportBuffer,(UInt32)reportSize);
	}
	if(reportID==0x11){
		PsychGetPrecisionTimerSeconds(&AInScanStart);
	}
	//if(error)printf("Warning: PsychHID: HIDSetReport error %ld (0x%lx).",error,error);
	if(0){
		*outErr=mxCreateDoubleMatrix(1,1,mxREAL);
		if(*outErr==NULL)PrintfExit("Couldn't allocate \"err\".");
		*mxGetPr(*outErr)=(double)error;
	}else{
		const char *fieldNames[]={"n", "name", "description"};
		char *name="",*description="";
		mxArray *fieldValue;
		
		PsychHIDErrors(error,&name,&description);
		*outErr=mxCreateStructMatrix(1,1,3,fieldNames);
		fieldValue=mxCreateString(name);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		mxSetField(*outErr,0,"name",fieldValue);
		fieldValue=mxCreateString(description);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		mxSetField(*outErr,0,"description",fieldValue);
		fieldValue=mxCreateDoubleMatrix(1,1,mxREAL);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		*mxGetPr(fieldValue)=(double)error;
		mxSetField(*outErr,0,"n",fieldValue);
	}		
    return(PsychError_none);	
}
Exemplo n.º 20
0
PsychError PSYCHHIDGetReport(void) 
{
	long error=0;
	pRecDevice device;
	int deviceIndex;
	int reportType; // 1=input, 2=output, 3=feature
	unsigned char *reportBuffer;
	UInt32 reportBytes=0;
	int reportBufferSize=0;
	int reportID=0;
	long dims[]={1,1};
	mxArray **outReport,**outErr;
	char *name="",*description="",string[256];
	IOHIDDeviceInterface122** interface=NULL;
	boolean reportAvailable;
	double reportTime;

    PsychPushHelp(useString,synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    PsychErrorExit(PsychCapNumOutputArgs(2));
    PsychErrorExit(PsychCapNumInputArgs(4));
	PsychCopyInIntegerArg(1,TRUE,&deviceIndex);
	PsychCopyInIntegerArg(2,TRUE,&reportType);
	PsychCopyInIntegerArg(3,TRUE,&reportID);
	PsychCopyInIntegerArg(4,TRUE,&reportBufferSize);
	outReport=PsychGetOutArgMxPtr(1); 
	outErr=PsychGetOutArgMxPtr(2); // outErr==NULL if optional argument is absent.
	dims[0]=1;
	dims[1]=reportBufferSize;
	*outReport=mxCreateNumericArray(2,(void *)dims,mxUINT8_CLASS,mxREAL);
	if(*outReport==NULL)PrintfExit("Couldn't allocate report array.");
	reportBuffer=(void *)mxGetData(*outReport);
	if(reportBuffer==NULL)PrintfExit("Couldn't allocate report buffer.");
	reportBytes=reportBufferSize;
	PsychHIDVerifyInit();
    device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	if(!HIDIsValidDevice(device))PrintfExit("PsychHID:GetReport: Invalid device.\n");
	interface=device->interface;
	if(interface==NULL)PrintfExit("PsychHID:GetReport: No interface for device.\n");
	if(reportType==0){
		printf("GetReport(reportType %d, reportID %d, reportBytes %d)\n",reportType,reportID,(int)reportBytes);
	}else{
		// Apple defines constants for the reportType with values (0,1,2) that are one less that those specified by USB (1,2,3).
		if(0){
			// HIDGetReport
			error=HIDGetReport(device,reportType-1,reportID,reportBuffer,&reportBytes);
		}
		if(0){
			// getReport
			error=(*interface)->getReport(interface,reportType-1,reportID,reportBuffer,&reportBytes,-1,nil,nil,nil);
		}
		if(0){
			// handleReport
		}
		if(1){
			// using setInterruptReportHandlerCallback and CFRunLoopRunInMode
			error=ReceiveReports(deviceIndex);
			error=GiveMeReport(deviceIndex,&reportAvailable,reportBuffer,&reportBytes,&reportTime);
		}else{
			// using getReport
			if(error==0)reportAvailable=1;
			PsychGetPrecisionTimerSeconds(&reportTime);
		}
	}
	if(outReport==NULL)PrintfExit("Output argument is required."); // I think MATLAB always provides this.
	if(error==0 && reportBytes>reportBufferSize){
		error=2;
		name="Warning";
		description=string;
		sprintf(description,"GetReport overflow. Expected %ld but received %ld bytes.",(long)reportBufferSize,(long)reportBytes); 
	}
	if(error==0 && reportBytes<reportBufferSize){
		// Reduce the declared size of the array to that of the received report.
		if(reportBytes>0)error=3;
		name="Warning";
		description=string;
		sprintf(description,"GetReport expected %ld but received %ld bytes.",(long)reportBufferSize,(long)reportBytes);
		mxSetN(*outReport,reportBytes);
	}
	if(outErr!=NULL){
		const char *fieldNames[]={"n", "name", "description", "reportLength", "reportTime"};
		mxArray *fieldValue;

		PsychHIDErrors(error,&name,&description); // Get error name and description, if available.
		*outErr=mxCreateStructMatrix(1,1,5,fieldNames);
		fieldValue=mxCreateString(name);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		mxSetField(*outErr,0,"name",fieldValue);
		fieldValue=mxCreateString(description);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		mxSetField(*outErr,0,"description",fieldValue);
		fieldValue=mxCreateDoubleMatrix(1,1,mxREAL);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		*mxGetPr(fieldValue)=(double)error;
		mxSetField(*outErr,0,"n",fieldValue);
		fieldValue=mxCreateDoubleMatrix(1,1,mxREAL);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		if(reportAvailable)*mxGetPr(fieldValue)=(double)reportBytes;
		else *mxGetPr(fieldValue)=-1.0;
		mxSetField(*outErr,0,"reportLength",fieldValue);
		fieldValue=mxCreateDoubleMatrix(1,1,mxREAL);
		if(fieldValue==NULL)PrintfExit("Couldn't allocate \"err\".");
		*mxGetPr(fieldValue)=reportTime;
		mxSetField(*outErr,0,"reportTime",fieldValue);
	}
    return(PsychError_none);	
}
/* Do all the report processing: Iterates in a fetch loop
 * until either no more reports pending for processing, error condition,
 * or a maximum allowable processing time of optionSecs seconds has been
 * exceeded.
 *
 * Calls hidlib function hid_read() to get reports, one at a time, enqueues
 * it in our own reports lists for later retrieval by 'GiveMeReports' or
 * 'GiveMeReport'.
 *
 */
PsychError ReceiveReports(int deviceIndex)
{
    double deadline, now;

    pRecDevice device;
    int n, m;
    unsigned int i;
    ReportStruct *r;
    long error = 0;

    CountReports("ReceiveReports beginning.");
    if(freeReportsPtr==NULL) PrintfExit("No free reports.");

    if(deviceIndex < 0 || deviceIndex > MAXDEVICEINDEXS-1) PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex, (int) MAXDEVICEINDEXS-1);

    PsychHIDVerifyInit();
    device = PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
    last_hid_device = (hid_device*) device->interface;
    
    PsychGetAdjustedPrecisionTimerSeconds(&deadline);
    deadline += optionsSecs;
    
    // Iterate until deadline reached or no more pending reports to process:
    while (TRUE) {
        // Test for timeout:
        PsychGetAdjustedPrecisionTimerSeconds(&now);
        if (now >= deadline) break;
                
        CountReports("ReportCallback beginning.");
        
        // take report from free list.
        if(freeReportsPtr == NULL){
            // Darn. We're full. It might be elegant to discard oldest report, but for now, we'll just ignore the new one.
            printf("PsychHID: WARNING! ReportCallback warning. No more free reports. Discarding new report.\n");
            break;
        }
        
        r = freeReportsPtr;
        freeReportsPtr = r->next;
        r->next=NULL;
        
        // install report into the device's list.
        r->next = deviceReportsPtr[deviceIndex];
        deviceReportsPtr[deviceIndex] = r;
        
        // fill in the rest of the report struct
        r->deviceIndex = deviceIndex;

        // Fetch the actual data: Bytes fetched, or zero for no reports available, or
        // -1 for error condition.
        r->error = hid_read((hid_device*) device->interface, &(r->report[0]), MAXREPORTSIZE);
        if (r->error >= 0) {
            // Success: Reset error, assign size of retrieved report:
            r->bytes = r->error;
            r->error = 0;
        }
        else {
            // Error: No data assigned.
            r->bytes = 0;
            
            // Signal error return code -1:
            error = -1;
            
            // Abort fetch loop:
            break;
        }
        
        // Timestamp processing:
        PsychGetPrecisionTimerSeconds(&r->time);

        if (optionsPrintReportSummary) {
            // print diagnostic summary of the report
            int serial;
            
            serial = r->report[62] + 256 * r->report[63]; // 32-bit serial number at end of AInScan report from PMD-1208FS
            printf("Got input report %4d: %2ld bytes, dev. %d, %4.0f ms. ", serial, (long) r->bytes, deviceIndex, 1000 * (r->time - AInScanStart));
            if(r->bytes>0) {
                printf(" report ");
                n = r->bytes;
                if (n > 6) n=6;
                for(i=0; i < (unsigned int) n; i++) printf("%3d ", (int) r->report[i]);
                m = r->bytes - 2;
                if (m > (int) i) {
                    printf("... ");
                    i = m;
                }
                for(; i < r->bytes; i++) printf("%3d ", (int) r->report[i]);
            }
            printf("\n");
        }
        CountReports("ReportCallback end.");
        
        // If no data has been returned then we're done for now:
        if (r->bytes == 0) break;
    }
    
	CountReports("ReceiveReports end.");
	return error;
}
PsychError PSYCHHIDKbTriggerWait(void) 
{
    pRecDevice	deviceRecord;
    int			i, deviceIndex, numDeviceIndices;
    long		KeysUsagePage=0x07;									// This is the keyboard usage page
	long		KeysUsage;											// This will contain the key code of the trigger key
    long		KbDeviceUsagePages[NUMDEVICEUSAGES]= {0x01,0x01}, KbDeviceUsages[NUMDEVICEUSAGES]={0x06,0x07}; // Generic Desktop page (0x01), keyboard (0x06), keypad (0x07)
    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;

    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(2));  	//Specify trigger key code and the deviceNumber of the keyboard or keypad to scan.  
    
    PsychHIDVerifyInit();
	
	if(hidDataRef!=NULL) PsychErrorExitMsg(PsychError_user, "A queue is already running, you must call KbQueueRelease() before invoking KbTriggerWait.");
	
	//Identify the trigger
	{
		int KeysUsageInteger;
		if(!PsychCopyInIntegerArg(1, TRUE, &KeysUsageInteger)){
			PsychErrorExitMsg(PsychError_user, "Keycode is required.");
		}
		KeysUsage=KeysUsageInteger;
	}
	
    //Choose the device index and its record
    PsychHIDGetDeviceListByUsages(numDeviceUsages, KbDeviceUsagePages, KbDeviceUsages, &numDeviceIndices, deviceIndices, deviceRecords);  
    isDeviceSpecified=PsychCopyInIntegerArg(2, FALSE, &deviceIndex);
    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]; 
    
    //Allocate and init out return arguments.
    PsychAllocOutDoubleArg(1, FALSE, &timeValueOutput);
	if(!timeValueOutput)
		PsychErrorExitMsg(PsychError_system, "Failed to allocate memory for output.");
		
	interface=deviceRecord->interface;
	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;
		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.");
			}
		}
		{
			// 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.");
			}
			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
	
    // PsychGetPrecisionTimerSeconds(timeValueOutput);		// Less precise strategy than using event.timestamp
        
    return(PsychError_none);	
}
PsychError ReceiveReports(int deviceIndex)
{
	long error=0;
	pRecDevice device;
	IOHIDDeviceInterface122** interface=NULL;
	int reason; // kCFRunLoopRunFinished, kCFRunLoopRunStopped, kCFRunLoopRunTimedOut, kCFRunLoopRunHandledSource

	CountReports("ReceiveReports beginning.");
	if(freeReportsPtr==NULL)PrintfExit("No free reports.");

	PsychHIDVerifyInit();
	device=PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
	if(!HIDIsValidDevice(device))PrintfExit("PsychHID: Invalid device.\n");
	interface=device->interface;
	if(interface==NULL)PrintfExit("PsychHID: No interface for device.\n");
	if(deviceIndex<0 || deviceIndex>MAXDEVICEINDEXS-1)PrintfExit("Sorry. Can't cope with deviceNumber %d (more than %d). Please tell [email protected]",deviceIndex,(int)MAXDEVICEINDEXS-1);
	CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__);
	if(!ready[deviceIndex]){
		// setInterruptReportHandlerCallback
		static unsigned char buffer[MAXREPORTSIZE];
		psych_uint32 bufferSize=MAXREPORTSIZE;
		psych_bool createSource;

		createSource=(source[deviceIndex]==NULL);
		if(createSource){
			if(optionsPrintCrashers && createSource)printf("%d: createAsyncEventSource\n",deviceIndex);
			error=(*interface)->createAsyncEventSource(interface,&(source[deviceIndex]));
			if(error)PrintfExit("ReceiveReports - createAsyncEventSource error 0x%lx.",error);
			if(0 && optionsPrintCrashers && createSource)
				printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
					   ,CFRunLoopSourceIsValid(source[deviceIndex])
					   ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		}
		if(optionsPrintCrashers && createSource)printf("%d: getAsyncEventSource\n",deviceIndex);
		CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__);
		if(optionsPrintCrashers && createSource)printf("%d: CFRunLoopAddSource\n",deviceIndex);
		CFRunLoopAddSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode);
		if(0 && optionsPrintCrashers && createSource)printf("%d: source %4.4lx validity %d, CFRunLoopContainsSource is %d.\n",deviceIndex,(unsigned long)source[deviceIndex]
			   ,CFRunLoopSourceIsValid(source[deviceIndex])
			   ,CFRunLoopContainsSource(CFRunLoopGetCurrent(),source[deviceIndex],myRunLoopMode));
		ready[deviceIndex]=1;
		CheckRunLoopSource(deviceIndex,"ReceiveReports",__LINE__);
		if(optionsPrintCrashers && createSource)printf("%d: setInterruptReportHandlerCallback\n",deviceIndex);
		error=(*interface)->setInterruptReportHandlerCallback(interface,buffer,bufferSize,ReportCallback,buffer,(void *)deviceIndex);
		if(error)PrintfExit("ReceiveReports - setInterruptReportHandlerCallback error 0x%lx.",error);
		if(optionsPrintCrashers && createSource)printf("%d: CFRunLoopRunInMode.\n",deviceIndex);
	}
	//printf("%d: CFRunLoopRunInMode\n",deviceIndex);
	reason=CFRunLoopRunInMode(myRunLoopMode,optionsSecs,false);
	if(reason!=kCFRunLoopRunTimedOut && reason!=kCFRunLoopRunHandledSource){
		char *s;
		switch(reason){
			case kCFRunLoopRunFinished: s="kCFRunLoopRunFinished"; break;
			case kCFRunLoopRunStopped: s="kCFRunLoopRunStopped"; break;
			case kCFRunLoopRunTimedOut: s="kCFRunLoopRunTimedOut"; break;
			case kCFRunLoopRunHandledSource: s="kCFRunLoopRunHandledSource"; break;
			default: s="of unknown reason.";
		}
		printf("RunLoop ended at %.3f s because %s.\n",CFAbsoluteTimeGetCurrent()-AInScanStart,s);			
	}
	CountReports("ReceiveReports end.");
	return error;
}
Exemplo n.º 24
0
PsychError PSYCHHIDKbCheck(void) 
{
    pRecDevice          	deviceRecord;
    pRecElement			currentElement;
    int				i, deviceIndex, numDeviceIndices;
    long			KeysUsagePage=7;
    long			KbDeviceUsagePage= 1, KbDeviceUsage=6; 
    int				deviceIndices[PSYCH_HID_MAX_KEYBOARD_DEVICES]; 
    pRecDevice			deviceRecords[PSYCH_HID_MAX_KEYBOARD_DEVICES];
    boolean 			isDeviceSpecified, foundUserSpecifiedDevice, isKeyArgPresent, isTimeArgPresent;
    double			*timeValueOutput, *isKeyDownOutput;
    PsychNativeBooleanType	*keyArrayOutput;
    	 

    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(3));
    PsychErrorExit(PsychCapNumInputArgs(1));  	//Specifies the number of the keyboard to scan.  
    
    PsychHIDVerifyInit();
    
    //Choose the device index and its record
    PsychHIDGetDeviceListByUsage(KbDeviceUsagePage, KbDeviceUsage, &numDeviceIndices, deviceIndices, deviceRecords);  
    isDeviceSpecified=PsychCopyInIntegerArg(1, FALSE, &deviceIndex);
    if(isDeviceSpecified){  //make sure that the device number provided by the user is really a keyboard.
        for(i=0;i<numDeviceIndices;i++){
            if(foundUserSpecifiedDevice=(deviceIndices[i]==deviceIndex))
                break;
        }
        if(!foundUserSpecifiedDevice)
            PsychErrorExitMsg(PsychError_user, "Specified device number is not a keyboard device.");
    }else{ // set the keyboard device to be the first keyboard device
        i=0;
        if(numDeviceIndices==0)
            PsychErrorExitMsg(PsychError_user, "No keyboard devices detected.");
        else{
            deviceIndex=deviceIndices[i];
        }
    }
    deviceRecord=deviceRecords[i]; 
    
    //Allocate and init out return arguments.  
    isKeyArgPresent = PsychAllocOutBooleanMatArg(3, FALSE, 1, 256, 1, &keyArrayOutput);
    isTimeArgPresent = PsychAllocOutDoubleArg(2, FALSE, &timeValueOutput);
    PsychGetPrecisionTimerSeconds(timeValueOutput);
    PsychAllocOutDoubleArg(1, FALSE, &isKeyDownOutput);
    *isKeyDownOutput=(double)FALSE;
        
    //step through the elements of the device.  Set flags in the return array for down keys.

    for(currentElement=HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeInput); 
        currentElement != NULL; 
        currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput))
    {
        if(currentElement->usagePage==KeysUsagePage && currentElement->usage <= 256 && currentElement->usage >=1){
            //printf("usage: %x value: %d \n", currentElement->usage, HIDGetElementValue(deviceRecord, currentElement));
            keyArrayOutput[currentElement->usage - 1]=(PsychNativeBooleanType)(HIDGetElementValue(deviceRecord, currentElement) || keyArrayOutput[currentElement->usage - 1]);
            *isKeyDownOutput= keyArrayOutput[currentElement->usage - 1] || *isKeyDownOutput; 
        }
    }
        
        
    return(PsychError_none);	
}
PsychError PSYCHHIDGetElements(void) 
{
    pRecDevice 			specDevice=NULL;
    UInt32                      numDeviceElements;
    
    const char 			*elementFieldNames[]={"typeMaskName", "name", "deviceIndex", "elementIndex", "typeValue", "typeName", "usagePageValue", "usageValue", 							"usageName", "dataSize", "rangeMin", "rangeMax", "scaledRangeMin", "scaledRangeMax", "relative", 
                                                        "wrapping", "nonLinear", "preferredState", "nullState", "calMin", "calMax", "scalingMin", "scalingMax"};
    int 			numElementStructElements, numElementStructFieldNames=23, elementIndex, deviceIndex;
    PsychGenericScriptType	*elementStruct;	
    pRecElement			currentElement;
    char			elementTypeName[PSYCH_HID_MAX_DEVICE_ELEMENT_TYPE_NAME_LENGTH];	
    char			usageName[PSYCH_HID_MAX_DEVICE_ELEMENT_USAGE_NAME_LENGTH];
    char			*typeMaskName;
    HIDElementTypeMask		typeMask;
    	 
    //all subfunctions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
    
    PsychCopyInIntegerArg(1, TRUE, &deviceIndex);
    PsychHIDVerifyInit();
    specDevice= PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex);
    PsychHIDVerifyOpenDeviceInterfaceFromDeviceRecordPtr(specDevice);
    numDeviceElements= HIDCountDeviceElements(specDevice, kHIDElementTypeIO);
    numElementStructElements = (int)numDeviceElements;
    PsychAllocOutStructArray(1, FALSE, numElementStructElements, numElementStructFieldNames, elementFieldNames, &elementStruct);
    elementIndex=0;
    for(currentElement=HIDGetFirstDeviceElement(specDevice,kHIDElementTypeIO); 
        currentElement != NULL; 
        currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeIO))
        {
        typeMask=HIDConvertElementTypeToMask (currentElement->type);
 	PsychHIDGetTypeMaskStringFromTypeMask(typeMask, &typeMaskName);
        PsychSetStructArrayStringElement("typeMaskName",	elementIndex, 	typeMaskName,	 			elementStruct);
        PsychSetStructArrayStringElement("name",		elementIndex, 	currentElement->name,	 		elementStruct);
        PsychSetStructArrayDoubleElement("deviceIndex",		elementIndex, 	(double)deviceIndex, 			elementStruct);
        PsychSetStructArrayDoubleElement("elementIndex",	elementIndex, 	(double)elementIndex+1, 		elementStruct);
        PsychSetStructArrayDoubleElement("typeValue",		elementIndex, 	(double)currentElement->type, 		elementStruct);
        HIDGetTypeName(currentElement->type, elementTypeName);
        PsychSetStructArrayStringElement("typeName",		elementIndex, 	elementTypeName,	 		elementStruct);
        PsychSetStructArrayDoubleElement("usagePageValue",	elementIndex, 	(double)currentElement->usagePage, 	elementStruct);
        PsychSetStructArrayDoubleElement("usageValue",		elementIndex, 	(double)currentElement->usage, 		elementStruct);
        HIDGetUsageName (currentElement->usagePage, currentElement->usage, usageName);
        PsychSetStructArrayStringElement("usageName",		elementIndex, 	usageName,	 			elementStruct);
        PsychSetStructArrayDoubleElement("dataSize",		elementIndex, 	(double)currentElement->size, 		elementStruct);
        PsychSetStructArrayDoubleElement("rangeMin",		elementIndex, 	(double)currentElement->min, 		elementStruct);
        PsychSetStructArrayDoubleElement("rangeMax",		elementIndex, 	(double)currentElement->max, 		elementStruct);
        PsychSetStructArrayDoubleElement("scaledRangeMin",	elementIndex, 	(double)currentElement->scaledMin, 	elementStruct);
        PsychSetStructArrayDoubleElement("scaledRangeMax",	elementIndex, 	(double)currentElement->scaledMax,	elementStruct);
        PsychSetStructArrayDoubleElement("relative",		elementIndex, 	(double)currentElement->relative,	elementStruct);	//psych_bool flag
        PsychSetStructArrayDoubleElement("wrapping",		elementIndex, 	(double)currentElement->wrapping,	elementStruct);	//psych_bool flag	
        PsychSetStructArrayDoubleElement("nonLinear",		elementIndex, 	(double)currentElement->nonLinear,	elementStruct);	//psych_bool flag
        PsychSetStructArrayDoubleElement("preferredState",	elementIndex, 	(double)currentElement->preferredState,	elementStruct);	//psych_bool flag
        PsychSetStructArrayDoubleElement("nullState",		elementIndex, 	(double)currentElement->nullState,	elementStruct);	//psych_bool flag

        PsychSetStructArrayDoubleElement("calMin",		elementIndex, 	(double)currentElement->calMin,		elementStruct);	
        PsychSetStructArrayDoubleElement("calMax",		elementIndex, 	(double)currentElement->calMax,		elementStruct);	
        PsychSetStructArrayDoubleElement("scalingMin",		elementIndex, 	(double)currentElement->userMin,	elementStruct);	
        PsychSetStructArrayDoubleElement("scalingMax",		elementIndex, 	(double)currentElement->userMax,	elementStruct);	
                                
        ++elementIndex; 
    }

    return(PsychError_none);	
}
Exemplo n.º 26
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
    }
}