Logging and Using Input

Forum for software developers to discuss BCI2000 software development
Locked
bburgess
Posts: 7
Joined: 08 Jun 2011, 15:46

Logging and Using Input

Post by bburgess » 18 Jul 2011, 12:59

I am near finishing a custom application based on the Feedback Demo Task, but I am having a problem. I need to listen to what keys the user is pressing and give a response in the program based on their key presses. Right now I am trying to do this by using the --LogKeyboard=1 command line option, and then in the DoFeedback method using a switch statement with the KeyDown state. This gives shoddy responses, as I have to continually press the key I want when running my application and get lucky to get the program to move on to the next phase. Needless to say this is inadequate for my purposes. How should I be implementing responses based on keys pressed?

As a somewhat unrelated question, I want there to be a pause before I display a picture to the subject. How would I do this without throwing off the timing (without exceeding a block time accidentally)?

gschalk
Posts: 615
Joined: 28 Jan 2003, 12:37

Re: Logging and Using Input

Post by gschalk » 18 Jul 2011, 17:53

Hi,

You need to check all keyboard state values for a particular sample block, not just the first one (the key may be pressed at any time during the sample block).

Gerv

bburgess
Posts: 7
Joined: 08 Jun 2011, 15:46

Re: Logging and Using Input

Post by bburgess » 18 Jul 2011, 21:29

I thought that's what I was doing...

Let me post the code for my DoPreFeedback method, which to my understanding is called at least once per sample block (it is called in the Process method for the FeedbackTask Class):

Edit: I just thought of some potentially helpful info. When I first tried my code the application threw an exception telling me that I was trying to access the KeyDown state without first checking it in preflight (I did check for "--LogKeyboard=1" in OnPreflight, however). So I just added State("KeyDown"); to my OnPreflight and the error wasn't there anymore. I just thought it was a little odd.

Code: Select all

void
BalloonTask::DoPreFeedback( const GenericSignal&, bool& doProgress )
{
	switch (State("KeyDown"))
	{
	case 0x5a://Z
		State("BalloonCode")=balloonLocs[0];
		doProgress = true;
		break;
	case 0x58://X
		State("BalloonCode")=balloonLocs[1];
		doProgress = true;
		break;
	case 0x4e://N
		State("BalloonCode")=balloonLocs[2];
		doProgress = true;
		break;
	case 0x4d://M
		State("BalloonCode")=balloonLocs[3];
		doProgress = true;
		break;
	default:
		  doProgress = false;
	}
}

bburgess
Posts: 7
Joined: 08 Jun 2011, 15:46

Re: Logging and Using Input

Post by bburgess » 20 Jul 2011, 11:46

I am still working on this problem. At the moment I am attempting to poll for the entire duration of the sample block. I don't think this is right, and I am getting the same behavior in the program (very shoddy response). I will post my current code. If someone could help I would greatly appreciate it.

Code: Select all

void
BalloonTask::DoPreFeedback( const GenericSignal&, bool& doProgress )
{

	int msPerSample(1000/Parameter("SamplingRate"));
	int msPerBlock(msPerSample*Parameter("SampleBlockSize"));
	int startTime = PrecisionTime::Now();
	while (!(doProgress || (int)PrecisionTime::Now()-startTime >= msPerBlock - msPerSample)){
		Sleep( 0 );
		switch ((int)State("KeyDown"))
		{
		case 0x5a://z
                     //statements that set doProgress to true if the correct key is down...
		}
	}
}

bburgess
Posts: 7
Joined: 08 Jun 2011, 15:46

Re: Logging and Using Input

Post by bburgess » 20 Jul 2011, 14:21

Success! The problem was that I was not iterating through each sample. This was where I was confused, since I thought that the state vector was only attached to the whole data block, instead of individual samples (which in retrospect is kind of silly, since states are supposed to represent events. Hindsight, 20/20, etc.) I will post the code in case anyone else wants to know how. I know that these forums are a good repository of info:

Code: Select all

void
BalloonTask::DoPreFeedback( const GenericSignal& input, bool& doProgress )
{
	for(int sample=0; sample < input.Elements() ; sample++ ){
		switch (Statevector->StateValue("KeyDown",sample))
		{
		case 0x5a://z
			State("BalloonCode")=balloonLocs[0];
			doProgress = true;
			break;
		case 0x58://x
			State("BalloonCode")=balloonLocs[1];
			doProgress = true;
			break;
		case 0x4e://n
			State("BalloonCode")=balloonLocs[2];
			doProgress = true;
			break;
		case 0x4d://m
			State("BalloonCode")=balloonLocs[3];
			doProgress = true;
			break;
		}
	}
}

gschalk
Posts: 615
Joined: 28 Jan 2003, 12:37

Re: Logging and Using Input

Post by gschalk » 20 Jul 2011, 15:16

Awesome.

Congratulations!

Thanks for posting the code.

Gerv

mellinger
Posts: 1065
Joined: 12 Feb 2003, 11:06

Re: Logging and Using Input

Post by mellinger » 02 Aug 2011, 09:07

Edit: I just thought of some potentially helpful info. When I first tried my code the application threw an exception telling me that I was trying to access the KeyDown state without first checking it in preflight (I did check for "--LogKeyboard=1" in OnPreflight, however). So I just added State("KeyDown"); to my OnPreflight and the error wasn't there anymore. I just thought it was a little odd.
It's not quite as odd as it seems. Imagine what happens when the "KeyDown" state does not exist in the system when it is accessed from your code: A run-time error will occur, resulting in an abort while running an experiment. To avoid this situation, BCI2000 forces you to test the "KeyDown" state for existence during OnPreflight(). This way, the user gets an error message when clicking SetConfig rather than in the middle of an experimental run.

For more about this, please check
http://www.bci2000.org/wiki/index.php/P ... ate_access

--Juergen

Locked

Who is online

Users browsing this forum: No registered users and 1 guest