PsychError WAITSECSYieldSecs(void)
{
    static char useString[] = "[realWakeupTimeSecs] = WaitSecs('YieldSecs', waitPeriodSecs);";
    //                                                                      1 
    static char synopsisString[] = 
    "Wait for at least \"waitPeriodSecs\", don't care if it takes a few milliseconds longer. "
    "Optionally, return the real wakeup time \"realWakeupTimeSecs\".\n"
	"This call is useful if you want your code to release the cpu for a few milliseconds, "
	"e.g., to avoid overloading the cpu in a spinning loop, and you don't care if the "
	"wait takes a few msecs longer than specified. If you do care, use one of the other "
	"WaitSecs() variants! The other variants emphasize accuracy of timed waits, even if "
	"this causes a high load on the processor.\n";
	
    static char seeAlsoString[] = "";	

    double	waitPeriodSecs;
    double	now;

    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
    
    PsychCopyInDoubleArg(1,TRUE,&waitPeriodSecs);
    PsychYieldIntervalSeconds(waitPeriodSecs);

    // Return current system time at end of sleep:
    PsychGetAdjustedPrecisionTimerSeconds(&now);
    PsychCopyOutDoubleArg(1, FALSE, now);

    return(PsychError_none);	
}
/*
	PsychEstimateGetSecsValueAtTickCountZero()
	Note that the tick counter rolls over about every 27 months. Its possible to have machine uptime of that long 
	but it seems unlikely so we don't worry about roll over when calculating 
*/
void PsychEstimateGetSecsValueAtTickCountZero(void)
{
	double		nowTicks, nowSecs;
	
	nowTicks=(double)TickCount();
	PsychGetAdjustedPrecisionTimerSeconds(&nowSecs);
	estimatedGetSecsValueAtTickCountZero=nowSecs - nowTicks * (1/60.15); 
}
/* Perform one context loop iteration (for bus message handling) if doWait == false,
 * or two seconds worth of iterations if doWait == true. This drives the message-bus
 * callback, so needs to be performed to get any error reporting etc.
 */
int PsychGSProcessMovieContext(GMainLoop *loop, psych_bool doWait)
{
	double tdeadline, tnow;
	PsychGetAdjustedPrecisionTimerSeconds(&tdeadline);
    tnow = tdeadline;
	tdeadline+=2.0;

	if (NULL == loop) return(0);

	while (doWait && (tnow < tdeadline)) {
		// Perform non-blocking work iteration:
		if (!g_main_context_iteration(g_main_loop_get_context(loop), false)) PsychYieldIntervalSeconds(0.010);

		// Update time:
		PsychGetAdjustedPrecisionTimerSeconds(&tnow);
	}

	// Perform one more work iteration of the event context, but don't block:
	return(g_main_context_iteration(g_main_loop_get_context(loop), false));
}
PsychError GETSECSGetSecs(void) 
{
    double 	*returnValue;  

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(0));
    
    //Allocate a return matrix and load it with the depth values.  
    PsychAllocOutDoubleArg(1, FALSE, &returnValue);
    PsychGetAdjustedPrecisionTimerSeconds(returnValue);

    return(PsychError_none);	
}
/* Perform context loop iterations (for bus message handling) if doWait == false,
 * as long as there is work to do, or at least two seconds worth of iterations
 * if doWait == true. This drives the message-bus callback, so needs to be
 * performed to get any error reporting etc.
 */
static int PsychGSProcessMovieContext(GMainLoop *loop, psych_bool doWait)
{
    psych_bool workdone;    
    double tdeadline, tnow;
    PsychGetAdjustedPrecisionTimerSeconds(&tdeadline);
    tnow = tdeadline;
    tdeadline+=2.0;
    
    if (NULL == loop) return(0);
    
    while (doWait && (tnow < tdeadline)) {
        // Perform non-blocking work iteration:
        if (!g_main_context_iteration(g_main_loop_get_context(loop), false)) PsychYieldIntervalSeconds(0.010);
        
        // Update time:
        PsychGetAdjustedPrecisionTimerSeconds(&tnow);
    }
    
    // Perform work iterations of the event context as long as events are available, but don't block:
    while ((workdone = g_main_context_iteration(g_main_loop_get_context(loop), false)) == TRUE);
    
    return(workdone);
}
void StoreNowTime(void)
{
	double				now;
	timeArrayElement	*newElement;
	
	PsychGetAdjustedPrecisionTimerSeconds(&now);
	newElement=(timeArrayElement *)malloc(sizeof(timeArrayElement));
	newElement->timeValue=now;
	newElement->next=NULL;
	if(timeListTail != NULL)
		timeListTail->next=newElement;
	timeListTail=newElement;
	if(timeListHead==NULL)
		timeListHead=newElement;
	++numElements;
}
PsychError WAITSECSWaitUntilSecs(void)
{
    static char useString[] = "[realWakeupTimeSecs] = WaitSecs('UntilTime', whenSecs);";
    //                                                                      1 
    static char synopsisString[] = 
    "Wait until at least system time \"whenSecs\" has been reached. "
    "Optionally, return the real wakeup time \"realWakeupTimeSecs\".\n"
    "This allows conveniently waiting until an absolute point in time "
    "has been reached, or to allow drift-free waiting for a well defined "
    "interval, more accurate than the standard WaitSecs() call.\n"
    "Example:\n"
    "Wait until 0.6 secs after last stimulus onset, if vbl=Screen('Flip', window); "
    "was the onset timestamp vbl from a previous flip:\n"
    "realwakeup = WaitSecs('UntilTime', vbl + 0.6);\n\n"
    "In a perfect world, realwakeup == vbl + 0.6, in reality it will be\n"
    "realwakeup == vbl + 0.6 + randomjitter; with randomjitter being the "
    "hopefully small scheduling delay of your operating system. If the "
    "delay is high or varies a lot between trials then your system has "
    "noisy timing or real timing problems.\n";
	
    static char seeAlsoString[] = "";	

    double	waitUntilSecs;
    double	now;

    //all sub functions should have these two lines
    PsychPushHelp(useString, synopsisString,seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
    
    PsychCopyInDoubleArg(1,TRUE,&waitUntilSecs);
    PsychWaitUntilSeconds(waitUntilSecs);

    // Return current system time at end of sleep:
    PsychGetAdjustedPrecisionTimerSeconds(&now);
    PsychCopyOutDoubleArg(1, FALSE, now);

    return(PsychError_none);	
}
/* Atomically release the 'mutex' lock and go to sleep, waiting for the 'condition' variable
 * being signalled, then waking up and trying to re-lock the 'mutex'. Will return with
 * mutex locked.
 *
 * Like PsychWaitCondition, but function will timeout if it fails being signalled before
 * timeout interval 'maxwaittimesecs' expires. In any case, it will only return after
 * reacquiring the mutex. It will retun zero on successfull wait, non-zero (ETIMEDOUT) if
 * timeout was triggered without the condition being signalled.
 */
int PsychTimedWaitCondition(psych_condition* condition, psych_mutex* mutex, double maxwaittimesecs)
{
	struct timespec abstime;
	double tnow;

	// Convert relative wait time to absolute system time:
	PsychGetAdjustedPrecisionTimerSeconds(&tnow);
	maxwaittimesecs+=tnow;

	// Split maxwaittimesecs in...
		
	// ... full integral seconds (floor() it)...
	abstime.tv_sec  = (time_t) maxwaittimesecs;

	// ... and fractional seconds, expressed as nanoseconds in (long) format:
	abstime.tv_nsec = (long) (((double) maxwaittimesecs - (double) abstime.tv_sec) * (double) (1e9));

	// Perform wait with timeout:
	return(pthread_cond_timedwait(condition, mutex, &abstime));
}
// Display link callback: Needed so we can actually start the display link:
// Gets apparently called from a separate high-priority thread, close to vblank
// time. "inNow" is the timestamp of last vblank.
static CVReturn PsychCVDisplayLinkOutputCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *inNow, const CVTimeStamp *inOutputTime,
                                                 CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
{
    double tVBlank;
    CVTimeStamp tVbl;
    double tHost;
    
    // Retrieve screenId of associated display screen:
    int screenId = (int) (long int) displayLinkContext;
    
    // Extra guard against shutdown races:
    if (NULL == cvDisplayLink[screenId]) return(kCVReturnSuccess);
    
    // Translate CoreVideo inNow timestamp with time of last vbl from gpu time
    // to host system time, aka our GetSecs() timebase:
    memset(&tVbl, 0, sizeof(tVbl));
    tVbl.version = 0;
    tVbl.flags = kCVTimeStampHostTimeValid;
    CVDisplayLinkTranslateTime(displayLink, inNow, &tVbl);
    tVBlank = (double) tVbl.hostTime / (double) 1000000000;

    // Store timestamp in our shared data structure, also increment virtual vblank counter:
    PsychLockMutex(&(cvDisplayLinkData[screenId].mutex));
    cvDisplayLinkData[screenId].vblCount++;
    cvDisplayLinkData[screenId].vblTimestamp = tVBlank;
    PsychUnlockMutex(&(cvDisplayLinkData[screenId].mutex));
    
    // Low-level timestamp debugging requested?
    if (PsychPrefStateGet_Verbosity() > 20) {
        // Compare CV timestamps against host time for correctness check. We wait 4 msecs,
        // then take tHost and hopefully tHost will be at least 4 msecs later than the
        // computed vblank timestamp tVBlank:
        PsychWaitIntervalSeconds(0.004);
        PsychGetAdjustedPrecisionTimerSeconds(&tHost);
        
        // Caution: Don't run from Matlab GUI! This printf will crash Matlab otherwise.
        printf("CVCallback: %i : tHost = %lf secs, tVBlank = %lf secs. tHost - tVBlank = %lf secs.\n", screenId, tHost, tVBlank, tHost - tVBlank);
    }

    return(kCVReturnSuccess);
}
/* PsychOSMonotonicToRefTime(t)
 *
 * Map given input time value monotonicTime to PTB reference time if
 * neccessary, pass-through otherwise.
 *
 * Can conditionally convert from CLOCK_MONOTONIC time to reftime, e.g.,
 * to CLOCK_REALTIME aka gettimeofday().
 *
 */
double PsychOSMonotonicToRefTime(double monotonicTime)
{
	double now, tMonotonic;
	// Get current reftime:
	PsychGetAdjustedPrecisionTimerSeconds(&now);
	// Get current CLOCK_MONOTONIC time:
	tMonotonic = PsychOSGetLinuxMonotonicTime();
	// Given input monotonicTime time value closer to tMonotonic than to GetSecs time?
	if (fabs(monotonicTime - tMonotonic) < fabs(monotonicTime - now)) {
		// Timestamps are in monotonic time! Need to remap.
		// tMonotonic shall be the offset between GetSecs and monotonic time,
		// i.e., the offset that needs to be added to monotonic timestamps to
		// remap them to GetSecs time:
		tMonotonic = now - tMonotonic;
		
		// Correct timestamp by adding corrective offset:
		monotonicTime += tMonotonic;
	}

	return(monotonicTime);
}
Exemple #11
0
PsychError WAITSECSWaitSecs(void) 
{
    double	waitPeriodSecs;
    double	now;

    //check to see if the user supplied superfluous arguments
    PsychErrorExit(PsychCapNumOutputArgs(1));
    PsychErrorExit(PsychCapNumInputArgs(1));
    
    if (!PsychCopyInDoubleArg(1, FALSE, &waitPeriodSecs)) {
	// Called without arguments. Output synopsis:
	WAITSECSSynopsis();
	return(PsychError_none);
    }

    // Wait for requested interval:
    PsychWaitIntervalSeconds(waitPeriodSecs);

    // Return current system time at end of sleep:
    PsychGetAdjustedPrecisionTimerSeconds(&now);
    PsychCopyOutDoubleArg(1, FALSE, now);

    return(PsychError_none);	
}
PsychError SCREENGetMovieImage(void) 
{
    PsychWindowRecordType	*windowRecord;
    PsychWindowRecordType	*textureRecord;
    PsychRectType		rect;
    double			deadline, tnow;
    int                         moviehandle = -1;
    int                         waitForImage = TRUE;
    double                      requestedTimeIndex = -1;
    double                      presentation_timestamp = 0;
    int				rc=0;
    int				specialFlags = 0;
    int				specialFlags2 = 0;
	
    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(6));            // Max. 6 input args.
    PsychErrorExit(PsychRequireNumInputArgs(2));        // Min. 2 input args required.
    PsychErrorExit(PsychCapNumOutputArgs(2));           // Max. 2 output args.
    
    // Get the window record from the window record argument and get info from the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    // Only onscreen windows allowed:
    if(!PsychIsOnscreenWindow(windowRecord)) {
        PsychErrorExitMsg(PsychError_user, "GetMovieImage called on something else than an onscreen window.");
    }
    
    // Get the movie handle:
    PsychCopyInIntegerArg(2, TRUE, &moviehandle);
    if (moviehandle==-1) {
        PsychErrorExitMsg(PsychError_user, "GetMovieImage called without valid handle to a movie object.");
    }

    // Get the 'waitForImage' flag: If waitForImage == true == 1, we'll do a blocking wait for
    // arrival of a new image for playback. Otherwise we will return with a 0-Handle if there
    // isn't any new image available.
    PsychCopyInIntegerArg(3, FALSE, &waitForImage);
    
    // Get the requested timeindex for the frame. The default is -1, which means: Get the next image,
    // according to current movie playback time.
    PsychCopyInDoubleArg(4, FALSE, &requestedTimeIndex);
    
    // Get the optional specialFlags flag:
    PsychCopyInIntegerArg(5, FALSE, &specialFlags);

    // Get the optional specialFlags2 flag:
    PsychCopyInIntegerArg(6, FALSE, &specialFlags2);

    PsychGetAdjustedPrecisionTimerSeconds(&deadline);
    deadline += 5;

    while (rc==0) {
        rc = PsychGetTextureFromMovie(windowRecord, moviehandle, TRUE, requestedTimeIndex, NULL, NULL);
		PsychGetAdjustedPrecisionTimerSeconds(&tnow);
        if (rc<0 || (tnow > deadline)) {
            // No image available and there won't be any in the future, because the movie has reached
            // its end and we are not in looped playback mode:
	    if (tnow > deadline) printf("PTB-ERROR: In Screen('GetMovieImage') for movie %i: Timed out while waiting for new frame after 5 seconds!\n", moviehandle);

            // No new texture available: Return a negative handle:
            PsychCopyOutDoubleArg(1, TRUE, -1);
            // ...and an invalid timestamp:
            PsychCopyOutDoubleArg(2, FALSE, -1);
            // Ready!
            return(PsychError_none);
        }
        else if (rc==0 && waitForImage == 0) {
            // We should just poll once and no new texture available: Return a null-handle:
            PsychCopyOutDoubleArg(1, TRUE, 0);
            // ...and an invalid timestamp:
            PsychCopyOutDoubleArg(2, FALSE, -1);
            // Ready!
            return(PsychError_none);
        }
        else if (rc==0 && waitForImage != 0) {
            // No new texture available yet. Just sleep a bit and then retry...
            PsychWaitIntervalSeconds(0.005);
        }
    }

    // New image available: Go ahead...
    
    // Create a texture record.  Really just a window record adapted for textures.  
    PsychCreateWindowRecord(&textureRecord);	// This also fills the window index field.
    // Set mode to 'Texture':
    textureRecord->windowType=kPsychTexture;
    // We need to assign the screen number of the onscreen-window.
    textureRecord->screenNumber=windowRecord->screenNumber;
    // It is always a 32 bit texture for movie textures:
    textureRecord->depth=32;
    textureRecord->nrchannels = 4;

    // Create default rectangle which describes the dimensions of the image. Will be overwritten
    // later on.
    PsychMakeRect(rect, 0, 0, 10, 10);
    PsychCopyRect(textureRecord->rect, rect);
    
    // Other setup stuff:
    textureRecord->textureMemorySizeBytes= 0;
    textureRecord->textureMemory=NULL;

    // Assign parent window and copy its inheritable properties:
    PsychAssignParentWindow(textureRecord, windowRecord);

    // Try to fetch an image from the movie object and return it as texture:
    PsychGetTextureFromMovie(windowRecord, moviehandle, FALSE, requestedTimeIndex, textureRecord, ((specialFlags2 & 1) ? NULL : &presentation_timestamp));

    // Assign GLSL filter-/lookup-shaders if needed: usefloatformat is always == 0 as
    // our current movie engine implementations only return 8 bpc fixed textures.
    // The 'userRequest' flag is set if specialmode flag is set to 8.
    PsychAssignHighPrecisionTextureShaders(textureRecord, windowRecord, 0, (specialFlags & 2) ? 1 : 0);

    // Texture ready for consumption. Mark it valid and return handle to userspace:
    PsychSetWindowRecordValid(textureRecord);
    PsychCopyOutDoubleArg(1, TRUE, textureRecord->windowIndex);
    // Return presentation timestamp for this image:
    PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp);
    
    // Ready!
    return(PsychError_none);
}
PsychError SCREENGetMouseHelper(void) 
{

    const char *valuatorInfo[]={"label", "min", "max", "resolution", "mode", "sourceID"};
    int numValuatorStructFieldNames = 6;
    int numIValuators = 0;
    PsychGenericScriptType *valuatorStruct = NULL;

#if PSYCH_SYSTEM == PSYCH_OSX
	Point		mouseXY;
	UInt32		buttonState;
	double		*buttonArray;
	int		numButtons, i;
	psych_bool	doButtonArray;
	PsychWindowRecordType *windowRecord;
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(3));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(6));  //The maximum number of outputs
	
	//Buttons.  
	// The only way I know to detect the  number number of mouse buttons is directly via HID.  The device reports
	//that information but OS X seems to ignore it above the level of the HID driver, that is, no OS X API above the HID driver
	//exposes it.  So GetMouse.m function calls PsychHID detect the number of buttons and then passes that value to GetMouseHelper 
	//which returns that number of button values in a vector.      
	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);
	if(numButtons > 32)
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must not exceed 32");

	// Special codes -10 to -15? --> Console keyboard queries:
	if(numButtons <= -10 && numButtons >= -15) {
		ConsoleInputHelper((int) numButtons);
		return(PsychError_none);
	}

	if(numButtons < 1) 
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must exceed 1");

	doButtonArray=PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);
	if(doButtonArray){
		buttonState=GetCurrentButtonState();
		for(i=0;i<numButtons;i++)
			buttonArray[i]=(double)(buttonState & (1<<i));
	}
			
	// Get cursor position:
