How can you get a time interval for pressing down a key from two participants at the same time?

For our current experiment we need to be able to recieve the amount of time that two participant hold down two seperate keys and they will both be pressing the keys at the same time. Is there a way to record and retrieve the interval of time that each participant held down their key?

For context, the participants will be holding down a key to indicate how long they thought a shape took to apear on the screen. One participant will hold down the “a” key for the amount of time that they think passed before a shape apeared on the screen and the other participant will hold down the “k” key for the amount of time that they think passed before a shape appeared on the screen. They will be prompted to hold down their respective keys at the same time and they will both press and hold their key on the same keyboard after reading the prompt. Is this possible?

So far I have this code which allows two keys to be pressed and held at the same time without any errors but I need to be able to record the interval for each key that is pressed when they are pressed and released at different times.

        while 1
            [keyIsDown, ~, keyCode] = KbCheck;
            if keyIsDown == 1 && keyCode(65) == 1 && keyCode(66)==1
                startTime = Screen('Flip',mainWin);
                while keyIsDown == 1
                    [keyIsDown, ~, keyCode] = KbCheck;
                    thisTime = Screen('Flip',mainWin);
                    timeEstimate2 = thisTime - startTime;
                end
                break;
            end
             
        end

Any ideas for this? Thanks in advance for any help!

I would look into KbQueues for this (KbQueueDemo), KbQueueCheck returns the info you need for each key.

1 Like

Thank you for the suggestion! I looked into KbQueues and it seemed like it would be perfect for what I need but I am having a little difficulty implementing it. So far I have:

device = -1; 
keys=[88 89];
keylist=zeros(1, 256);
keylist(keys)=1;
KbQueueCreate(device, keylist);
KbQueueStart(device);

while 1
        [~, firstPress, firstRelease] = KbQueueCheck(device); 
        if firstRelease(88) > 0 && firstRelease(89) > 0
            break;
        end
end

KbQueueStop(device);
KbQueueRelease(device);
  
timeEstimate1 = firstRelease(88) - firstPress(88);
timeEstimate2 = firstRelease(89) - firstPress(89);

Which I was expecting to output two time intervals: One for the amount of time “x” was held down for and one for the amount of time “y” was held down for. But I think the KbQueueCheck is being reset every time the loop iterates and the firstPress and firstRelease values are not giving the correct values for the time interval. Is there a way to store the time stamp for the actual firstPress of the “x” and “y” keys and not have it reset within the loop after every iteration of the loop?

There’s also KbEventGet and friends, which return one key event struct for each key press or release, also demonstrated in that demo, for recording a “timeline” of what press/release happened when.

Maybe something like this:

...
[~, firstPress, firstRelease] = KbQueueCheck(device); 
while 1
        [~, p, r] = KbQueueCheck(device); 
        firstPress(p>0) = p(p>0);
        firstRelease(r>0) = r(r>0);
        ...
1 Like

Thanks for the reply! I am not really following though sorry… I need to end up with the interval of time that a key is pressed down and the interval of time that another key is pressed down and these keys will be pressed roughly around the same time but will start and end at different times. Is there a way to modify this code to enable this functionality?

Also just tested this code and it always gives an identical value for firstPress and firstRelease, not sure what’s going on.

KbEventGet would certainly allow you to do what you want, but is too complicated. _qx1147 gives the solution. Just using their suggestion (and making your break condition a bit more generic), this code works for me:

device = -1; 
keys=[88 89];
keylist=zeros(1, 256);
keylist(keys)=1;
KbQueueCreate(device, keylist);
KbQueueStart(device);

[~, firstPress, firstRelease] = KbQueueCheck(device); 
while 1
        [~, p, r] = KbQueueCheck(device); 
        firstPress(p>0) = p(p>0);
        firstRelease(r>0) = r(r>0);
        if all(firstRelease(keys) > 0)
            break;
        end
end

KbQueueStop(device);
KbQueueRelease(device);
1 Like

Maybe it should be noted that, when embedding the code snippet in a real script, more care has to be taken to handle arbitrary key and queue states when entering the while loop. How this would be done depends on what exactly you want to achieve (e.g., what if the user presses a key even before the stimulus appeared, or if the user presses one key twice while the other key is held down, etc.).

[~, firstPress, firstRelease] = KbQueueCheck(device); 
firstPress(:) = 0;
...
while 1
        [~, p, r] = KbQueueCheck(device); 
        firstPress(p>0) = p(p>0);
        firstRelease(r>0) = r(r>0);
        if all(firstPress(keys)>0 & firstRelease(keys)>firstPress(keys))
            break
        end
end

You can use KbQueueFlush for that as well