psychopy.org | Reference | Downloads | Github

Counter too Slow for Keyboard Response?

timing
#1

I’m working on an experiment where the subject must make 6 responses (say, ‘f’ key for numbers and ‘j’ key for letters) based on a 3x2 matrix of numbers and letters. The trial terminates after the first 6 responses have been made and my critical DV is trial length (i.e. time it took to make the 6th response). I’ve created a counter that begins each routine at 0 that I call keyboard. Here is my code for updating every frame

if keyboard == 6:
    continueRoutine = False
    
theseKeys = event.getKeys(keyList=['j','f'])

if len(theseKeys) > 0: # at least one key is pressed
    keyboard = keyboard + 1
    key_resp_2.keys.extend(theseKeys)  # storing all keys
    key_resp_2.rt.append(key_resp_2.clock.getTime())

This works in practice, but looking at the data it seems like sometimes the counter is too slow and collects more than 6 responses.
04%20PM

Is there a way to get around this? I know with mouse responses the line “while.mouse.isPressed…continue”, is helpful for this issue but I can’t find a similar bit of code for keyboard responses.

#2

This looks like some sort of conflict between having a graphical Builder keyboard component (I’m guessing called key_resp_2) and your code. Since you are checking for keypresses yourself (via event.getKeys(keyList=['j','f'])), you have no need for a graphical keyboard component as well. Simply delete that component.

What might be happening is that the graphical component collects keypresses that you miss, and then you add up to 6 more to its list .keys. If so, the list should have a minimum of 6 entries that you detect, plus a variable number (0, 1, 2, …) of additional entries collected by the keyboard component before or after your code runs on each screen refresh. As you don’t detect them, you also aren’t counting them.

So just store your collected key presses and reaction times in your own lists. At the end of the routine, you will need to save these in the data manually using

thisExp.addData('keys', your_key_list_variable)

and similarly for the RTs. Or, more conveniently, you might even want to save each keypress and RT into its own column: that will be easier to analyse, rather than having them all collected together into a single column, which would then need to be split apart at the analysis stage.

e.g.

theseKeys = event.getKeys(keyList=['j','f'])

if len(theseKeys) > 0: # at least one key is pressed
    keyboard = keyboard + 1

    # store current time in column rt_1, rt_2, etc:
    thisExp.addData('rt_' + str(keyboard), t) 
    
    # store response:
    thisExp.addData('key_' + str(keyboard), theseKeys[0])

    # if 6 keys have been pressed, stop:
    if keyboard == 6:
        continueRoutine = False

I’ve shifted the check whether 6 keypresses have happened to inside the keypress detection code, or else finishing the routine will always happen one screen refresh period late (not the end of the world, but it is good to pay attention to these things).

1 Like
#3

This works perfectly thank you! For my own understanding, what does the [0] in theseKeys[0] tell the program to do?

#4

getKeys() returns a list, so even if it contains just one element, we have to refer to it by its index within that list.

Given that you are checking on every screen refresh, it is very unlikely that the list would ever contain more than one element, so you aren’t likely to be missing any real responses.