#ifndef __LP64__
    // 32-Bit Carbon version:
	GetGlobalMouse(&mouseXY);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)mouseXY.h);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double)mouseXY.v);
#else
    // 64-Bit HIToolbox version (OSX 10.5 and later):
    HIPoint outPoint;
    HIGetMousePosition(kHICoordSpaceScreenPixel, NULL, &outPoint);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) outPoint.x);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) outPoint.y);
#endif
	// Return optional keyboard input focus status:
	if (numButtons > 0) {
		// Window provided?
        // We only have the function GetUserFocusWindow on 32-Bit Carbon.
        // We have a drop-in replacement in OSX/PsychCocoaGlue.c for 64-Bit Cocoa.
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetUserFocusWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else
        {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}
	}

	// Return optional valuator values: Unimplemented on OS/X. Just return an empty matrix.
	// The buttonArray is just a dummy assignment without any meaning.
	PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
#endif

#if PSYCH_SYSTEM == PSYCH_WINDOWS
	static unsigned char disabledKeys[256];
	static unsigned char firsttime = 1;
	int keysdown, i, priorityLevel;
	unsigned char keyState[256];
	double* buttonArray;
	double numButtons, timestamp;
	PsychNativeBooleanType* buttonStates;
	POINT		point;
	HANDLE	   currentProcess;
	DWORD   oldPriority = NORMAL_PRIORITY_CLASS;
    const  DWORD   realtime_class = REALTIME_PRIORITY_CLASS;
	PsychWindowRecordType *windowRecord;

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

	// Retrieve optional number of mouse buttons:
	numButtons = 0;
	PsychCopyInDoubleArg(1, FALSE, &numButtons);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
		// GetMouse-Mode: Return mouse button states and mouse cursor position:

		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)3, (int)1, &buttonArray);
		// Query and return mouse button state:
		PsychGetMouseButtonState(buttonArray);
		// Query and return cursor position in global coordinates:
		GetCursorPos(&point);
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) point.x);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) point.y);
		
		// Window provided?
		if (PsychIsWindowIndexArg(2)) {
			// Yes: Check if it has focus.
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (GetForegroundWindow() == windowRecord->targetSpecific.windowHandle) ? 1 : 0);
		} else {
			// No. Just always return "has focus":
			PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) 1);
		}		

		// Return optional valuator values: Unimplemented on Windows. Just return an empty matrix.
		// The &timestamp is just a dummy assignment without any meaning.
		PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) 0, (int) 1, &timestamp);
		PsychCopyOutDoubleMatArg(6, kPsychArgOptional, (int) 1, (int) 0, (int) 1, buttonArray);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Microsoft Windows is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (firsttime) {
			// First time init:
			firsttime = 0;
			memset(keyState, 0, sizeof(keyState));
			memset(disabledKeys, 0, sizeof(disabledKeys));
			// These keycodes are always disabled: 0, 255:
			disabledKeys[0]=1;
			disabledKeys[255]=1;
			// Mouse buttone (left, right, middle) are also disabled by default:
			disabledKeys[1]=1;
			disabledKeys[2]=1;
			disabledKeys[4]=1;
	  }

	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode
	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

			// Query state of all keys:
			for(i=1;i<255;i++){
				keyState[i] = (GetAsyncKeyState(i) & -32768) ? 1 : 0;
			}

	      // Disable all keys that are registered in disabledKeys. Check if
			// any non-disabled key is down.
	      for (i=0; i<256; i++) {
				if (disabledKeys[i]>0) keyState[i] = 0;
				keysdown+=(unsigned int) keyState[i];
	      }

	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a millisecond before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.001);

	    } while(1);

	    if (numButtons==-2) {
	      // KbWait mode: Copy out time value.
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);

	      // Copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      

	      // Copy out keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Build 256 elements return vector:
	      for(i=0; i<255; i++) {
		  		buttonStates[i] = (PsychNativeBooleanType)((keyState[i+1]) ? 1 : 0);
	      }
			// Special case: Null out last element:
			buttonStates[255] = (PsychNativeBooleanType) 0;
	    }
	  }
	  
	  if (numButtons==-3) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Determine our processID:
		currentProcess = GetCurrentProcess();
    
		// Get current scheduling policy:
		oldPriority = GetPriorityClass(currentProcess);
		
		// Map to PTB's scheme:
		switch(oldPriority) {
			case NORMAL_PRIORITY_CLASS:
				priorityLevel = 0;
			break;

			case HIGH_PRIORITY_CLASS:
				priorityLevel = 1;
			break;

			case REALTIME_PRIORITY_CLASS:
				priorityLevel = 2;
			break;

			default:
				priorityLevel = 0;
		}
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 2) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must not exceed 2.");

			switch(priorityLevel) {
				case 0: // Standard scheduling:
					SetPriorityClass(currentProcess, NORMAL_PRIORITY_CLASS);

					// Disable any MMCSS scheduling for us:
					PsychSetThreadPriority((psych_thread*) 0x1, 0, 0);
				break;
				
				case 1: // High priority scheduling:
					SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);

					// Additionally try to schedule us MMCSS: This will lift us roughly into the
					// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
					// on Vista and Windows-7 and later, however with a scheduler safety net applied.
					PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
				break;
				
				case 2: // Realtime scheduling:
					// This can fail if Matlab is not running under a user account with proper permissions:
					if ((0 == SetPriorityClass(currentProcess, REALTIME_PRIORITY_CLASS)) || (REALTIME_PRIORITY_CLASS != GetPriorityClass(currentProcess))) {
						// Failed to get RT-Scheduling. Let's try at least high priority scheduling:
						SetPriorityClass(currentProcess, HIGH_PRIORITY_CLASS);
						
						// Additionally try to schedule us MMCSS: This will lift us roughly into the
						// same scheduling range as REALTIME_PRIORITY_CLASS, even if we are non-admin users
						// on Vista and Windows-7 and later, however with a scheduler safety net applied.
						PsychSetThreadPriority((psych_thread*) 0x1, 10, 0);
					}
				break;
			}
		}
		// End of Priority() helper for Win32.
	  }
	}
#endif
	
