psychopy.org | Reference | Downloads | Github

Recording two consecutive (correct) answers in one trial

Hi all,

I am trying to find a way to record two consecutive correct key presses in a single trial. My code is currently set up to call from a column (i.e., corrAns) in an excel file to get only one correct response per trial (keys: ‘p’, ‘r’, ‘l’, or ‘m’)
However, in my task, I would like participants to press two keys, one after the other (e.g. “p” followed by “r”) in a single trial. Crucially, they can only validate the trial if they press on these two keys. I suppose this can only be done in the Coder, so here’s the part of the code which I think might be relevant for doing this:

            theseKeys = key_resp.getKeys(keyList=['p','r','l','m'], waitRelease=False)
            if len(theseKeys):
                theseKeys = theseKeys[0]  # at least one key was pressed
                
                # check for quit:
                if "escape" == theseKeys:
                    endExpNow = True
                key_resp.keys = theseKeys.name  # just the last key pressed
                key_resp.rt = theseKeys.rt
                # was this 'correct'?
                if (key_resp.keys == str(corrAns)) or (key_resp.keys == corrAns):
                    key_resp.corr = 1
                else:
                    key_resp.corr = 0

I’ve also tried the following solution:

    if key_resp_1.status == STARTED:
        theseKeys = key_resp_1.getKeys((), waitRelease=False)
        if theseKeys: 
            'space' and 'r' == theseKeys
            continueRoutine = False

I thought that by having both space and r within an if statement that would work. It works when I press space followed by r, but not the other way around (when I press r it continues to the next trial right away)

Ok, so finally I managed to find a solution, mostly thanks to this post: End routine after TWO key presses

I adapted @Oli’s code component:

    theseKeys = key_resp_1.getKeys(('space','r'), waitRelease=False)
    if theseKeys:
        if "escape" in theseKeys:
            endExpNow = True
        else:
            thisResp.append(theseKeys)
            if len(thisResp) ==2:
                continueRoutine = False

And of course, don’t forget to create an empty list at the beginning of the trial:

thisResp = []

It works perfectly! :wink:

Oh now I just realized that, although I managed to record two separate answers with the code above, I still haven’t found a way of specifying whether these are correct or wrong answers. How should my corrAns column look like? Can I add two correct answers within a single cell, or do I have to create more rows/columns?

I found this old solution by @Michael Multiple correct responses in Builder View. He suggests adding the two correct keys in a single cell, within brackets and with single and double quotes, e.g., “[‘p’, ‘space’]”
This, however, doesn’t seem to work. In fact, when looking at the how the data is being recorded in the Excel file, the column corrAns is shifted to the left and the second key appears in that second column. Like this:
image

Any help would be greatly appreciated!

Hi @Mardock ,
thank you for sharing your progress!

Do I understand correctly that the order of the two correct keypresses is important? So, e.g. ["p", "r"] would be correct but ["r", "p"] would not? If so, you can simply create two columns corrAns1 and corrAns2. You then just have to check: if thisResp[0]==corrAns1 and thisResp[1]==corrAns2.
(In order to be more consistent with python’s zero-based indexing, you can of course call the columns corrAns0 and corrAns1 instead)

I would also recommend you to print(thisResp) before you make the if check above because it might be that your code will give you three elements after two keypresses because it always appends the whole list of current key presses. Therefore, for the first press, it would give you ["p"] but for the second one it will append another ["p", "r"] (i.e., the whole list of current key presses) resulting in ["p", "p", "r"]. If this will be the case, try to replace thisResp.append(theseKeys) by thisResp = theseKeys.

Hope this helps!
Best regards,
Mario

Hi @mario.reutter
Thanks for your reply!
I tried what you’re suggesting. The problem is that for some reason the keys are being stored in a weird format. So when I try accessing the attributes of thisResp I see this:
[[<psychopy.hardware.keyboard.KeyPress object at 0x11e23bba8>], [<psychopy.hardware.keyboard.KeyPress object at 0x11e22bb00>]]

And since this doesn’t correspond to what I have in the Excel file under the column corrAns1 and corrAns2 the feedback component returns wrong!, regardless of the key I press.

Oh, and regarding your question about the order in which the keys have to be pressed. It’s not that important actually. I would simply like the code to evaluate whether two keypresses are within a list, regardless of the order.

Thanks!

My bad, I have not worked yet with PsychoPy 3 so I didn’t know that getKeys now returns an object (take a look at https://www.psychopy.org/api/hardware/keyboard.html).

You need to change the definition of thisResp to:
thisResp = [key.name for key in theseKeys]

To check both key presses without order, you can do:
if corrAns1 in thisResp and corrAns2 in thisResp

Hope this solves it :slight_smile:

Hi @mario.reutter
I think I’m almost there! However this time when I change the definition of thisResp to what you’re suggesting nothing really happens. Normally after pressing two keys this is followed by feedback. This time it looks as if nothing is evaluated as correct or wrong, or no key is stored…

You can always print variables in order to understand what goes wrong. In this case, I think the following will work:
thisResp = thisResp.append( [key.name for key in theseKeys] )

Hi @mario.reutter!

Now it works!

Here’s the code component, in case anyone else wants to record two consecutive correct answers:

if key_resp.status == STARTED:
            theseKeys = key_resp.getKeys(keyList=['p','r'], waitRelease=False)
            if theseKeys:
                if "escape" in theseKeys:
                    endExpNow = True
                else:
                    thisResp.append( [key.name for key in theseKeys] ) #creating a list with the elements of theseKeys
                    if len(thisResp) == 2: #if thisResp has two elements
                       key1 = thisResp[0] #first key pressed
                       key2 = thisResp[1] #second key pressed
                       continueRoutine = False #continue to feedback
                   

                #check if two keys pressed are correct answer
                if (key1 == corrAns1 and key2 == corrAns2):
                    key_resp.corr = 1
                else:
                    key_resp.corr = 0

Oh, sorry @mario.reutter, one more quick question. Do you know if, now that I converted my key responses to lists, it would be possible to record the time at which they were pressed?
I’ve tried to do this with the standard procedure, i.e. with theseKeys.rt, but this doesn’t seem to be working. Thanks a lot!

theseKeys is a list of key presses. Each key press contains information about the name of the pressed key, the time it was pressed down (rt) and the duration of the key press.
Hence you need something like: thisTime.append( [key.rt for key in theseKeys] )

NB: Splitting the key presses into separate lists of name and time may not be the most tidy way to code this but it is the most efficient way given your already working code.