psychopy.org | Reference | Downloads | Github

Force end of routine with two key presses, within time limit

Hi everybody,
I’m new to python so I apologize in advance if my question is trivial.

When I present the probe for my task, I want the response to be made with two key presses. I want the two key presses to force the end of the routine, but also if a time limit is reached the routine has to finish.
In other words, I’d want the same as event.waitKeys(), but with two key presses.

I tried using core.wait() like this:

core.wait(5)
x=event.getKeys('v, b, n, m')
if len(x)>=2:
   continueRoutine=False
elif len(x)<2
   continueRoutine=True

But it always waits the 5 seconds, even with two key presses. I guess core.wait() is not “overridden” by the ContinueRoutine=False.

I also tried to use a while loop and a timer:

timer=core.CountdownTimer(5)
while timer.getTime()>0:
   x=event.getKeys('v, b, n, m')
   if len(x)<2:
      continueRoutine=True
   elif len(x)>=2:
      continueRoutine=False

But it’s not working. I guess it depends on the timing and order in which the operations are carried out, because if I try to print x I get many empty lists.

Any ideas on how to solve this issue?

Thank you!

This is the usual case of computers frustratingly doing exactly what you tell them :wink:

In the first case, you ask to wait for 5 s and only then check for any key presses which may have occurred. So naturally, this will always lead to a 5 second delay before any responses can be dealt with.

So your instinct of checking more frequently within a loop is the correct one. The issue this creates is the opposite: the checking is now so fast that it is unlikely that you will ever detect a pair of keys simultaneously. i.e. the first key will be detected, but the second key will likely not be detected until a subsequent iteration. With frequent checking like this, even if the subject pushes two keys, your code will register them in two separate single-element lists. Hence, the length of the list will hardly ever be > 1.

So you need to add some extra logic. Set a flag (e.g. first_key_detected) to be False initially and True when the first key is found. Only quit the routine when both a key press is detected and first_key_detected == True.

Hi Michael,
thank you for your kind and very clear response. I tried to implement your suggestion but I didn’t manage to make it work. My problem is that I get again an empty list for every iteration in which it checks for a key press. Also, psychopy seems to freeze for a few seconds.

timer=core.CountdownTimer(5)
first_key_detected=False
while timer.getTime()>0:
   x=event.getKeys('v, b, n, m')
   if x!=[]
        first_key_detected=True
   if len(x)<0 and first_key_detected==True:
      continueRoutine=False
   else:
       continueRoutine=True

By many trial and errors, I found an alternative and very simple solution:

xTimer=core.Clock()
first_key_detected=event.waitKeys(x_dur, 'v, b, n, m', timeStamped=xTimer)
print first_key_detected
second_key_detected=event.waitKeys(x_dur,'v, b, n, m', timeStamped=xTimer)
print second_key_detected
x=first_key_detected+second_key_detected
print x

I didn’t even try this solution earlier because I expected the first event.waitKeys to skip the routine, but this is not the case. It behaves exactly as I wanted and I get a list of two tuples (pressed key and corresponding time stamp).

Nevertheless, I think the solution you suggested might be very useful in other contexts, so I would really appreciate if you could point out what I was doing wrong when trying to implement it!

Thank you again! :slight_smile:

Just to check: I’ve been assuming that this experiment is entirely your own code.

If using Code components in Builder, we can’t use waitKeys() or loops, as Builder is structured around a screen refresh drawing loop that we can’t interrupt with code that will take longer than one screen refresh.

Yes, it is entirely code!