#if PSYCH_SYSTEM == PSYCH_LINUX
	double myvaluators[100];
	int    numvaluators;
	unsigned char keys_return[32];
	char* keystring;
	PsychGenericScriptType *kbNames;
	CGDirectDisplayID dpy;
	Window rootwin, childwin, mywin;
	int i, j, mx, my, dx, dy;
	double mxd, myd, dxd, dyd;
	unsigned int mask_return;
	double timestamp;
	int numButtons;
	double* buttonArray;
	PsychNativeBooleanType* buttonStates;
	int keysdown;
	XEvent event_return;
	XKeyPressedEvent keypressevent;
	int screenNumber;
	int priorityLevel;
	struct sched_param schedulingparam;
	PsychWindowRecordType *windowRecord;
	int mouseIndex;
	XIButtonState buttons_return;
	XIModifierState modifiers_return;
	XIGroupState group_return;

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

	PsychCopyInIntegerArg(1, kPsychArgRequired, &numButtons);

	// Retrieve optional screenNumber argument:
	if (numButtons!=-5) {
		screenNumber = 0;
		if (PsychIsScreenNumberArg(2)) {
			PsychCopyInScreenNumberArg(2, FALSE, &screenNumber);
		}

		// Map screenNumber to X11 display handle and screenid:
		PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		if (PsychIsWindowIndexArg(2)) {
			PsychAllocInWindowRecordArg(2, TRUE, &windowRecord);
			if (!PsychIsOnscreenWindow(windowRecord)) {
				PsychErrorExitMsg(PsychError_user, "Provided window handle isn't an onscreen window, as required.");
			}

			screenNumber = windowRecord->screenNumber;
			mywin = windowRecord->targetSpecific.xwindowHandle;

			// Map screenNumber to X11 display handle and screenid:
			PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

		} else {
			mywin = RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber));
		}
	}

	// Default to "old school" mouse query - System default mouse via X core protocol:
	mouseIndex = -1;
	PsychCopyInIntegerArg(3, FALSE, &mouseIndex);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
	  // Mouse pointer query mode:
	  numvaluators = 0;

	  if (mouseIndex >= 0) {
		// XInput-2 query for handling of multiple mouse pointers:

		// Query input device list for screen:
		int nDevices;
		XIDeviceInfo* indevs = PsychGetInputDevicesForScreen(screenNumber, &nDevices);

		// Sanity check:
		if (NULL == indevs) PsychErrorExitMsg(PsychError_user, "Sorry, your system does not support individual mouse pointer queries.");
		if (mouseIndex >= nDevices) PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. No such device.");
		if ((indevs[mouseIndex].use != XIMasterPointer) && (indevs[mouseIndex].use != XISlavePointer) && (indevs[mouseIndex].use != XIFloatingSlave)) {
			PsychErrorExitMsg(PsychError_user, "Invalid 'mouseIndex' provided. Not a pointer device.");
		}

		// We requery the device info struct to retrieve updated live device state:
		// Crucial for slave pointers to get any state at all, but also needed on
		// master pointers to get the state of additional valuators, e.g., pen pressure,
		// touch area, tilt etc. for digitizer tablets, touch pads etc. For master pointers,
		// the primary 2 axis for 2D (x,y) position and the button/modifier state will be
		// queried via a dedicated XIQueryPointer() call, so that info gets overriden.
		indevs = XIQueryDevice(dpy, indevs[mouseIndex].deviceid, &numButtons);
		modifiers_return.effective = 0;

		// Query real number of mouse buttons and the raw button and axis state
		// stored inside the device itself. This is done mostly because slave pointer
		// devices don't support XIQueryPointer() so we get their relevant info from the
		// XIDeviceInfo struct itself:
		numButtons = 0;
		numvaluators = 0;
		memset(myvaluators, 0, sizeof(myvaluators));

		if (PsychIsArgPresent(PsychArgOut, 6)) {
			// Usercode wants valuator info structs:
			for (i = 0; i < indevs->num_classes; i++) if (indevs->classes[i]->type == XIValuatorClass) numIValuators++;
			PsychAllocOutStructArray(6, TRUE, numIValuators, numValuatorStructFieldNames, valuatorInfo, &valuatorStruct);
		}

		for (i = 0; i < indevs->num_classes; i++) {
			// printf("Class %i: Type %i\n", i, (int) indevs->classes[i]->type);
			if (indevs->classes[i]->type == XIButtonClass) {
				// Number of buttons: For all pointers.
				numButtons = ((XIButtonClassInfo*) indevs->classes[i])->num_buttons;

				// Button state for slave pointers. Will get overriden for master pointers:
				buttons_return.mask = ((XIButtonClassInfo*) indevs->classes[i])->state.mask;
				buttons_return.mask_len = ((XIButtonClassInfo*) indevs->classes[i])->state.mask_len;
			}

			// Axis state for slave pointers. First two axis (x,y) will get overriden for master pointers:
			if (indevs->classes[i]->type == XIValuatorClass) {
				XIValuatorClassInfo* axis = (XIValuatorClassInfo*) indevs->classes[i];
				if (axis->number == 0) mxd = axis->value;  // x-Axis.
				if (axis->number == 1) myd = axis->value;  // y-Axis.

				// Additional axis, e.g., digitizer tablet, touchpads etc.:
				if (axis->number >= 0 && axis->number < 100) {
					myvaluators[axis->number] = axis->value;
					numvaluators = (numvaluators >= axis->number + 1) ? numvaluators : axis->number + 1;
				}

				// Assign valuator info struct, if requested:
				if (valuatorStruct) {
					if (axis->label != None) {
						char* atomlabel =  XGetAtomName(dpy, axis->label);
						PsychSetStructArrayStringElement("label", axis->number, atomlabel, valuatorStruct);
						XFree(atomlabel);
					} else {
						PsychSetStructArrayStringElement("label", axis->number, "None", valuatorStruct);
					}

					PsychSetStructArrayDoubleElement("min", axis->number, (double) axis->min, valuatorStruct);
					PsychSetStructArrayDoubleElement("max", axis->number, (double) axis->max, valuatorStruct);
					PsychSetStructArrayDoubleElement("resolution", axis->number, (double) axis->resolution, valuatorStruct);
					PsychSetStructArrayDoubleElement("mode", axis->number, (double) axis->mode, valuatorStruct);
					PsychSetStructArrayDoubleElement("sourceID", axis->number, (double) axis->sourceid, valuatorStruct);
				}
				// printf("AXIS %i, LABEL = %s, MIN = %f, MAX = %f, VAL = %f\n", axis->number, (char*) "NONE", (float) axis->min, (float) axis->max, (float) axis->value);
			}
		}

		// Add 32 buttons for modifier key state vector:
		numButtons += 32;

		// A real master pointer: Use official query for mouse devices.
		if (indevs->use == XIMasterPointer) {
			// Query pointer location and state:
			XIQueryPointer(dpy, indevs->deviceid, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mxd, &myd, &dxd, &dyd,
				       &buttons_return, &modifiers_return, &group_return);
		}

		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, mxd);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, myd);

		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int) numButtons, (int)1, &buttonArray);
		memset(buttonArray, 0, sizeof(double) * numButtons);

		if (numButtons > 0) {
			// Mouse buttons:
			const int buttonOffset = 1; // Buttons start at bit 1, not 0 for some strange reason? At least so on Ubuntu 10.10 and 11.10 with 2 mice and 1 joystick?
			for (i = buttonOffset; (i < numButtons - 32) && ((i / 8 ) < buttons_return.mask_len); i++) {
				buttonArray[i - buttonOffset] = (double) ((buttons_return.mask[i / 8] & (1 << (i % 8))) ? 1 : 0);
			}

			// Free mask if retrieved via XIQueryPointer():
			if (indevs->use == XIMasterPointer) free(buttons_return.mask);

			// Append modifier key state from associated master keyboard. Last 32 entries:
			for (i = 0; i < 32; i++) {
				buttonArray[numButtons - 32 + i] = (double) ((modifiers_return.effective & (1 << i)) ? 1 : 0);
			}
		}

		// Release live state info structure:
		XIFreeDeviceInfo(indevs);
	  }
	  else {
		// Old school core protocol query of virtual core pointer:
		XQueryPointer(dpy, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mx, &my, &dx, &dy, &mask_return);
	  
		// Copy out mouse x and y position:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) mx);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) my);
	  
		// Copy out mouse button state:
		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);

		// Bits 8, 9 and 10 of mask_return seem to correspond to mouse buttons
		// 1, 2 and 3 of a mouse for some weird reason. Bits 0-7 describe keyboard modifier keys
		// like Alt, Ctrl, Shift, ScrollLock, NumLock, CapsLock...
		// We remap here, so the first three returned entries correspond to the mouse buttons and
		// the rest is attached behind, if requested...
	  
		// Mouse buttons: Left, Middle, Right == 0, 1, 2, aka 1,2,3 in Matlab space...
		for (i=0; i<numButtons && i<3; i++) {
			buttonArray[i] = (mask_return & (1<<(i+8))) ? 1 : 0; 
		}
		// Modifier keys 0 to 7 appended:
		for (i=3; i<numButtons && i<3+8; i++) {
			buttonArray[i] = (mask_return & (1<<(i-3))) ? 1 : 0; 
		}
		// Everything else appended:
		for (i=11; i<numButtons; i++) {
			buttonArray[i] = (mask_return & (1<<i)) ? 1 : 0; 
		}
	  }

	  // Return optional 4th argument: Focus state. Returns 1 if our window has
	  // keyboard input focus, zero otherwise:
	  XGetInputFocus(dpy, &rootwin, &i);
	  PsychCopyOutDoubleArg(4, kPsychArgOptional, (double) (rootwin == mywin) ? 1 : 0);

	  // Return optional valuator values:
	  PsychCopyOutDoubleMatArg(5, kPsychArgOptional, (int) 1, (int) numvaluators, (int) 1, &myvaluators[0]);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Linux is available...

		// Special codes -10 to -15? --> Console keyboard queries:
		if(numButtons <= -10 && numButtons >= -15) {
			ConsoleInputHelper((int) numButtons);
			return(PsychError_none);
		}
		
	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode:

	    // Switch X-Server into synchronous mode: We need this to get
	    // a higher timing precision.
	    XSynchronize(dpy, TRUE);

	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current keyboard state from X-Server:
	      XQueryKeymap(dpy, keys_return);

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

	      // Any key down?
	      for (i=0; i<32; i++) keysdown+=(unsigned int) keys_return[i];
	      
	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a few milliseconds before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.01);
	    } while(1);

	    if (numButtons==-2) {
	      // Copy out time:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);
	      // copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      
	      // Copy keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Map 32 times 8 bitvector to 256 element return vector:
	      for(i=0; i<32; i++) {
				for(j=0; j<8; j++) {
		  			buttonStates[i*8 + j] = (PsychNativeBooleanType)(keys_return[i] & (1<<j)) ? 1 : 0;
				}
	      }
	    }
	  }
	  else if (numButtons == -3) {
	    // numButtons == -3 --> KbName mapping mode:
	    // Return the full keyboard keycode to ASCII character code mapping table...
	    PsychAllocOutCellVector(1, kPsychArgOptional, 256, &kbNames);

	    for(i=0; i<256; i++) {
	      // Map keyboard scan code to KeySym:
	      keystring = XKeysymToString(XKeycodeToKeysym(dpy, i, 0));
	      if (keystring) {
		// Character found: Return its ASCII name string:
		PsychSetCellVectorStringElement(i, keystring, kbNames);
	      }
	      else {
		// No character for this keycode:
		PsychSetCellVectorStringElement(i, "", kbNames);
	      }
	    }
	  }
	  else if (numButtons == -4) {
	    // GetChar() emulation.

/* 	    do { */
/* 	      // Fetch next keypress event from queue, block if none is available... */
/* 	      keystring = NULL; */
/* 	      XNextEvent(dpy, &event_return); */
/* 	      // Check for valid keypress event and extract character: */
/* 	      if (event_return.type == KeyPress) { */
/* 		keypressevent = (XKeyPressedEvent) event_return; */
/* 		keystring = NULL; */
/* 		keystring = XKeysymToString(XKeycodeToKeysym(dpy, keypressevent.keycode, 0)); */
/* 	      } */
/* 	      // Repeat until a valid char is returned. */
/* 	    } while (keystring == NULL); */

/* 	    // Copy out character: */
/* 	    PsychCopyOutCharArg(1, kPsychArgOptional, (char) keystring); */
/* 	    // Copy out time: */
/* 	    PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) keypressevent.time); */
	  }
	  else if (numButtons==-5) {
		// Priority() - helper mode: The 2nd argument is the priority level:

		// Query scheduling policy and priority:
		pthread_getschedparam(pthread_self(), &priorityLevel, &schedulingparam);

		// If scheduling mode is a realtime mode (RoundRobin realtime RR, or FIFO realtime),
		// then assign RT priority level (range 1-99) as current priorityLevel, otherwise
		// assign non realtime priority level zero:
		priorityLevel = (priorityLevel == SCHED_RR || priorityLevel == SCHED_FIFO) ? schedulingparam.sched_priority : 0;
        
		// Copy it out as optional return argument:
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) priorityLevel);
		
		// Query if a new level should be set:
		priorityLevel = -1;
		PsychCopyInIntegerArg(2, kPsychArgOptional, &priorityLevel);

		errno=0;
		// Priority level provided?
		if (priorityLevel > -1) {
			// Map to new scheduling class:
			if (priorityLevel > 99 || priorityLevel < 0) PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "Invalid Priority level: Requested Priority() level must be between zero and 99!");

			if (priorityLevel > 0) {
				// Realtime FIFO scheduling and all pages of Matlab/Octave locked into memory:
				schedulingparam.sched_priority = priorityLevel;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to enable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}
				else {
					// RT-Scheduling active. Lock all current and future memory:
					priorityLevel = mlockall(MCL_CURRENT | MCL_FUTURE);
					if (priorityLevel!=0) {
						// Failed! Report problem as warning, but don't worry further. 
	    					if(!PsychPrefStateGet_SuppressAllWarnings()) printf("PTB-WARNING: Failed to enable system memory locking with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						// Undo any possibly partial mlocks....
						munlockall();
						errno=0;
					}
				}
			}
			else {
				// Standard scheduling and no memory locking:
				schedulingparam.sched_priority = 0;
				priorityLevel = pthread_setschedparam(pthread_self(), SCHED_OTHER, &schedulingparam);
				if (priorityLevel == -1) {
					// Failed!
					if(!PsychPrefStateGet_SuppressAllWarnings()) {
	    					printf("PTB-ERROR: Failed to disable realtime-scheduling with Priority(%i) [%s]!\n", schedulingparam.sched_priority, strerror(errno));
						if (errno==EPERM) {
							printf("PTB-ERROR: You need to run Matlab/Octave with root-privileges, or run the script PsychLinuxConfiguration once for this to work.\n");
						}
					}
					errno=0;
				}

				munlockall();
				errno=0;
			}
			// End of setup of new Priority...
		}
		// End of Priority() helper for Linux.
	  }
	}	// End of special functions handling for Linux...
