Recording All Key Presses

This seems like a simple problem, but I can’t figure out the issue. I have a dual-task experiment where a video plays on one side of the screen and some text appears on the other side. Participants respond to the text by pressing z, x, c or v. When they respond or when 4 seconds have passed (whichever comes first), the text disappears and new text appears. This continues until the video is over.

I want to record each key that they press throughout this time, and also record if they do not press anything in the 4 seconds. When I choose the option to record all keys in the data tab of my keyboard component, it only records some of the keys. I cannot figure out a pattern for what it does or doesn’t record because each time I run the experiment, it will save a different number of key presses and sometimes it saves repeated keys and other times it does not.

Then I tried to build a code component to save the keys. In the Begin Routine tab, I created a keyboard object called kb and an empty array called allKeysResp. In the Each Frame tab, I had this code:

if currentT >= 4 or kb.getKeys(['z','x','c','v']):
    allKeysResp.append(kb.getKeys)

and separately, I tried this code:

keys = kb.getKeys()
if currentT >= 4 or kb.getKeys(['z','x','c','v']):
   for key in keys:
      print(key.name)

Then in the End Routine I had it write allKeysResp to the data output. However, allKeysResp is just an array of empty arrays (looks like: [ ] [ ] [ ] [ ] [ ] ) with each little array representing a key press. I also tried to append the allKeysResp with kb.key, kb.getKeys[ ], and a number of other iterations of that type of call, but they either gave me the empty arrays or errors.

I found this topic and this topic and this topic that are similar to my issue, but couldn’t seem to apply their solutions to my experiment.

I also need to record the correct response for each of these text appearances. I have the correct response saved in the excel sheet where the text is drawing from, but it is not currently saving that information (even though that box is checked in the data menu for the keyboard component).

As a side note, I would like each key press to appear in it’s own row, rather than an array in a single cell in the excel sheet, if anyone can help me do that. I’ve only been trying to put it in an array for now because that’s all I knew how to do.

Thanks!

Could you make your experiment available to download?

How can you record all key presses if the first key press ends the routine?

Sorry, I should have been more clear. The text disappears with custom code in the Every Frame tab. The code essentially says “if current time > 4 or if there is a keyboard response, show the next set of text from the array”. The routine ends when the video is over.

I’m in the process of making my experiment available to download and will put it here, so hopefully that will clarify things too.

Here is a version of my experiment available to download.
Dowloadable.zip (115.4 KB)

There are no instructions in it, but the video on the left will play and it will end on its own or when you press the dispatch button (ending the routine either way) and the text on the right side of the screen should change every 4 seconds or each time you press either z, x, c or v. There are only two trials in this version.

Hi @cpat,

I got it to work making some small changes. You can download it here. Let me know if you need clarification on anything.

Regarding your need for the data populating different rows: I believe that this reformating is to be done after the fact. As far as I know, PsychoPy will only go to a new row if a new routine began. But in your experiments, all of the trials take place in one routine.

Thank you SO much! This is working and I’ll just do some post-processing of the code to get it into different rows.

For anyone that may come across this in the future, the code inserted into the Every Frame tab that made this work is:

if currentT >= 4 or len(keys) > 0:
        
    if len(keys) > 0:
        allKeysResp.append(response.keys[-1])
        allKeysCorr.append(int(response.keys[-1] == cur_CR))
    else:
        allKeysResp.append('None')
        allKeysCorr.append(0)

Where allkeysResp = [ ] and allKeysCorr = [ ] is defined in the start routine tab.

Hi again -

I’ve been using this code for other routines where the layout is the same as the previous trials but they are shown after some branching activity so they have to be their own routines. When I do this, it gives me the error “list index out of range” for the allKeysResp.append(response.keys[-1]) as soon as the trial starts, regardless of a response. I changed the [-1] to [0] just to troubleshoot I got the same error so I’m not sure that the -1 is the actual problem. I also made sure that “response” was changed to the new keyboard response variable name.

Any ideas why this is happening?

Hi, I suspect you forgot the line

keys = response.getKeys()

as it’s also not present in the code you posted above. This would lead to allKeysResp.append(response.keys[-1]) triggering in the beginning of the routine and failing because response.keys at this point is only an empty list.

Hi,

Thanks so much for the quick response! I did actually include that code in my experiment, but forgot to put it here.

The code in the new routine under “Each Frame” is

currentT = round(timer.getTime())
keys = response_AEChoice.getKeys(['z','x','c','v'])

if currentT >= 4 or len(keys) > 0:
        
    if len(keys) > 0:
        allKeysResp.append(response_AEChoice.keys[-1])
        allKeysCorr.append(int(response_AEChoice.keys[-1] == cur_CR))
    else:
        allKeysResp.append('None')
        allKeysCorr.append(0)
        
    cur_TargetPackage = cur_TargetPackage + 1
    cur_match1 = cur_match1 + 1
    cur_match2 = cur_match2 + 1
    cur_match3 = cur_match3 + 1
    cur_match4 = cur_match4 + 1
    cur_CR = cur_CR + 1
    timer.reset()

    

if cur_match1 == 301:
    cur_CR = 0
    cur_TargetPackage = 0
    cur_match1 = 0
    cur_match2 = 0
    cur_match3 = 0
    cur_match4 = 0
    timer.reset()

When it quits out, it actually just keeps loading for a long time and I have to manually click the “Stop” button in the runner window. Then it spits out " allKeysResp.append(response_AEChoice.keys[-1])
IndexError: list index out of range"

In the “Begin Routine” tab I do have the arrays defined as

allKeysResp = []
allKeysCorr = []

I fixed it! It turns out that changing the response.keys() doesn’t need to be changed each time. Instead, the code in the new routine is working like this:

currentT = round(timer.getTime())
keys = response_AEChoice.getKeys(['z','x','c','v'])

if currentT >= 4 or len(keys) > 0:
        
    if len(keys) > 0:
        allKeysResp.append(keys[-1])
        allKeysCorr.append(int(keys[-1] == cur_CR))
    else:
        allKeysResp.append('None')
        allKeysCorr.append(0)
        #continue code from above 
1 Like