Ejemplo n.º 1
0
int prHIDBuildElementList(VMGlobals *g, int numArgsPushed)
{

	PyrSlot *a = g->sp - 2; //class
	PyrSlot *b = g->sp - 1; //locID device
	PyrSlot *c = g->sp; //array

	int locID;
	int err = slotIntVal(b, &locID);
	if (err) return err;
	//look for the right device:
    pRecDevice  pCurrentHIDDevice = HIDGetFirstDevice ();
	while (pCurrentHIDDevice && (pCurrentHIDDevice->locID !=locID))
        pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice);
	if(!pCurrentHIDDevice) return errFailed;

	pRecElement	devElement =  HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll );
	UInt32 numElements = HIDCountDeviceElements (pCurrentHIDDevice, kHIDElementTypeAll );

//		PyrObject* devAllElementsArray = newPyrArray(g->gc, numElements * sizeof(PyrObject), 0 , true);
		PyrObject *devAllElementsArray = c->uo;
//		post("numElements: %d\n", numElements);
		numElements = sc_clip(numElements, 0, devAllElementsArray->size);
		for(uint i=0; i<numElements; i++){
			if(devElement){
				char cstrElementName [256];
				PyrObject* devElementArray = newPyrArray(g->gc, 8 * sizeof(PyrObject), 0 , true);
				// type name (1)
				HIDGetTypeName((IOHIDElementType) devElement->type, cstrElementName);
				PyrString *devstring = newPyrString(g->gc, cstrElementName, 0, true);
				SetObject(devElementArray->slots+devElementArray->size++, devstring);
				//g->gc->GCWrite(devElementArray, (PyrObject*) devstring);
				//usage (2)
				HIDGetUsageName (devElement->usagePage, devElement->usage, cstrElementName);
				PyrString *usestring = newPyrString(g->gc, cstrElementName, 0, true);
				SetObject(devElementArray->slots+devElementArray->size++, usestring);
				//g->gc->GCWrite(devElementArray, (PyrObject*) usestring);
				//cookie (3)
				SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->cookie);
				// min (4)
				SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->min);
				// max (5)
				SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->max);

				// IO type as int: (6)
				SetInt(devElementArray->slots+devElementArray->size++, (int) devElement->type);
				// Usage page as int: (7)
				SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->usagePage);
				// Usage type as int: (8)
				SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->usage);

				SetObject(devAllElementsArray->slots+i, devElementArray);
				//g->gc->GCWrite(devAllElementsArray, (PyrObject*) devElementArray);
			}
			devElement =  HIDGetNextDeviceElement (devElement, kHIDElementTypeAll);
		}
	SetObject(a, devAllElementsArray);
	return errNone;

}
Ejemplo n.º 2
0
int prHIDGetElementListSize(VMGlobals *g, int numArgsPushed)
{
	PyrSlot *a = g->sp - 1; //class
	PyrSlot *b = g->sp; //locID device
	int locID;
	int err = slotIntVal(b, &locID);
	if (err) return err;
    pRecDevice  pCurrentHIDDevice = HIDGetFirstDevice ();
	while (pCurrentHIDDevice && (pCurrentHIDDevice->locID !=locID))
        pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice);
	if(!pCurrentHIDDevice) return errFailed;
	UInt32 numElements = HIDCountDeviceElements (pCurrentHIDDevice, kHIDElementTypeAll );
	SetInt(a, numElements);
	return errNone;
}
unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef		inIOHIDDeviceRef,
                                             IOHIDElementRef *	outIOHIDElementRef,
                                             double				timeout) {
	if (!inIOHIDDeviceRef) {
		return (0);
	}
	if (0 == HIDHaveDeviceList()) {                                             // if we do not have a device list
		return (0);                                                             // return 0
	}

	Boolean found = false;

	// build list of device and elements to save current values
	CFIndex maxElements = HIDCountDeviceElements(inIOHIDDeviceRef,
	                                             kHIDElementTypeInput);
	double *saveValueArray = (double *) calloc(maxElements,
	                                           sizeof(double));                 // 2D array to save values

	// store initial values on first pass / compare to initial value on subsequent passes
	Boolean first = true;

	// get all the elements from this device
	CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef,
	                                                               NULL,
	                                                               kIOHIDOptionsTypeNone);
	// if that worked...
	if (elementCFArrayRef) {
		clock_t start = clock(),
		        end;

		// poll all devices and elements
		while (!found) {
			uint32_t currElementIndex = 0;
			CFIndex idx,
			        cnt = CFArrayGetCount(elementCFArrayRef);
			for (idx = 0; idx < cnt; idx++) {
				*outIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef,
				                                                               idx);
				if (!*outIOHIDElementRef) {
					continue;
				}

				// is this an input element?
				IOHIDElementType type = IOHIDElementGetType(*outIOHIDElementRef);

				switch (type) {
					// these types are inputs
					case kIOHIDElementTypeInput_Misc:
					case kIOHIDElementTypeInput_Button:
					case kIOHIDElementTypeInput_Axis:
					case kIOHIDElementTypeInput_ScanCodes:
					default:
					{
						break;
					}

					case kIOHIDElementTypeOutput:
					case kIOHIDElementTypeFeature:
					case kIOHIDElementTypeCollection:
					{
						*outIOHIDElementRef = NULL;                             // these types are not (Skip them)
						break;
					}
				}                                                               /* switch */
				if (!*outIOHIDElementRef) {
					continue;                                                   // skip this element
				}

				// get this elements current value
				double value = 0;                                               // default value is zero
				IOHIDValueRef tIOHIDValueRef;
				IOReturn ioReturn = IOHIDDeviceGetValue(inIOHIDDeviceRef,
				                                        *outIOHIDElementRef,
				                                        &tIOHIDValueRef);
				if (kIOReturnSuccess == ioReturn) {
					value = IOHIDValueGetScaledValue(tIOHIDValueRef,
					                                 kIOHIDValueScaleTypePhysical);
				}
				if (first) {
					saveValueArray[currElementIndex] = value;
				} else {
					CFIndex min = IOHIDElementGetLogicalMin(*outIOHIDElementRef);
					CFIndex max = IOHIDElementGetLogicalMax(*outIOHIDElementRef);

					double initialValue = saveValueArray[currElementIndex];
					double delta = (double) (max -
					                         min) *
					               kPercentMove *
					               0.01f;
					// is the new value within +/- delta of the initial value?
					if (((initialValue +
					      delta) < value) ||
					    ((initialValue -
					      delta) > value))
					{
						found = 1;                                              // (yes!) mark as found
						break;
					}
				}                                                               // if (first)

				currElementIndex++;                                             // bump element index
			}                                                                   // next idx
			if (first) {
				first = false;                                                  // no longer the first pass
			} else {
				// are we done?
				end = clock();
				double secs = (double) (end -
				                        start) /
				              CLOCKS_PER_SEC;
				if (secs > timeout) {
					break;                                                      // (yes) timeout
				}
			}
		}                                                                       // while (!found)

		CFRelease(elementCFArrayRef);
	}                                                                           // if (elementCFArrayRef)
	if (saveValueArray) {
		free(saveValueArray);
	}
	// return device and element moved
	if (found) {
		return (1);
	} else {
		*outIOHIDElementRef = NULL;

		return (0);
	}
}                                                                               // HIDConfigureSingleDeviceAction
Ejemplo n.º 4
0
unsigned char HIDConfigureAction (pRecDevice * ppDevice, pRecElement * ppElement, float timeout)
{
    unsigned long devices, maxElements = 0;
    long * saveValueArray;
    pRecDevice pDevice = NULL;
    pRecElement pElement = NULL;
    short deviceNum = 0;
    unsigned char found = 0, done = 0;
	clock_t start = clock (), end;
    unsigned long i;
    
     if (0 == HIDHaveDeviceList ())   // if we do not have a device list
		if (0 == HIDBuildDeviceList (0, 0)) // if we could not build anorther list (use generic usage and page)
			return 0; // return 0

    // build list of device and elements to save current values
    devices = HIDCountDevices ();
    pDevice = HIDGetFirstDevice ();
    while (pDevice)
    {
		if (HIDCountDeviceElements (pDevice, kHIDElementTypeIO) > maxElements)
			maxElements = HIDCountDeviceElements (pDevice, kHIDElementTypeIO);
		pDevice = HIDGetNextDevice (pDevice);
	}
	saveValueArray = (long *) malloc (sizeof (long) * devices * maxElements); // 2D array to save values
	for (i = 0; i < devices * maxElements; i++) // clear array
		*(saveValueArray + i) = 0x00000000;
		
	// store current values
	deviceNum = 0;
	pDevice = HIDGetFirstDevice ();
	while (pDevice)
	{
		short elementNum = 0;
		pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO);
		while (pElement)
		{
			*(saveValueArray + (deviceNum * maxElements) + elementNum) = HIDGetElementValue (pDevice, pElement);
			pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); 
			elementNum++;
		}
		pDevice = HIDGetNextDevice (pDevice);
		deviceNum++;
    }
    
    // poll all devices and elements, compare current value to save +/- kPercentMove
    while ((!found) && (!done))
    {
		double secs;
		// are we done?
		end = clock();
		secs = (double)(end - start) / CLOCKS_PER_SEC;
		if (secs > timeout)
			done = 1;
		deviceNum = 0;
		pDevice = HIDGetFirstDevice ();
		while (pDevice)
		{
			short elementNum = 0;
			pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO);
			while (pElement)
			{
				long initialValue = *(saveValueArray + (deviceNum * maxElements) + elementNum);
				long value = HIDGetElementValue (pDevice, pElement);
				long delta = (float)(pElement->max - pElement->min) * kPercentMove * 0.01;
				if (((initialValue + delta) < value) || ((initialValue - delta) > value))
				{
					found = 1;
					break;
				}
				pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); 
				elementNum++;
			}
			if (found)
				break;
			pDevice = HIDGetNextDevice (pDevice);
			deviceNum++;
		}
    }
    
    // return device and element moved
    if (found)
    {
		*ppDevice = pDevice;
		*ppElement = pElement;
		return 1;
    }
	else
	{
		*ppDevice = NULL;
		*ppElement = NULL;
		return 0;
	}
}
Boolean HIDConfigureAction( IOHIDDeviceRef* outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float inTimeout )
{
	// param error?
	if ( !outIOHIDDeviceRef || !outIOHIDElementRef ) {
		return 0;
	}
	
	if ( !gDeviceCFArrayRef ) { // if we do not have a device list
		// and  we can't build another list
		if ( !HIDBuildDeviceList( 0, 0 ) || !gDeviceCFArrayRef ) {
			return FALSE;	// bail
		}
	}
	
	IOHIDDeviceRef tIOHIDDeviceRef;	
	IOHIDElementRef tIOHIDElementRef;	
	
	// remember when we start; used to calculate timeout
	clock_t start = clock(), end;
	
	// determine the maximum number of elements
	CFIndex maxElements = 0;
	CFIndex devIndex, devCount = CFArrayGetCount( gDeviceCFArrayRef );
	for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
		tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, devIndex );
		
		if ( !tIOHIDDeviceRef ) {
			continue;               // skip this one
		}
		
		UInt32 count = HIDCountDeviceElements( tIOHIDDeviceRef, kHIDElementTypeInput );
		if ( count > maxElements ) {
			maxElements = count;
		}
	}
	
	// allocate an array of int's in which to store devCount * maxElements values
	double* saveValueArray = ( double * ) calloc( devCount * maxElements, sizeof( double ) ); // clear 2D array to save values
	
	// on first pass store initial values / compare current values to initial values on subsequent passes
	Boolean found = FALSE, first = TRUE;
	while ( !found ) {
		double maxDeltaPercent = 0;	// we want to find the one that moves the most ( percentage wise )
		for ( devIndex = 0; devIndex < devCount; devIndex++ ) {
			IOHIDDeviceRef tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDeviceCFArrayRef, devIndex );
			
			if ( !tIOHIDDeviceRef ) {
				continue;                       // skip this one
			}
#ifdef DEBUG
			long vendorID = IOHIDDevice_GetVendorID( tIOHIDDeviceRef );
			long productID = IOHIDDevice_GetProductID( tIOHIDDeviceRef );
#endif
			gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone );
			
			if ( gElementCFArrayRef ) {
				CFIndex eleIndex, eleCount = CFArrayGetCount( gElementCFArrayRef );
				for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) {
					tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, eleIndex );
					
					if ( !tIOHIDElementRef ) {
						continue;
					}
					
					IOHIDElementType tIOHIDElementType = IOHIDElementGetType( tIOHIDElementRef );
					
					// only care about inputs (no outputs or features)
					if ( tIOHIDElementType <= kIOHIDElementTypeInput_ScanCodes ) {

						if ( IOHIDElementIsArray( tIOHIDElementRef ) ) {
							//printf( "ARRAY!\n" );
							continue;	// skip array elements
						}
						uint32_t usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
						uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
						uint32_t reportCount = IOHIDElementGetReportCount( tIOHIDElementRef );
#ifdef DEBUG
						if ( first ) {
							IOHIDElementCookie cookie = IOHIDElementGetCookie( tIOHIDElementRef );
							printf( "%s, dev: {ref:%p, ven: 0x%08lX, pro: 0x%08lX}, ele: {ref:%p, cookie: %p, usage:%04lX:%08lX}\n",
								   __PRETTY_FUNCTION__,
								   tIOHIDDeviceRef,
								   vendorID,
								   productID,
								   tIOHIDElementRef,
								   cookie,
								   (long unsigned int) usagePage,
								   (long unsigned int) usage ); fflush( stdout );
							
							if ( ( 0x054C == vendorID ) && ( 0x0268 == productID ) && ( 0x001E == (UInt32) cookie ) ) {
								//printf( "DING!\n" );
							}
						}
#endif
#if 1					// work-around for IOHIDValueGetScaledValue crash (when element report count > 1)
						if ( reportCount > 1 ) {
							//printf( "REPORT!\n" );
							continue; // skip reports
						}
#endif					
						// ignore PID elements and arrays
						if ( ( kHIDPage_PID != usagePage ) && ( -1 != usage ) ) {
							// get this elements current value
							double value = 0.0;	// default value is zero
							IOHIDValueRef tIOHIDValueRef;
							IOReturn ioReturn = IOHIDDeviceGetValue( tIOHIDDeviceRef, tIOHIDElementRef, &tIOHIDValueRef );
							if ( kIOReturnSuccess == ioReturn ) {
								value = IOHIDValueGetScaledValue( tIOHIDValueRef, kIOHIDValueScaleTypePhysical );
							}
							
							if ( first ) {
								saveValueArray[( devIndex * maxElements ) + eleIndex] = value;
							} else {
								double initialValue = saveValueArray[( devIndex * maxElements ) + eleIndex];
								
								CFIndex valueMin = IOHIDElementGetPhysicalMin( tIOHIDElementRef );
								CFIndex valueMax = IOHIDElementGetPhysicalMax( tIOHIDElementRef );
								
								double deltaPercent = fabs( ( initialValue - value ) * 100.0 / (valueMax - valueMin) );
#if 0
								if ( !first ) {
								// Device: 0x13b6a0 = { Logitech Inc. - WingMan Force 3D, 	vendorID:	0x046D, 	productID:	0xC283, usage: 0x0001:0x0004, "Generic Desktop Joystick"
									if ( ( vendorID == 0x046D ) && ( productID == 0xC283 ) ) {
										if ( ( kHIDPage_GenericDesktop == usagePage ) && ( kHIDUsage_GD_Rz == usage ) ) {
											printf( "initial: %6.2f, value: %6.2f, diff: %6.2f, delta percent: %6.2f!\n", initialValue, value, fabs( initialValue - value ), deltaPercent );
										}
									}
								}
								deltaPercent = 0.0;
#endif
								if ( deltaPercent >= kPercentMove ) {
									found = TRUE;
									if ( deltaPercent > maxDeltaPercent ) {
										maxDeltaPercent = deltaPercent;
										
										*outIOHIDDeviceRef = tIOHIDDeviceRef;
										*outIOHIDElementRef = tIOHIDElementRef;
									}
									break;
								}
							}   // if first
						}       // if usage
					}           // if type
				}               // for elements...
				CFRelease( gElementCFArrayRef );
				gElementCFArrayRef = NULL;
			}	// if ( gElementCFArrayRef )
			if ( found ) {
				// HIDDumpElementInfo( tIOHIDElementRef );
				break; // DONE!
			}
		}                   // for devices
		
		first = FALSE;          // no longer the first pass
		
		// are we done?
		end = clock();
		double secs = (double)( end - start ) / CLOCKS_PER_SEC;
		
		if ( secs > inTimeout ) {
			break;              // ( yes ) timeout
		}
	}	//	while ( !found )
	
	// return device and element moved
	if ( !found ) {
		*outIOHIDDeviceRef = NULL;
		*outIOHIDElementRef = NULL;
	}
	return found;
}   // HIDConfigureAction
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);	
}
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);	
}