#endif
	return(PsychError_none);	
}
/* CHECKED
*  PsychARVideoCaptureRate() - Start- and stop video capture.
*
*  capturehandle = Grabber to start-/stop.
*  playbackrate = zero == Stop capture, non-zero == Capture
*  dropframes = 0 - Always deliver oldest frame in DMA ringbuffer. 1 - Always deliver newest frame.
*               --> 1 == drop frames in ringbuffer if behind -- low-latency capture.
*  startattime = Deadline (in system time) for which to wait before real start of capture.
*  Returns Number of dropped frames during capture.
*/
int PsychARVideoCaptureRate(int capturehandle, double capturerate, int dropframes, double* startattime)
{
	int dropped = 0;
	float framerate = 0;
	
	// Retrieve device record for handle:
	PsychVidcapRecordType* capdev = PsychGetARVidcapRecord(capturehandle);
	
	// Start- or stop capture?
	if (capturerate > 0) {
		// Start capture:
		if (capdev->grabber_active) PsychErrorExitMsg(PsychError_user, "You tried to start video capture, but capture is already started!");
		
		// Reset statistics:
		capdev->last_pts = -1.0;
		capdev->nr_droppedframes = 0;
		capdev->frame_ready = 0;
		
		// Framedropping is not supported by libARVideo, so we implement it ourselves.
		// Store the 'dropframes' flag in our capdev struct, so the PsychARGetTextureFromCapture()
		// knows how to handle this:
		capdev->dropframes = (dropframes > 0) ? 1 : 0;

		// Ready to go! Now we just need to tell the camera to start its capture cycle:
		
		// Wait until start deadline reached:
		if (*startattime != 0) PsychWaitUntilSeconds(*startattime);
		
		// Start DMA driven isochronous data transfer:
		if(PsychPrefStateGet_Verbosity()>5) printf("PTB-DEBUG: Starting capture...\n"); fflush(NULL);

		// Start the video capture for this camera.
		if (ar2VideoCapStart(capdev->camera) !=DC1394_SUCCESS) {
			// Failed!
			PsychErrorExitMsg(PsychError_user, "Unable to start capture on camera via ar2VideoCapStart() - Start of video capture failed!");
		}
		
		// Record real start time:
		PsychGetAdjustedPrecisionTimerSeconds(startattime);
		
		if(PsychPrefStateGet_Verbosity()>5) printf("PTB-DEBUG: Capture engine fully running...\n"); fflush(NULL);
		
		// Query framerate and convert to floating point value and assign it:
		#if PSYCH_SYSTEM == PSYCH_WINDOWS
		ar2VideoInqFreq(capdev->camera, &framerate);
		#else
		// TODO: Implement for non-Win32:
		framerate = (float) capturerate;
		#endif

		capdev->fps = (double) framerate;

		// Ok, capture is now started:
		capdev->grabber_active = 1;
		
		// Allocate conversion buffer if needed for YUV->RGB conversions.
		if (capdev->pixeldepth == -1) {
			// Not used at the moment!!
			// Software conversion of YUV -> RGB needed. Allocate a proper scratch-buffer:
			capdev->scratchbuffer = malloc(capdev->width * capdev->height * 3);
		}
		
		if(PsychPrefStateGet_Verbosity()>1) {
			printf("PTB-INFO: Capture started on device %i - Width x Height = %i x %i - Framerate: %f fps.\n", capturehandle, capdev->width, capdev->height, capdev->fps);
		}
	}
	else {
		// Stop capture:
		if (capdev->grabber_active) {
			// Stop isochronous data transfer from camera:
			if (ar2VideoCapStop(capdev->camera) !=DC1394_SUCCESS) {
				PsychErrorExitMsg(PsychError_user, "Unable to stop video transfer on camera! (ar2VideoCapStop() failed)!");
			}
			
			// Ok, capture is now stopped.
			capdev->frame_ready = 0;
			capdev->grabber_active = 0;
			
			if (capdev->scratchbuffer) {
				// Release scratch-buffer:
				free(capdev->scratchbuffer);
				capdev->scratchbuffer = NULL;
			}

			if(PsychPrefStateGet_Verbosity()>1){
				// Output count of dropped frames:
				if ((dropped=capdev->nr_droppedframes) > 0) {
					printf("PTB-INFO: Video capture dropped %i frames on device %i to keep capture running in sync with realtime.\n", dropped, capturehandle); 
				}
				
				if (capdev->nrframes>0) capdev->avg_decompresstime/= (double) capdev->nrframes;
				printf("PTB-INFO: Average time spent in video decompressor (waiting/polling for new frames) was %f milliseconds.\n", (float) capdev->avg_decompresstime * 1000.0f);
				if (capdev->nrgfxframes>0) capdev->avg_gfxtime/= (double) capdev->nrgfxframes;
				printf("PTB-INFO: Average time spent in GetCapturedImage (intensity calculation Video->OpenGL texture conversion) was %f milliseconds.\n",  (float) capdev->avg_gfxtime * 1000.0f);
			}
		}
	}
	
	fflush(NULL);
    
	// Reset framecounters and statistics:
	capdev->nrframes = 0;
	capdev->avg_decompresstime = 0;
	capdev->nrgfxframes = 0;
	capdev->avg_gfxtime = 0;
	
	// Return either the real capture framerate (at start of capture) or count of dropped frames - at end of capture.
	return((capturerate!=0) ? (int) (capdev->fps + 0.5) : dropped);
}
/* 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;
}
/*  PsychWaitForBufferswapPendingOrFinished()
 *  Waits until a bufferswap for window windowRecord has either already happened or
 *  bufferswap is certain.
 *  Input values:
 *  windowRecord struct of onscreen window to monitor.
 *  timestamp    = Deadline for abortion of flip detection at input.
 *
 *  Return values:
 *  timestamp    = System time at polling loop exit.
 *  beamposition = Beamposition at polling loop exit.
 *
 *  Return value: FALSE if swap happened already, TRUE if swap is imminent.
 */
