how to register a single key press

I am setting up an experiment where a sequence of stimuli is running
and the subject presses a keyboard key to respond to events. I would
like to know which frame of the stimulus sequence is showing when the
key is pressed. Here is a simple demo, where a press of the right
arrow key starts a dot travelling from left to right, and the frame
numbers corresponding to presses of the left arrow key are stored in
an array (bb). The program works fine except that each key press
results in a random number of entries (between 4 and 6) in the array
bb. For example, two presses of the left arrow key in the duration of
travelling dot may result in:
bb=[161 162 163 164 165 259 260 261 262 263];
Each key press results in a series of 5 entries. I can use the first
entry of each series as the stimulus frame corresponding to a key
press, but I'd like to have a cleaner result. I do have a
FlushEvents('keyDown');
in the loop, but it does not seem to do any thing and the keyDown
event lingers for 4 or 5 frames.

I am using a 2 GHz PC running Windows 2000, MatLab 6.1 and the lastest
PsychToolbox.

Thanks!

Lei

% travelling dot
white=255;
[w,wRect]=Screen(0,'OpenWindow',white);
srcRect=[0,0,100,100];
dstRect=CenterRect(srcRect,wRect);
dotRect0=CenterRect([0 0 12 12],srcRect);
[dot offRect]=Screen(w,'OpenOffscreenWindow',white,dstRect);
Screen(dot,'FillOval',black,dotRect0);

white=255;
black=0;

d0=OffsetRect(offRect,0,0);

rightKey = KbName('right');
leftKey = KbName('left');
escapeKey = KbName('esc');
bb=[];
while 1
[a,b,keyCode] = KbCheck;
if keyCode(rightKey)
for i=1:300
dotRect=OffsetRect(d0,i,0);
Screen(w,'WaitBlanking')
Screen('CopyWindow',dot,w,offRect,dotRect);
[a,b,keyCode] = KbCheck;
if keyCode(leftKey)
bb=[bb i];
end
FlushEvents('keyDown');
end
end
if keyCode(escapeKey)
break;
end
end

FlushEvents('keyDown');
Screen('CloseAll');
Nice sample code. Made the issue very clear and easy to suggest help.
(The line "black = 0;" needed to be put before the first
Screen('FillOval') command, but that was no big deal.)

My solution for this type of issue is typically the use of state flags
(i.e., logical variables that flip between 0 and 1 when the state of
something changes) which get incorporated in more detailed
if-statements and while-statements.

In your case, I added the flag "leftKeyDown" which is 0 when the left
key is not being pressed and 1 when it is being pressed. And you will
see that I enhanced your if-statement and added an elseif-statement to
reset the flag when the left key is no longer being pressed. Seems to
work for me, single frame values recorded in bb for each press. Threw
in some comments too where I made changes. I am pasting it with the
tabs collapsed for transmission.

Daniel Shima
Vanderbilt Vision Research Center


% travelling dot
clear all;
white=255;
black = 0;
[w,wRect]=Screen(0,'OpenWindow',white);
srcRect=[0,0,100,100];
dstRect=CenterRect(srcRect,wRect);
dotRect0=CenterRect([0 0 12 12],srcRect);
[dot offRect]=Screen(w,'OpenOffscreenWindow',white,dstRect);
Screen(dot,'FillOval',black,dotRect0);

white=255;
black=0;

d0=OffsetRect(offRect,0,0);

rightKey = KbName('right');
leftKey = KbName('left');
escapeKey = KbName('esc');
bb=[];
while 1
[a,b,keyCode] = KbCheck;
if keyCode(rightKey)
leftKeyDown = 0; % flag indicating state of left key.
for i=1:300
dotRect=OffsetRect(d0,i,0);
Screen(w,'WaitBlanking')
Screen('CopyWindow',dot,w,offRect,dotRect);
[a,b,keyCode] = KbCheck;
% Only add to bb if left key not already down.
if (keyCode(leftKey) & leftKeyDown == 0)
leftKeyDown = 1; % Change left key flag when down.
bb=[bb i];
elseif (~keyCode(leftKey) & leftKeyDown == 1)
% Else if left key is not down but flag says it is down,
% change flag to indicate left key not down.
leftKeyDown = 0;
end
FlushEvents('keyDown');
end
end
if keyCode(escapeKey)
break;
end
end

FlushEvents('keyDown');
Screen('CloseAll');


On 6/8/05, liul15110 <lliu@...> wrote:
> I am setting up an experiment where a sequence of stimuli is running
> and the subject presses a keyboard key to respond to events. I would
> like to know which frame of the stimulus sequence is showing when the
> key is pressed. Here is a simple demo, where a press of the right
> arrow key starts a dot travelling from left to right, and the frame
> numbers corresponding to presses of the left arrow key are stored in
> an array (bb). The program works fine except that each key press
> results in a random number of entries (between 4 and 6) in the array
> bb. For example, two presses of the left arrow key in the duration of
> travelling dot may result in:
> bb=[161 162 163 164 165 259 260 261 262 263];
> Each key press results in a series of 5 entries. I can use the first
> entry of each series as the stimulus frame corresponding to a key
> press, but I'd like to have a cleaner result. I do have a
> FlushEvents('keyDown');
> in the loop, but it does not seem to do any thing and the keyDown
> event lingers for 4 or 5 frames.
>
> I am using a 2 GHz PC running Windows 2000, MatLab 6.1 and the lastest
> PsychToolbox.
>
> Thanks!
>
> Lei
>
> % travelling dot
> white=255;
> [w,wRect]=Screen(0,'OpenWindow',white);
> srcRect=[0,0,100,100];
> dstRect=CenterRect(srcRect,wRect);
> dotRect0=CenterRect([0 0 12 12],srcRect);
> [dot offRect]=Screen(w,'OpenOffscreenWindow',white,dstRect);
> Screen(dot,'FillOval',black,dotRect0);
>
> white=255;
> black=0;
>
> d0=OffsetRect(offRect,0,0);
>
> rightKey = KbName('right');
> leftKey = KbName('left');
> escapeKey = KbName('esc');
> bb=[];
> while 1
> [a,b,keyCode] = KbCheck;
> if keyCode(rightKey)
> for i=1:300
> dotRect=OffsetRect(d0,i,0);
> Screen(w,'WaitBlanking')
> Screen('CopyWindow',dot,w,offRect,dotRect);
> [a,b,keyCode] = KbCheck;
> if keyCode(leftKey)
> bb=[bb i];
> end
> FlushEvents('keyDown');
> end
> end
> if keyCode(escapeKey)
> break;
> end
> end
>
> FlushEvents('keyDown');
> Screen('CloseAll');