End routine after TWO key presses

Hi,

My task involves entering a percentage 0-99. I want the 2nd digit press to end the routine as its a long task, and this will speed it up for participants

Is this possible - in the GUI? I’m not a confident coder.

Thanks!
JG

It would need a code component and the output would be in list format (so rather than 99 you’d get [9,9])

If mouse input would be acceptable - you could use a rating scale with a range of 0-99

Many thanks for your quick reply, Oli. The first is preferably as there are versions of the task published which used the digit entry method - so this is preferable.

If you could be so kind as to explain how it is done, and where to insert code, that would be much appreciated. If code is changed, is this reflected in the builder; and similarly, do I still run it from the builder or do i have to run from the code window after adding this?

Many thanks indeed,
JG

Adapted from Michaels code in a previous thread. Check out code components in the documentation. Add the following to the Every Frame tab. You won’t need a Keyboard component from what I understand.
BW

Oli

keys = event.getKeys()

if keys: # if at least one key exists in the list,
    if 'escape' in keys: # now need to check for the quit key ourselves
        core.quit() 

     elif len(keys) == 2: #if two keys have been pressed
        thisExp.addData('keys', ''.join(keys) # store keys
        thisExp.addData('RT', t) #reaction time because why not
        contineRoutine = False #end routine.

1 Like

Hi @Oli,

I’m not sure how well this would work in this case: when checking event.getKeys() on every frame, I think it would be pretty unlikely to actually get two keys returned. i.e. the second would need to have been pressed within a few milliseconds of the first to get collected in the in the same call to event.getKeys() . More likely, you’ll detect the keys individually as they come in (each call to getKeys() clears the buffer of previous keypresses).

That would mean storing key presses and taking action once the second has been received

Thanks again Michael - I’m being too hasty and not testing this stuff!

#beginRoutine Tab
thisResp = [] #make an empty list

#every Frame
keys = event.getKeys()

if keys: # if at least one key exists in the list,
    if 'escape' in keys: # now need to check for the quit key ourselves
        core.quit() 

     else: #add this frame keys to response list
        thisResp.append(keys)
        if len(thisResp) == 2:
					thisExp.addData('response',''.join(thisResp))
        	thisExp.addData('RT',t)
          contineRoutine = False #end routine.

Hi @Oli.
I tried to implement your solution. Although it works, I’m still struggling with getting the two keypresses registered correctly as data in the excel file.
When I run my script with the code component you’re suggesting I get the following error:

thisExp.addData('response',''.join(thisResp))
TypeError: sequence item 0: expected str instance, list found

What I did then was to transform thisResp into a string, by adding a str before thisResp:

thisResp.append(theseKeys)
if len(thisResp) == 2:
           thisExp.addData('response',''.join(str(thisResp)))
           continueRoutine = False

This, again, seems to work. But when I look at 'response' cell in the excel file I see this:
[[<psychopy.hardware.keyboard.KeyPress object at 0x118c42860>], [<psychopy.hardware.keyboard.KeyPress object at 0x11dab7128>]]

The first entry here (I suppose) is space, while the second is r. Any idea of how to fix this?

Hey it’s been years since I’ve used psychopy or even python - but it looks like theseKeys is a function - when you assign a function to a variable it stores the function, not the value. Try adding brackets to make it a function call:

‘’.join(theseKeys())

Hi @Oli, Thanks for your help.
Indeed, theseKeys seems to be a function. When I add brackets, as you suggest, I get the following error.

    thisExp.addData('response',''.join(theseKeys()))
TypeError: 'list' object is not callable

Oli is on the right track in that you’re not dealing with a string, but it isn’t a function either, it is a list.

Try this sort of code to see what you are dealing with:

print(thisResp)    # the list
print(thisResp[0]) # the first element of that list
print(type(thisResp[0])) # what is it?

I think the elements of the list will be the new KeyPress objects of PsychoPy’s Keyboard class, which has superseded the old event module code in the old posts above. These objects have certain attributes you can access like this:

key = thisResp[0]
print(key.name)
print(key.rt) 
print(key.duration)

or in your case, something like:

response = ''

for key in thisResp:
    response = response + key.name

thisExp.addData('response', response)

Hi @Michael,

I checked what kind of object is thisResp, and it turns you were right, it is a list. The objects it contains looks like this: [<psychopy.hardware.keyboard.KeyPress object at 0x11f75ccf8>]

But then, when I try to see the name of the first key, with:

key = thisResp[0]
print(key.name)

I get the following error:

print(key.name)
AttributeError: 'list' object has no attribute 'name'

Should I transform key into something else to access the attributes?

Thanks for the help!

One again, print() and print(type()) are your friends in diagnosing these things.

Hi @Michael,

I’m dealing mostly with lists, as you can see here:

print(type(theseKeys))
<class 'list'>

The problem that I’m having is that, for some reason, the keys in that lists are being stored in a weird format, so that when I try to access the attributes in theseKeys by doing this:

print(theseKeys)

I end up seeing this:

[[<psychopy.hardware.keyboard.KeyPress object at 0x11e2da860>], [<psychopy.hardware.keyboard.KeyPress object at 0x11eb80ba8>]]

For some reason, each entry in your list is itself a list (even though it contains only a single entry). (i.e. look at how the square brackets occur, nested within each other). So you need to burrow down another level with your indexing:

e.g.

key = thisResp[0][0] # the first element of the first element

Hello Oli,

Thank you again for your help. I have also tried to implement your code. The code worked with ending routine after two keypresses, but it does not store the response or the reaction time data. When I looked at the data csv file, it looks like this


Would you have any idea how to add the key responses and the reaction time into the data? Thank you again for your help.