bool PsychWaitForBufferswapPendingOrFinished(PsychWindowRecordType* windowRecord, double* timestamp, int *beamposition)
{
#if PSYCH_SYSTEM == PSYCH_OSX || PSYCH_SYSTEM == PSYCH_LINUX
    CGDirectDisplayID displayID;
	unsigned int primarySurface, secondarySurface;
	unsigned int updateStatus;
	double deadline = *timestamp;

	// If we are called, we know that 'windowRecord' is an onscreen window.
	int screenId = windowRecord->screenNumber;

    // Retrieve display id and screen size spec that is needed later...
    PsychGetCGDisplayIDFromScreenNumber(&displayID, screenId);

#define RADEON_D1GRPH_UPDATE	0x6144
#define RADEON_D2GRPH_UPDATE	0x6944
#define RADEON_SURFACE_UPDATE_PENDING 4
#define RADEON_SURFACE_UPDATE_TAKEN   8

	// Just need to check if GPU low-level access is supported:
	if (!PsychOSIsKernelDriverAvailable(screenId)) return;
	
	// Driver is online. Enter polling loop:
	while (TRUE) {
		// Read surface address registers:
		primarySurface   = PsychOSKDReadRegister(screenId, (screenId <=0 ) ? RADEON_D1GRPH_PRIMARY_SURFACE_ADDRESS : RADEON_D2GRPH_PRIMARY_SURFACE_ADDRESS, NULL);
		secondarySurface = PsychOSKDReadRegister(screenId, (screenId <=0 ) ? RADEON_D1GRPH_SECONDARY_SURFACE_ADDRESS : RADEON_D2GRPH_SECONDARY_SURFACE_ADDRESS, NULL);

		// Read update status registers:
		updateStatus     = PsychOSKDReadRegister(screenId, (screenId <=0 ) ? RADEON_D1GRPH_UPDATE : RADEON_D2GRPH_UPDATE, NULL);

		PsychGetAdjustedPrecisionTimerSeconds(timestamp);

		if (primarySurface!=windowRecord->gpu_preflip_Surfaces[0] || secondarySurface!=windowRecord->gpu_preflip_Surfaces[1] || (updateStatus & (RADEON_SURFACE_UPDATE_PENDING | RADEON_SURFACE_UPDATE_TAKEN)) || (*timestamp > deadline)) {
			// Abort condition: Exit loop.
			break;
		}
		
		if (PsychPrefStateGet_Verbosity() > 9) {
			printf("PTB-DEBUG: Head %i: primarySurface=%p : secondarySurface=%p : updateStatus=%i\n", ((screenId <=0) ? 0:1), primarySurface, secondarySurface, updateStatus);
		}

		// Sleep 200 microseconds, then retry:
		PsychWaitIntervalSeconds(0.0002);
	};
	
	// Take timestamp and beamposition:
	*beamposition = PsychGetDisplayBeamPosition(&displayID, screenId);
	PsychGetAdjustedPrecisionTimerSeconds(timestamp);

	// Exit due to timeout?
	if (*timestamp > deadline) {
		// Mark timestamp as invalid due to timeout:
		*timestamp = -1;
	}
	
	// Return FALSE if bufferswap happened already, TRUE if swap is still pending:
	return((updateStatus & RADEON_SURFACE_UPDATE_PENDING) ? TRUE : FALSE);
#else
	// On Windows, we always return "swap happened":
	return(FALSE);
#endif
}
/* 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;
}
/* CHECKED TODO
*  PsychARGetTextureFromCapture() -- Create an OpenGL texturemap from a specific videoframe from given capture object.
*
*  win = Window pointer of onscreen window for which a OpenGL texture should be created.
*  capturehandle = Handle to the capture object.
*  checkForImage = >0 == Just check if new image available, 0 == really retrieve the image, blocking if necessary.
*                   2 == Check for new image, block inside this function (if possible) if no image available.
*
*  timeindex = This parameter is currently ignored and reserved for future use.
*  out_texture = Pointer to the Psychtoolbox texture-record where the new texture should be stored.
*  presentation_timestamp = A ptr to a double variable, where the presentation timestamp of the returned frame should be stored.
*  summed_intensity = An optional ptr to a double variable. If non-NULL, then sum of intensities over all channels is calculated and returned.
*  outrawbuffer = An optional ptr to a memory buffer of sufficient size. If non-NULL, the buffer will be filled with the captured raw image data, e.g., for use inside Matlab or whatever...
*  Returns Number of pending or dropped frames after fetch on success (>=0), -1 if no new image available yet, -2 if no new image available and there won't be any in future.
*/
int PsychARGetTextureFromCapture(PsychWindowRecordType *win, int capturehandle, int checkForImage, double timeindex,
								 PsychWindowRecordType *out_texture, double *presentation_timestamp, double* summed_intensity, rawcapimgdata* outrawbuffer)
{
    GLuint texid;
    int w, h;
    double targetdelta, realdelta, frames;
    unsigned int intensity = 0;
    unsigned int count, i, bpp;
    unsigned char* pixptr;
    psych_bool newframe = FALSE;
    double tstart, tend;
    unsigned int pixval, alphacount;
    int error;
    int nrdropped = 0;
    unsigned char* input_image = NULL;
	
    // Retrieve device record for handle:
    PsychVidcapRecordType* capdev = PsychGetARVidcapRecord(capturehandle);
	
	// Compute width and height for later creation of textures etc. Need to do this here,
	// so we can return the values for raw data retrieval:
	w=capdev->width;
    h=capdev->height;

	// Size of a single pixel in bytes:
	bpp = capdev->reqpixeldepth;
	
	// If a outrawbuffer struct is provided, we fill it with info needed to allocate a
	// sufficient memory buffer for returned raw image data later on:
	if (outrawbuffer) {
		outrawbuffer->w = w;
		outrawbuffer->h = h;
		outrawbuffer->depth = bpp;
	}
	
    // int waitforframe = (checkForImage > 1) ? 1:0; // Blocking wait for new image requested?
	
	// A checkForImage 4 means "no op" with the ARVideo capture engine: This is meant to drive
	// a movie recording engine, ie., grant processing time to it. Our ARVideo engine doesn't
	// support movie recording, so this is a no-op:
	if (checkForImage == 4) return(0);

    // Take start timestamp for timing stats:
    PsychGetAdjustedPrecisionTimerSeconds(&tstart);
	
    // Should we just check for new image?
    if (checkForImage) {
		// Reset current dropped count to zero:
		capdev->current_dropped = 0;
        
		if (capdev->grabber_active == 0) {
			// Grabber stopped. We'll never get a new image:
			return(-2);
		}
		
		// Check for image in polling mode: We capture in non-blocking mode:			
		capdev->frame = ar2VideoGetImage(capdev->camera);

		// Ok, call succeeded. If the 'frame' pointer is non-NULL then there's a new frame ready and dequeued from DMA
		// ringbuffer. We'll return it on next non-poll invocation. Otherwise no new video data ready yet:
		capdev->frame_ready = (capdev->frame != NULL) ? 1 : 0;

		
		if (capdev->frame_ready) {
			// Store count of currently queued frames (in addition to the one just fetched).
			// This is an indication of how well the users script is keeping up with the video stream,
			// technically the number of frames that would need to be dropped to keep in sync with the
			// stream.
			// TODO: Think about this. ARVideo doesn't support a query for pending/dropped frames, so
			// we either need to live without this feature or think up something clever...
			capdev->current_dropped = (int) 0;
			
			// Ok, at least one new frame ready. If more than one frame has queued up and
			// we are in 'dropframes' mode, ie. we should always deliver the most recent available
			// frame, then we quickly fetch & discard all queued frames except the last one.
			while((capdev->dropframes) && ((int) capdev->current_dropped > 0)) {
				// We just poll - fetch the frames. As we know there are some queued frames, it
				// doesn't matter if we poll or block, but polling sounds like a bit less overhead
				// at the OS level:
				
				// First enqueue the recently dequeued buffer...
				if (ar2VideoCapNext(capdev->camera) != DC1394_SUCCESS) {
					PsychErrorExitMsg(PsychError_system, "Requeuing of discarded video frame failed while dropping frames (dropframes=1)!!!");
				}
				
				// Then fetch the next one:
				if ((capdev->frame = ar2VideoGetImage(capdev->camera)) == NULL) {
					// Polling failed for some reason...
					PsychErrorExitMsg(PsychError_system, "Polling for new video frame failed while dropping frames (dropframes=1)!!!");
				}
				
			}
			
			// Update stats for decompression:
			PsychGetAdjustedPrecisionTimerSeconds(&tend);
			
			// Increase counter of decompressed frames:
			capdev->nrframes++;
			
			// Update avg. decompress time:
			capdev->avg_decompresstime+=(tend - tstart);
			
			// Query capture timestamp in seconds:
			// TODO: ARVideo doesn't provide such a timestamp. For now we just return the current
			// system time as a lame replacement...
			// On Windows there would be uint64 capdev->camera->g_Timestamp
			PsychGetAdjustedPrecisionTimerSeconds(&(capdev->current_pts));
		}

		// Return availability status: 0 = new frame ready for retrieval. -1 = No new frame ready yet.
		return((capdev->frame_ready) ? 0 : -1);
    }
    
    // This point is only reached if checkForImage == FALSE, which only happens
    // if a new frame is available in our buffer:
    
    // Presentation timestamp requested?
    if (presentation_timestamp) {
		// Return it:
		*presentation_timestamp = capdev->current_pts;
    }
	
    // Synchronous texture fetch: Copy content of capture buffer into a texture:
    // =========================================================================
	
    // input_image points to the image buffer in our cam:
    input_image = (unsigned char*) (capdev->frame);
	
    // Do we want to do something with the image data and have a
    // scratch buffer for color conversion alloc'ed?
    if ((capdev->scratchbuffer) && ((out_texture) || (summed_intensity) || (outrawbuffer))) {
		// Yes. Perform color-conversion YUV->RGB from cameras DMA buffer
		// into the scratch buffer and set scratch buffer as source for
		// all further operations:

		memcpy(capdev->scratchbuffer, input_image, capdev->width * capdev->height * bpp);
		
		// Ok, at this point we should have a RGB8 texture image ready in scratch_buffer.
		// Set scratch buffer as our new image source for all further processing:
		input_image = (unsigned char*) capdev->scratchbuffer;
    }
	
    // Only setup if really a texture is requested (non-benchmarking mode):
    if (out_texture) {
		PsychMakeRect(out_texture->rect, 0, 0, w, h);    
		
		// Set NULL - special texture object as part of the PTB texture record:
		out_texture->targetSpecific.QuickTimeGLTexture = NULL;
		
		// Set texture orientation as if it were an inverted Offscreen window: Upside-down.
		out_texture->textureOrientation = 3;
		
		#if PSYCH_SYSTEM == PSYCH_WINDOWS
		// On Windows in non RGB32 bit modes, set orientation to Upright:
		out_texture->textureOrientation = (capdev->reqpixeldepth == 4) ? 3 : 2;
		#endif

		// Setup a pointer to our buffer as texture data pointer: Setting memsize to zero
		// prevents unwanted free() operation in PsychDeleteTexture...
		out_texture->textureMemorySizeBytes = 0;
		
		// Set texture depth: Could be 8, 16, 24 or 32 bpp.
		out_texture->depth = capdev->reqpixeldepth * 8;
		
		// This will retrieve an OpenGL compatible pointer to the pixel data and assign it to our texmemptr:
		out_texture->textureMemory = (GLuint*) input_image;
		
		// Let PsychCreateTexture() do the rest of the job of creating, setting up and
		// filling an OpenGL texture with content:
		PsychCreateTexture(out_texture);
		
		// Ready to use the texture...
    }
    
    // Sum of pixel intensities requested?
    if(summed_intensity) {
		pixptr = (unsigned char*) input_image;
		count  = w * h * bpp;
		for (i=0; i<count; i++) intensity+=(unsigned int) pixptr[i];
		*summed_intensity = ((double) intensity) / w / h / bpp;
    }
	
	// Raw data requested?
	if (outrawbuffer) {
		// Copy it out:
		outrawbuffer->w = w;
		outrawbuffer->h = h;
		outrawbuffer->depth = bpp;
		count = (w * h * outrawbuffer->depth);
		memcpy(outrawbuffer->data, (const void *) input_image, count);
	}
	
    // Release the capture buffer. Return it to the DMA ringbuffer pool:
	if (ar2VideoCapNext(capdev->camera) != DC1394_SUCCESS) {
		PsychErrorExitMsg(PsychError_system, "Re-Enqueuing processed video frame failed.");
	}

    // Update total count of dropped (or pending) frames:
    capdev->nr_droppedframes += capdev->current_dropped;
    nrdropped = capdev->current_dropped;
    capdev->current_dropped = 0;
	
    // Timestamping:
    PsychGetAdjustedPrecisionTimerSeconds(&tend);
	
    // Increase counter of retrieved textures:
    capdev->nrgfxframes++;
	
    // Update average time spent in texture conversion:
    capdev->avg_gfxtime+=(tend - tstart);
    
    // We're successfully done! Return number of dropped (or pending in DMA ringbuffer) frames:
    return(nrdropped);
}
PsychError SCREENGetMouseHelper(void) 
{
#if PSYCH_SYSTEM == PSYCH_OSX
	Point		mouseXY;
	UInt32		buttonState;
	double		numButtons, *buttonArray;
	int		i;
	boolean		doButtonArray;
	
	
	//all subfunctions should have these two lines.  
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
	
	//cap the numbers of inputs and outputs
	PsychErrorExit(PsychCapNumInputArgs(1));   //The maximum number of inputs
	PsychErrorExit(PsychCapNumOutputArgs(3));  //The maximum number of outputs
	
	//Buttons.  
	// The only way I know to detect the  number number of mouse buttons is directly via HID.  The device reports
	//that information but OS X seems to ignore it above the level of the HID driver, that is, no OS X API above the HID driver
	//exposes it.  So GetMouse.m function calls PsychHID detect the number of buttons and then passes that value to GetMouseHelper 
	//which returns that number of button values in a vector.      
	PsychCopyInDoubleArg(1, kPsychArgRequired, &numButtons);
	if(numButtons > 32)
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must not exceed 32");
	if(numButtons < 1) 
		PsychErrorExitMsg(PsychErorr_argumentValueOutOfRange, "numButtons must exceed 1");
	doButtonArray=PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);
	if(doButtonArray){
		buttonState=GetCurrentButtonState();
		for(i=0;i<numButtons;i++)
			buttonArray[i]=(double)(buttonState & (1<<i));
	}
			
	//cursor position
	GetMouse(&mouseXY);
	PsychCopyOutDoubleArg(1, kPsychArgOptional, (double)mouseXY.h);
	PsychCopyOutDoubleArg(2, kPsychArgOptional, (double)mouseXY.v);
#endif

#if PSYCH_SYSTEM == PSYCH_WINDOWS
	static unsigned char disabledKeys[256];
	static unsigned char firsttime = 1;
	int keysdown, i;
	unsigned char keyState[256];
	double* buttonArray;
	double numButtons, timestamp;
	PsychNativeBooleanType* buttonStates;
	POINT		point;
	PsychPushHelp(useString, synopsisString, seeAlsoString);
	if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};

	// Retrieve optional number of mouse buttons:
	numButtons = 0;
	PsychCopyInDoubleArg(1, FALSE, &numButtons);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
		// GetMouse-Mode: Return mouse button states and mouse cursor position:

		PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)3, (int)1, &buttonArray);
		// Query and return mouse button state:
		PsychGetMouseButtonState(buttonArray);
		// Query and return cursor position in global coordinates:
		GetCursorPos(&point);
		PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) point.x);
		PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) point.y);
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Microsoft Windows is available...

	  if (firsttime) {
			// First time init:
			firsttime = 0;
			memset(keyState, 0, sizeof(keyState));
			memset(disabledKeys, 0, sizeof(disabledKeys));
			// These keycodes are always disabled: 0, 255:
			disabledKeys[0]=1;
			disabledKeys[255]=1;
			// Mouse buttone (left, right, middle) are also disabled by default:
			disabledKeys[1]=1;
			disabledKeys[2]=1;
			disabledKeys[4]=1;
	  }

	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode
	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

			// Query state of all keys:
			for(i=1;i<255;i++){
				keyState[i] = (GetAsyncKeyState(i) & -32768) ? 1 : 0;
			}

	      // Disable all keys that are registered in disabledKeys. Check if
			// any non-disabled key is down.
	      for (i=0; i<256; i++) {
				if (disabledKeys[i]>0) keyState[i] = 0;
				keysdown+=(unsigned int) keyState[i];
	      }

	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a millisecond before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.001);

	    } while(1);

	    if (numButtons==-2) {
	      // KbWait mode: Copy out time value.
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);

	      // Copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      

	      // Copy out keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Build 256 elements return vector:
	      for(i=0; i<255; i++) {
		  		buttonStates[i] = (PsychNativeBooleanType)((keyState[i+1]) ? 1 : 0);
	      }
			// Special case: Null out last element:
			buttonStates[255] = (PsychNativeBooleanType) 0;
	    }
	  }
	}
#endif
	
#if PSYCH_SYSTEM == PSYCH_LINUX
	unsigned char keys_return[32];
	char* keystring;
	PsychGenericScriptType *kbNames;
	CGDirectDisplayID dpy;
	Window rootwin, childwin;
	int i, j, mx, my, dx, dy;
	unsigned int mask_return;
	double numButtons, timestamp;
	double* buttonArray;
	PsychNativeBooleanType* buttonStates;
	int keysdown;
	XEvent event_return;
	XKeyPressedEvent keypressevent;
	int screenNumber;

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

	PsychCopyInDoubleArg(1, kPsychArgRequired, &numButtons);

	// Retrieve optional screenNumber argument:
	screenNumber = 0;
	PsychCopyInScreenNumberArg(2, FALSE, &screenNumber);

	// Map screenNumber to X11 display handle and screenid:
	PsychGetCGDisplayIDFromScreenNumber(&dpy, screenNumber);

	// Are we operating in 'GetMouseHelper' mode? numButtons>=0 indicates this.
	if (numButtons>=0) {
	  // Mouse pointer query mode:
	  XQueryPointer(dpy, RootWindow(dpy, PsychGetXScreenIdForScreen(screenNumber)), &rootwin, &childwin, &mx, &my, &dx, &dy, &mask_return);
	  
	  // Copy out mouse x and y position:
	  PsychCopyOutDoubleArg(1, kPsychArgOptional, (double) mx);
	  PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) my);
	  
	  // Copy out mouse button state:
	  PsychAllocOutDoubleMatArg(3, kPsychArgOptional, (int)1, (int)numButtons, (int)1, &buttonArray);

	  // Bits 8, 9 and 10 of mask_return seem to correspond to mouse buttons
	  // 1, 2 and 3 of a mouse for some weird reason. Bits 0-7 describe keyboard modifier keys
	  // like Alt, Ctrl, Shift, ScrollLock, NumLock, CapsLock...
	  // We remap here, so the first three returned entries correspond to the mouse buttons and
	  // the rest is attached behind, if requested...
	  
	  // Mouse buttons: Left, Middle, Right == 0, 1, 2, aka 1,2,3 in Matlab space...
	  for (i=0; i<numButtons && i<3; i++) {
	    buttonArray[i] = (mask_return & (1<<(i+8))) ? 1 : 0; 
	  }
	  // Modifier keys 0 to 7 appended:
	  for (i=3; i<numButtons && i<3+8; i++) {
	    buttonArray[i] = (mask_return & (1<<(i-3))) ? 1 : 0; 
	  }
	  // Everything else appended:
	  for (i=11; i<numButtons; i++) {
	    buttonArray[i] = (mask_return & (1<<i)) ? 1 : 0; 
	  }
	}
	else {
	  // 'KeyboardHelper' mode: We implement either KbCheck() or KbWait() via X11.
	  // This is a hack to provide keyboard queries until a PsychHID() implementation
	  // for Linux is available...

	  if (numButtons==-1 || numButtons==-2) {
	    // KbCheck()/KbWait() mode:

	    // Switch X-Server into synchronous mode: We need this to get
	    // a higher timing precision.
	    XSynchronize(dpy, TRUE);

	    do {
	      // Reset overall key state to "none pressed":
	      keysdown=0;

	      // Request current keyboard state from X-Server:
	      XQueryKeymap(dpy, keys_return);

	      // Request current time of query:
	      PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

	      // Any key down?
	      for (i=0; i<32; i++) keysdown+=(unsigned int) keys_return[i];
	      
	      // We repeat until any key pressed if in KbWait() mode, otherwise we
	      // exit the loop after first iteration in KbCheck mode.
	      if ((numButtons==-1) || ((numButtons==-2) && (keysdown>0))) break;

	      // Sleep for a few milliseconds before next KbWait loop iteration:
	      PsychWaitIntervalSeconds(0.01);
	    } while(1);

	    if (numButtons==-2) {
	      // Copy out time:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, timestamp);
	    }
	    else {
	      // KbCheck mode:
	      
	      // Copy out overall keystate:
	      PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown>0) ? 1 : 0);
	      // copy out timestamp:
	      PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);	      
	      // Copy keyboard state:
	      PsychAllocOutBooleanMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);

	      // Map 32 times 8 bitvector to 256 element return vector:
	      for(i=0; i<32; i++) {
				for(j=0; j<8; j++) {
		  			buttonStates[i*8 + j] = (PsychNativeBooleanType)(keys_return[i] & (1<<j)) ? 1 : 0;
				}
	      }
	    }
	  }
	  else if (numButtons == -3) {
	    // numButtons == -3 --> KbName mapping mode:
	    // Return the full keyboard keycode to ASCII character code mapping table...
	    PsychAllocOutCellVector(1, kPsychArgOptional, 256, &kbNames);

	    for(i=0; i<256; i++) {
	      // Map keyboard scan code to KeySym:
	      keystring = XKeysymToString(XKeycodeToKeysym(dpy, i, 0));
	      if (keystring) {
		// Character found: Return its ASCII name string:
		PsychSetCellVectorStringElement(i, keystring, kbNames);
	      }
	      else {
		// No character for this keycode:
		PsychSetCellVectorStringElement(i, "", kbNames);
	      }
	    }
	  }
	  else if (numButtons == -4) {
	    // GetChar() emulation.

/* 	    do { */
/* 	      // Fetch next keypress event from queue, block if none is available... */
/* 	      keystring = NULL; */
/* 	      XNextEvent(dpy, &event_return); */
/* 	      // Check for valid keypress event and extract character: */
/* 	      if (event_return.type == KeyPress) { */
/* 		keypressevent = (XKeyPressedEvent) event_return; */
/* 		keystring = NULL; */
/* 		keystring = XKeysymToString(XKeycodeToKeysym(dpy, keypressevent.keycode, 0)); */
/* 	      } */
/* 	      // Repeat until a valid char is returned. */
/* 	    } while (keystring == NULL); */

/* 	    // Copy out character: */
/* 	    PsychCopyOutCharArg(1, kPsychArgOptional, (char) keystring); */
/* 	    // Copy out time: */
/* 	    PsychCopyOutDoubleArg(2, kPsychArgOptional, (double) keypressevent.time); */
	  }
	}
#endif
	return(PsychError_none);	
}
// This is the event dequeue & process function which updates
// Keyboard queue state. It can be called with 'blockingSinglepass'
// set to TRUE to process exactly one event, if called from the
// background keyboard queue processing thread. Alternatively it
// can be called synchronously from KbQueueCheck with a setting of FALSE
// to iterate over all available events and process them instantaneously:
void KbQueueProcessEvents(psych_bool blockingSinglepass)
{
    LPDIRECTINPUTDEVICE8 kb;
    DIDEVICEOBJECTDATA event;
    HRESULT rc;
    DWORD dwItems;
    double tnow;
    unsigned int i, keycode, keystate;
    PsychHIDEventRecord evt;
    WORD asciiValue[2];
    UCHAR keyboardState[256];

    while (1) {
        // Single pass or multi-pass?
        if (blockingSinglepass) {
            // Wait until at least one event available and dequeue it:
            // We use a timeout of 100 msecs.
            WaitForSingleObject(hEvent, 100);
        } else {
            // Check if event available, dequeue it, if so. Abort
            // processing if no new event available, aka queue empty:
            // TODO if (!XCheckTypedEvent(thread_dpy, GenericEvent, &KbQueue_xevent)) break;
        }

        // Take timestamp:
        PsychGetAdjustedPrecisionTimerSeconds(&tnow);

        // Need the lock from here on:
        PsychLockMutex(&KbQueueMutex);

        // Do a sweep over all keyboard devices whose queues are active:
        for (i = 0; i < (unsigned int) ndevices; i++) {
            // Skip this one if inactive:
            if (!psychHIDKbQueueActive[i]) continue;

            // Check this device:
            kb = GetXDevice(i);

            // Fetch one item from the buffer:
            // event.dwTimeStamp = Timestamp in msecs of timeGetTime() timebase.
            // event.dwSequence = Sequence number.

            // Fetch from this device, item-by-item, until nothing more to fetch:
            while (TRUE) {
                // Try one fetch from this device:
                dwItems = 1;
                rc = kb->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &event, &dwItems, 0);

                // If failed or nothing more to fetch, break out of fetch loop:
                if (!SUCCEEDED(rc) || (0 == dwItems)) break;

                // Clear ringbuffer event:
                memset(&evt, 0 , sizeof(evt));

                // Init character code to "unmapped": It will stay like that for anything but real keyboards:
                evt.cookedEventCode = -1;

                // Map to key code and key state:
                keycode = event.dwOfs & 0xff;
                keystate = event.dwData & 0x80;

                // Remap keycode into target slot in our arrays, depending on input device:
                switch (info[i].dwDevType & 0xff) {
                case DI8DEVTYPE_KEYBOARD:
                    // Try to map scancode to ascii character:
                    memset(keyboardState, 0, sizeof(keyboardState));
                    if (GetAsyncKeyState(VK_SHIFT)) keyboardState[VK_SHIFT] = 0xff;

                    if ((1 == ToAsciiEx(MapVirtualKeyEx(keycode, 1, GetKeyboardLayout(0)), keycode, keyboardState, (LPWORD) &(asciiValue[0]), 0, GetKeyboardLayout(0)))) {
                        // Mapped to single char: Return it as cooked keycode:
                        evt.cookedEventCode = (int) (asciiValue[0] & 0xff);
                    }
                    else {
                        // Could not map key to valid ascii character: Mark as "not mapped" aka zero:
                        evt.cookedEventCode = 0;
                    }

                    // Map scancode 'keycode' to virtual key code 'keycode':
                    keycode = PsychHIDOSMapKey(keycode);
                    break;

                case DI8DEVTYPE_MOUSE:
                case DI8DEVTYPE_SCREENPOINTER:
                    // Button event? Otherwise skip it.
                    if (keycode < 3 * sizeof(LONG)) continue;
                    // Correct for buttons offset in data structure DIMOUSESTATE2:
                    keycode -= 3 * sizeof(LONG);
                    break;

                case DI8DEVTYPE_JOYSTICK:
                    // Button event? Otherwise skip it.
                    if (keycode < (8 * sizeof(LONG) + 4 * sizeof(DWORD))) continue;
                    // Correct for buttons offset in data structure DIJOYSTATE2:
                    keycode -= (8 * sizeof(LONG) + 4 * sizeof(DWORD));
                    // Also skip if beyond button array:
                    if (keycode >= 128) continue;
                    break;

                default: // Unkown device -- Skip it.
                    continue;
                }

                // This keyboard queue interested in this keycode?
                if (psychHIDKbQueueScanKeys[i][keycode] != 0) {
                    // Yes: The queue wants to receive info about this key event.

                    // Press or release?
                    if (keystate) {
                        // Enqueue key press. Always in the "last press" array, because any
                        // press at this time is the best candidate for the last press.
                        // Only enqeue in "first press" if there wasn't any registered before,
                        // ie., the slot is so far empty:
                        if (psychHIDKbQueueFirstPress[i][keycode] == 0) psychHIDKbQueueFirstPress[i][keycode] = tnow;
                        psychHIDKbQueueLastPress[i][keycode] = tnow;
                        evt.status |= (1 << 0);
                    } else {
                        // Enqueue key release. See logic above:
                        if (psychHIDKbQueueFirstRelease[i][keycode] == 0) psychHIDKbQueueFirstRelease[i][keycode] = tnow;
                        psychHIDKbQueueLastRelease[i][keycode] = tnow;
                        evt.status &= ~(1 << 0);
                        // Clear cooked keycode - We don't record key releases this way:
                        if (evt.cookedEventCode > 0) evt.cookedEventCode = 0;
                    }

                    // Update event buffer:
                    evt.timestamp = tnow;
                    evt.rawEventCode = keycode + 1;
                    PsychHIDAddEventToEventBuffer(i, &evt);

                    // Tell waiting userspace (under KbQueueMutex protection for better scheduling) something interesting has changed:
                    PsychSignalCondition(&KbQueueCondition);
                }
                // Next fetch iteration for this device...
            }
            // Check next device...
        }

        // Done with shared data access:
        PsychUnlockMutex(&KbQueueMutex);

        // Done if we were only supposed to handle one sweep, which we did:
        if (blockingSinglepass) break;
    }

    return;
}
PsychError PsychHIDOSKbCheck(int deviceIndex, double* scanList)
{
    psych_uint8 keys[1024];
    LPDIRECTINPUTDEVICE8 kb;
    unsigned int i, j;
    double* buttonStates;
    int keysdown;
    double timestamp;
    DWORD cbSize;

    if (deviceIndex == INT_MAX) {
        deviceIndex = PsychHIDGetDefaultKbQueueDevice();
        // Ok, deviceIndex now contains our default keyboard to use - The first suitable keyboard.
    }

    if ((deviceIndex < 0) || (deviceIndex >= ndevices)) {
        // Out of range index:
        PsychErrorExitMsg(PsychError_user, "Invalid 'deviceIndex' specified. No such device!");
    }

    // Get DirectInput keyboard device:
    kb = GetXDevice(deviceIndex);

    // Keyboard queue for this deviceIndex already exists?
    if (NULL == psychHIDKbQueueFirstPress[deviceIndex]) {
        // No. Create one which accepts all keys:
        PsychHIDOSKbQueueCreate(deviceIndex, 0, NULL);
    }

    // Keyboard queue for this device active? If not, we need
    // to start it:
    if (!psychHIDKbQueueActive[deviceIndex]) {
        // Keyboard idle: Need to start it:
        PsychHIDOSKbQueueStart(deviceIndex);

        // Startup to first key delivery takes time. Wait for
        // 50 msecs to be on the safe side:
        PsychYieldIntervalSeconds(0.050);
    }

    // Size of state structure is device dependent:
    switch (info[deviceIndex].dwDevType & 0xff) {
    case DI8DEVTYPE_KEYBOARD:
        cbSize = 256;
        break;

    case DI8DEVTYPE_MOUSE:
    case DI8DEVTYPE_SCREENPOINTER:
        cbSize = sizeof(DIMOUSESTATE2);
        break;

    case DI8DEVTYPE_JOYSTICK:
        cbSize = sizeof(DIJOYSTATE2);
        break;

    default: // Unkown device. Fail.
        cbSize = 0;
    }


    // Query current state snapshot of keyboard:
    memset(keys, 0, sizeof(keys));
    if (DI_OK != kb->GetDeviceState(cbSize, (LPVOID) &keys[0])) {
        printf("PsychHID-ERROR: KbCheck for deviceIndex %i failed, because query of device failed!\n", deviceIndex);
        PsychErrorExitMsg(PsychError_user, "KbCheck failed!");
    }

    // Request current time of query:
    PsychGetAdjustedPrecisionTimerSeconds(&timestamp);

    // Reset overall key state to "none pressed":
    keysdown = 0;

    // Copy out timestamp:
    PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp);

    // Copy keyboard state:
    PsychAllocOutDoubleMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates);
    for (i = 0; i < 256; i++) buttonStates[i] = 0;

    // Keyboard?
    if (cbSize == 256) {
        // Copy button state to output vector, apply scanlist mask, compute
        // resulting overall keysdown state. We ignore keyboard scancode zero and
        // start with 1 instead. We also ignore code 255. These are borderline codes
        // which may do weird things...
        for (i = 1; i < 255; i++) {
            // Compute target key slot for this scancode i:
            j = PsychHIDOSMapKey(i);

            // This key down?
            buttonStates[j] += (keys[i] > 0) ? 1 : 0;
            // Apply scanList mask, if any provided:
            if (scanList && (scanList[j] <= 0)) buttonStates[j] = 0;
            keysdown += (unsigned int) buttonStates[j];
        }
    }

    // Joystick?
    if (cbSize == sizeof(DIJOYSTATE2)) {
        // Copy button state to output vector, apply scanlist mask, compute
        // resulting overall keysdown state. There are 128 buttons at an offset:
        for (i = (8 * sizeof(LONG) + 4 * sizeof(DWORD)); i < (8 * sizeof(LONG) + 4 * sizeof(DWORD)) + 128; i++) {
            // Compute target key slot for this scancode i:
            j = i - (8 * sizeof(LONG) + 4 * sizeof(DWORD));

            // This key down?
            buttonStates[j] += (keys[i] > 0) ? 1 : 0;
            // Apply scanList mask, if any provided:
            if (scanList && (scanList[j] <= 0)) buttonStates[j] = 0;
            keysdown += (unsigned int) buttonStates[j];
        }
    }

    // Mouse?
    if (cbSize == sizeof(DIMOUSESTATE2)) {
        // Copy button state to output vector, apply scanlist mask, compute
        // resulting overall keysdown state. There are 8 buttons at an offset:
        for (i = (3 * sizeof(LONG)); i < (3 * sizeof(LONG)) + 8; i++) {
            // Compute target key slot for this scancode i:
            j = i - (3 * sizeof(LONG));

            // This key down?
            buttonStates[j] += (keys[i] > 0) ? 1 : 0;
            // Apply scanList mask, if any provided:
            if (scanList && (scanList[j] <= 0)) buttonStates[j] = 0;
            keysdown += (unsigned int) buttonStates[j];
        }
    }

    // Copy out overall keystate:
    PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown > 0) ? 1 : 0);

    return(PsychError_none);
}
PsychError SCREENWaitBlanking(void) 
{
    PsychWindowRecordType *windowRecord;
    int waitFrames, framesWaited;
    double tvbl, ifi;
    long screenwidth, screenheight;
    int vbl_startline, beampos, lastline;
    psych_uint64 vblCount, vblRefCount;
    CGDirectDisplayID	cgDisplayID;
    GLint read_buffer, draw_buffer;
    
    // All subfunctions should have these two lines.  
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(2));     //The maximum number of inputs
    PsychErrorExit(PsychRequireNumInputArgs(1)); //The required number of inputs	
    PsychErrorExit(PsychCapNumOutputArgs(1));    //The maximum number of outputs
    
    // Get the window record from the window record argument and get info from the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    
    if(!PsychIsOnscreenWindow(windowRecord))
        PsychErrorExitMsg(PsychError_user, "Tried to call 'WaitBlanking' on something else than an onscreen window!");
    
    // Get the number of frames to wait:
    waitFrames = 0;
    PsychCopyInIntegerArg(2, FALSE, &waitFrames);

	// We default to wait at least one interval if no argument supplied:
    waitFrames = (waitFrames < 1) ? 1 : waitFrames;
    
    // Enable this windowRecords framebuffer as current drawingtarget:
    // This is needed to make sure that Offscreen windows work propely.
    PsychSetDrawingTarget(windowRecord);
    
    // Retrieve display handle for beamposition queries:
    PsychGetCGDisplayIDFromScreenNumber(&cgDisplayID, windowRecord->screenNumber);
    
    // Retrieve final vbl_startline, aka physical height of the display in pixels:
    PsychGetScreenSize(windowRecord->screenNumber, &screenwidth, &screenheight);
    vbl_startline = (int) screenheight;
    
    // Query duration of a monitor refresh interval: We try to use the measured interval,
	// but fallback of the nominal value reported by the operating system if necessary:
    if ((ifi = windowRecord->VideoRefreshInterval)<=0) {
        if (PsychGetNominalFramerate(windowRecord->screenNumber) > 0) {
            // Valid nominal framerate returned by OS: Calculate nominal IFI from it.
            ifi = 1.0 / ((double) PsychGetNominalFramerate(windowRecord->screenNumber));        
        }
        else {
            // No reasonable value available! We fallback to an assumed 60 Hz refresh...
            ifi = 1.0 / 60.0;
        }
    }
    
    // Query vblcount to test if this method works correctly:
    PsychOSGetVBLTimeAndCount(windowRecord, &vblRefCount);
    
    // Check if beamposition queries are supported by this OS and working properly:
    if (-1 != PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber) && windowRecord->VBL_Endline >= 0) {
        // Beamposition queries supported and fine. We can wait for VBL without bufferswap-tricks:
        // This is the OS-X way of doing things. We query the rasterbeamposition and compare it
        // to the known values for the VBL area. If we enter VBL, we take a timestamp and return -
        // or wait for the next VBL if waitFrames>0
        
        // Query current beamposition when entering WaitBlanking:
        beampos = PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber);
        // Are we in VBL when entering WaitBlanking? If so, we should wait for one additional frame,
        // because by definition, WaitBlanking should always wait for at least one monitor refresh
        // interval...
        if ((beampos<=windowRecord->VBL_Endline) && (beampos>=vbl_startline)) waitFrames++;
        
        while(waitFrames > 0) {
            // Enough time for a sleep? If the beam is far away from VBL area, we try to sleep to
            // yield some CPU time to other processes in the system -- we are nice citizens ;)
            beampos = PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber);
            while (( ((float)(vbl_startline - beampos)) / (float) windowRecord->VBL_Endline * ifi) > 0.003) {
                // At least 3 milliseconds left until retrace. We sleep for 1 millisecond.
                PsychWaitIntervalSeconds(0.001);
                beampos = PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber);
            }
            
            // Less than 3 ms away from retrace. Busy-Wait for retrace...
			lastline = PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber);
			beampos = lastline;
			while ((beampos < vbl_startline) && (beampos >= lastline)) {
				lastline = beampos;
				beampos = (long) PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber);
			} 
			
            // Retrace! Take system timestamp of VBL onset:
            PsychGetAdjustedPrecisionTimerSeconds(&tvbl);
            
            // If this wasn't the last frame to wait, we need to wait for end of retrace before
            // repeating the loop, because otherwise we would detect the same VBL and skip frames.
            // If it is the last frame, we skip it and return as quickly as possible to save the
            // Matlab script some extra Millisecond for drawing...
            if (waitFrames>1) { 
                beampos = vbl_startline;
                while ((beampos<=windowRecord->VBL_Endline) && (beampos>=vbl_startline)) { beampos = PsychGetDisplayBeamPosition(cgDisplayID, windowRecord->screenNumber); };
            }
            
            // Done with this refresh interval...
            // Decrement remaining number of frames to wait:
            waitFrames--;
        }
    }
    else if (vblRefCount > 0) {
        // Display beamposition queries unsupported, but vblank count queries seem to work. Try those.
        // Should work on Linux and OS/X:
        while(waitFrames > 0) {
            vblCount = vblRefCount;

            // Wait for next vblank counter increment - aka start of next frame (its vblank):
            while (vblCount == vblRefCount) {
                // Requery:
                PsychOSGetVBLTimeAndCount(windowRecord, &vblCount);
                // Yield at least 100 usecs. This is accurate as this code-path
                // only executes on OS/X and Linux, never on Windows (as of 01/06/2011):
                PsychYieldIntervalSeconds(0.000100);
            }

            vblRefCount = vblCount;
            
            // Done with this refresh interval...
            // Decrement remaining number of frames to wait:
            waitFrames--;
        }
    }
    else {            
        // Other methods unsupported. We use the doublebuffer swap method of waiting for retrace.
        //
        // Working principle: On each frame, we first copy the content of the (user visible) frontbuffer into the backbuffer.
        // Then we ask the OS to perform a front-backbuffer swap on next vertical retrace and go to sleep via glFinish() et al.
        // until the OS signals swap-completion. This way PTB's/Matlabs execution will stall until VBL, when swap happens and
        // we get woken up. We repeat this procedure 'waitFrames' times, then we take a high precision timestamp and exit the
        // Waitblanking loop. As backbuffer and frontbuffer are identical (due to the copy) at swap time, the visual display
        // won't change at all for the subject.
        // This method should work reliably, but it has one drawback: A random wakeup delay (scheduling jitter) is added after
        // retrace has been entered, so Waitblanking returns only after the beam has left retrace state on older hardware.
        // This means a bit less time (1 ms?) for stimulus drawing on Windows than on OS-X where Waitblanking returns faster. 
        
        // Child protection:
        if (windowRecord->windowType != kPsychDoubleBufferOnscreen) {
            PsychErrorExitMsg(PsychError_internal, "WaitBlanking tried to perform swap-waiting on a single buffered window!");
        }
        
        // Setup buffers for front->back copy op:
        
        // Backup old read- writebuffer assignments:
        glGetIntegerv(GL_READ_BUFFER, &read_buffer);
        glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
        
        // Set read- and writebuffer properly:
        glReadBuffer(GL_FRONT);
        glDrawBuffer(GL_BACK);
        
        // Reset viewport to full-screen default:
        glViewport(0, 0, screenwidth, screenheight);                
        glScissor(0, 0, screenwidth, screenheight);                
        
        // Reset color buffer writemask to "All enabled":
        glColorMask(TRUE, TRUE, TRUE, TRUE);
        glDisable(GL_BLEND);
        glPixelZoom(1,1);

		// Disable draw shader:
		PsychSetShader(windowRecord, 0);

        // Swap-Waiting loop for 'waitFrames' frames:
        while(waitFrames > 0) {
            // Copy current content of front buffer into backbuffer:
            glRasterPos2i(0, screenheight);
            glCopyPixels(0, 0, screenwidth, screenheight, GL_COLOR);            
            
            // Ok, front- and backbuffer are now identical, so a bufferswap
            // will be a visual no-op.
            
            // Enable beamsyncing of bufferswaps to VBL:
            PsychOSSetVBLSyncLevel(windowRecord, 1);                
            
            // Trigger bufferswap in sync with retrace:
            PsychOSFlipWindowBuffers(windowRecord);
            
            // Wait for swap-completion, aka beginning of VBL:
            PsychWaitPixelSyncToken(windowRecord);
            
            // VBL happened - Take system timestamp:
            PsychGetAdjustedPrecisionTimerSeconds(&tvbl);
            
            // This code-chunk is an alternate way of syncing, only used for debugging:
            if (false) {
                // Disable beamsyncing of bufferswaps to VBL:
                PsychOSSetVBLSyncLevel(windowRecord, 0);                
                // Swap buffers immediately without vsync:
                PsychOSFlipWindowBuffers(windowRecord);
            }
            
            // Decrement remaining number of frames to wait:
            waitFrames--;
        } // Do it again...
        
        // Enable beamsyncing of bufferswaps to VBL:
        PsychOSSetVBLSyncLevel(windowRecord, 1);                
        
        // Restore assignment of read- writebuffers and such:
        glEnable(GL_BLEND);
        glReadBuffer(read_buffer);
        glDrawBuffer(draw_buffer);        
        // Done with Windows waitblanking...
    }
    
    // Compute number of frames waited: It is timestamp of return of this waitblanking minus
    // timestamp of return of last waitblanking, divided by duration of a monitor refresh
    // interval, mathematically rounded to an integral number:
    framesWaited = (int) (((tvbl - windowRecord->time_at_last_vbl) / ifi) + 0.5f);
    
    // Update timestamp for next invocation of Waitblanking:
    windowRecord->time_at_last_vbl = tvbl;
    
    // Return optional number of frames waited:
    PsychCopyOutDoubleArg(1, FALSE, (double) framesWaited);
    
    // Done.
    return(PsychError_none);
}
PsychError SCREENGetCapturedImage(void) 
{
    PsychWindowRecordType		*windowRecord;
    PsychWindowRecordType		*textureRecord;
    PsychRectType				rect;
    double                      summed_intensity;
    int                         capturehandle = -1;
    int                         waitForImage = TRUE;
    int                         specialmode = 0;
	double						timeout, tnow;
    double                      presentation_timestamp = 0;
    int							rc=-1;
    double						targetmemptr = 0;
	double*						tsummed = NULL;
	psych_uint8					*targetmatrixptr = NULL;
	static rawcapimgdata		rawCaptureBuffer = {0, 0, 0, NULL};

    // All sub functions should have these two lines
    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if(PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};
    
    PsychErrorExit(PsychCapNumInputArgs(6));            // Max. 6 input args.
    PsychErrorExit(PsychRequireNumInputArgs(2));        // Min. 2 input args required.
    PsychErrorExit(PsychCapNumOutputArgs(4));           // Max. 4 output args.
    
    // Get the window record from the window record argument and get info from the window record
    PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord);
    // Only onscreen windows allowed:
    if(!PsychIsOnscreenWindow(windowRecord) && !PsychIsOffscreenWindow(windowRecord)) {
        PsychErrorExitMsg(PsychError_user, "GetCapturedImage called on something else than an onscreen window or offscreen window.");
    }
    
    // Get the handle:
    PsychCopyInIntegerArg(2, TRUE, &capturehandle);
    if (capturehandle==-1) {
        PsychErrorExitMsg(PsychError_user, "GetCapturedImage called without valid handle to a capture object.");
    }

    // Get the 'waitForImage' flag: If waitForImage == true == 1, we'll do a blocking wait for
    // arrival of a new image. Otherwise we will return with a 0-Handle if there
    // isn't any new image available.
    PsychCopyInIntegerArg(3, FALSE, &waitForImage);

	// Special case waitForImage == 4? This would ask to call into the capture driver, but
	// not wait for any image to arrive and not return any information. This is only useful
	// on OS/X and Windows when using the capture engine for video recording to harddisk. In
	// that case we are not interested at all in the captured live video, we just want it to
	// get written to harddisk in the background. To keep the video encoder going, we need to
	// call its SGIdle() routine and waitForImage==4 does just that, call SGIdle().
	if (waitForImage == 4) {
		// Perform the null-call to the capture engine, ie a SGIdle() on OS/X and Windows:
		PsychGetTextureFromCapture(windowRecord, capturehandle, 4, 0.0, NULL, NULL, NULL, NULL);
		// Done. Nothing to return...
		return(PsychError_none);
	}
	
    // Get the optional textureRecord for the optional texture handle. If the calling script
    // provides the texture handle of an existing Psychtoolbox texture that has a matching
    // format, then that texture is recycled by overwriting its previous content with the
    // image data from the new captured image. This can save some overhead for texture destruction
    // and recreation. While this is probably not noticeable on mid- to high-end gfx cards with
    // rectangle texture support, it can provide a significant speedup on low-end gfx cards with
    // only power-of-two texture support.
    textureRecord = NULL;
    if ((PsychGetNumInputArgs()>=4) && PsychIsWindowIndexArg(4)) PsychAllocInWindowRecordArg(4, FALSE, &textureRecord);
    
    // Get the optional specialmode flag:
    PsychCopyInIntegerArg(5, FALSE, &specialmode);

	// Set a 10 second maximum timeout for waiting for new frames:
	PsychGetAdjustedPrecisionTimerSeconds(&timeout);
	timeout+=10;

    while (rc==-1) {		
      // We pass a checkForImage value of 2 if waitForImage>0. This way we can signal if we are in polling or blocking mode.
      // With the libdc1394 engine this allows to do a real blocking wait in the driver -- much more efficient than the spin-waiting approach!
      rc = PsychGetTextureFromCapture(windowRecord, capturehandle, ((waitForImage>0 && waitForImage<3) ? 2 : 1), 0.0, NULL, &presentation_timestamp, NULL, &rawCaptureBuffer);
		PsychGetAdjustedPrecisionTimerSeconds(&tnow);
        if (rc==-2 || (tnow > timeout)) {
            // No image available and there won't be any in the future, because capture has been stopped or there is a timeout:
			if (tnow > timeout) printf("PTB-WARNING: In Screen('GetCapturedImage') timed out waiting for a new frame. No video data in over 10 seconds!\n");

            // No new texture available: Return a negative handle:
            PsychCopyOutDoubleArg(1, TRUE, -1);
            // ...and an invalid timestamp:
            PsychCopyOutDoubleArg(2, FALSE, -1);
            PsychCopyOutDoubleArg(3, FALSE, 0);
            PsychCopyOutDoubleArg(4, FALSE, 0);

            // Ready!
            return(PsychError_none);
        }
        else if (rc==-1 && (waitForImage == 0 || waitForImage == 3)) {
            // We should just poll once and no new texture available: Return a null-handle:
            PsychCopyOutDoubleArg(1, TRUE, 0);
            // ...and the current timestamp:
            PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp);
            PsychCopyOutDoubleArg(3, FALSE, 0);
            PsychCopyOutDoubleArg(4, FALSE, 0);

            // Ready!
            return(PsychError_none);
        }
        else if (rc==-1 && waitForImage != 0) {
            // No new texture available yet. Just sleep a bit and then retry...
            PsychYieldIntervalSeconds(0.002);
        }
    }

    // rc == 0 --> New image available: Go ahead...
    if (waitForImage!=2 && waitForImage!=3) {
      // Ok, we need a texture for the image. Did script provide an old one for recycling?
      if (textureRecord) {
	// Old texture provided for reuse? Some basic sanity check: Everything else is
	// up to the lower level PsychGetTextureFromCapture() routine.
        if(!PsychIsOffscreenWindow(textureRecord)) {
	  PsychErrorExitMsg(PsychError_user, "GetCapturedImage provided with something else than a texture as fourth call parameter.");
        }	
      }
      else {
        // No old texture provided: Create a new texture record:
        PsychCreateWindowRecord(&textureRecord);

        // Set mode to 'Texture':
        textureRecord->windowType=kPsychTexture;

        // We need to assign the screen number of the onscreen-window.
        textureRecord->screenNumber=windowRecord->screenNumber;

        // It defaults to a 32 bit texture for captured images. On Linux, this will be overriden,
		// if optimized formats exist for our purpose:
        textureRecord->depth=32;
		textureRecord->nrchannels = 4;

        // Create default rectangle which describes the dimensions of the image. Will be overwritten
        // later on.
        PsychMakeRect(rect, 0, 0, 10, 10);
        PsychCopyRect(textureRecord->rect, rect);
        
        // Other setup stuff:
        textureRecord->textureMemorySizeBytes= 0;
        textureRecord->textureMemory=NULL;
        
        // Assign parent window and copy its inheritable properties:
		PsychAssignParentWindow(textureRecord, windowRecord);

        // Set textureNumber to zero, which means "Not cached, do not recycle"
        // Todo: Texture recycling like in PsychMovieSupport for higher efficiency!
        textureRecord->textureNumber = 0;
      }

      // Power-of-two texture requested?
      if (specialmode & 0x01) {
		// Yes. Spec it:
		textureRecord->texturetarget = GL_TEXTURE_2D;
      }
    }
    else {
        // Just want to return summed_intensity and timestamp, not real texture...
        textureRecord = NULL;
    }

	// Default to no calculation of summed image intensity:
	tsummed = NULL;
    if ((PsychGetNumOutputArgs() > 3) && !(specialmode & 0x2)) {
        // Return sum of pixel intensities for all channels of this image: Need to
		// assign the output pointer for this to happen:
		tsummed = &summed_intensity;
	}

    // Try to fetch an image from the capture object and return it as texture:
	targetmatrixptr = NULL;
	
	// Shall we return a Matlab matrix?
	if ((PsychGetNumOutputArgs() > 3) && (specialmode & 0x2)) {
		// We shall return a matrix with raw image data. Allocate a uint8 matrix
		// of sufficient size:
		PsychAllocOutUnsignedByteMatArg(4, TRUE, rawCaptureBuffer.depth, rawCaptureBuffer.w, rawCaptureBuffer.h, &targetmatrixptr);
		tsummed = NULL;
	}
	
	// Shall we return data into preallocated memory buffer?
	if (specialmode & 0x4) {
		// Copy in memory address (which itself is encoded in a double value):
		PsychCopyInDoubleArg(6, TRUE, &targetmemptr);
		targetmatrixptr = (psych_uint8*) PsychDoubleToPtr(targetmemptr);
	}
	
	if (targetmatrixptr == NULL) {
		// Standard fetch of a texture and its timestamp:
		rc = PsychGetTextureFromCapture(windowRecord, capturehandle, 0, 0.0, textureRecord, &presentation_timestamp, tsummed, NULL);
	}
	else {
		// Fetch of a memory raw image buffer + timestamp + possibly a texture:
		rawCaptureBuffer.data = (void*) targetmatrixptr;
		rc = PsychGetTextureFromCapture(windowRecord, capturehandle, 0, 0.0, textureRecord, &presentation_timestamp, tsummed, &rawCaptureBuffer);			
	}
	
    if (tsummed) {
        // Return sum of pixel intensities for all channels of this image:
        PsychCopyOutDoubleArg(4, FALSE, summed_intensity);
    }

    // Real texture requested?
    if (textureRecord) {
        // Texture ready for consumption.

		// Assign GLSL filter-/lookup-shaders if needed: usefloatformat is always == 0 as
		// our current capture engine implementations only return 8 bpc fixed textures.
		// The 'userRequest' flag is set if specialmode flag is set to 8.
		PsychAssignHighPrecisionTextureShaders(textureRecord, windowRecord, 0, (specialmode & 8) ? 1 : 0);

        // specialmode setting 16? Disable auto-mipmap generation:
        if (specialmode & 16) textureRecord->specialflags |= kPsychDontAutoGenMipMaps;    

		// Mark it valid and return handle to userspace:
        PsychSetWindowRecordValid(textureRecord);
        PsychCopyOutDoubleArg(1, TRUE, textureRecord->windowIndex);
    }
    else {
        PsychCopyOutDoubleArg(1, TRUE, 0);
    }
    
    // Return presentation timestamp for this image:
    PsychCopyOutDoubleArg(2, FALSE, presentation_timestamp);

    // Return count of pending frames in buffers or of dropped frames:
    PsychCopyOutDoubleArg(3, FALSE, (double) rc);

    // Ready!
    return(PsychError_none);
}