| Reference | Downloads | Github

Keyboard component alive even after the routine is over

OS (e.g. Win10): Win10
PsychoPy version (e.g. 1.84.x): 1.85.2


I have a problem regarding keyboard responses and following are what I’m trying to do and what the problem is.

1.What I am trying to do

I made self-paced reading task; a task where participants read sentences by pressing ‘space bar’ and revealing the words of the sentence one by one from the first word appearing at the left. Before any word is revealed, all words are masked by dashes. (check the gif below)
After reading and comprehending the whole sentence properly, the participant must answer a comprehension question(or a ‘probe’ question). It simply shows certain part of the previous sentence in a form of shorter sentence. Participants will decide whether the probe sentence is true of false by pressing the ‘j’ or ‘f’. After a response, there will appear a cross symbol(‘break_2’) at the center of the screen and soon, next sentence will appear masked.

The screenshot below shows basic layout of the routines I just mentioned.

The code component of the routine ‘trial’ is shown below. The original code is from this post and I modified it to work as I intended.
There are codes in the Begin Routine tab and Each Frame tab only.

At Begin Routine:

sentenceList = sentence.split() 
# this breaks your sentence's single string of characters into a list of individual 
# words, e.g. 'The quick brown fox.' becomes ['The', 'quick', 'brown', 'fox.'] 

# keep track of which word we are up to: 
wordNumber = -1 # -1 as we haven't started yet

# now define a function which we can use here and later on to replace letters with '-': 

def replaceWithdash(textList, currentWordNumber): 
    dashSentence = ''
    for index, word in enumerate(textList): # cycle through the words and their index numbers 
        if index != currentWordNumber: 
            dashSentence = dashSentence + '--' * len(word) + '--' # add a string of dash characters 
        elif wordNumber==5: 
            dashSentence = dashSentence + ' ' + word + '.'# the last word will appear with a period
            dashSentence = dashSentence + ' ' + word + ' ' # except for the current word 
    return dashSentence # yields the manipulated sentence 

# now at the very beginning of the trial, we need to run this function for the 
# first time. As the current word number is -1, it should make all words '-'. 
# Use the actual name of your Builder text component here: 

text.text = replaceWithdash(sentenceList, wordNumber) 

# In the Builder interface, specify a "constant" value for the text content, e.g. 
# 'test', so it doesn't conflict with our code.

At Each Frame

keypresses = event.getKeys() # returns a list of keypresses 

if len(keypresses) > 0: # at least one key was pushed 
    if 'space' in keypresses:
        thisResponseTime = t # the current time in the trial 
        wordNumber = wordNumber + 1 
        if wordNumber == 6:
            thisExp.addData('word' + str(wordNumber), thisResponseTime - timeOfLastResponse) 
            timeOfLastResponse = thisResponseTime
            continueRoutine = False
        elif wordNumber < len(sentenceList) + 1:
            if wordNumber == 0: # need to initialise a variable: 
                timeOfLastResponse = 0 
            # save the inter response interval for this keypress, 
            # in variables called word0, word1, etc: 
            thisExp.addData('word' + str(wordNumber), thisResponseTime - timeOfLastResponse) 
            timeOfLastResponse = thisResponseTime 
            # update the text by masking all but the current word  
            text.text = replaceWithdash(sentenceList, wordNumber)

    elif 'escape' in keypresses: 
            core.quit() # I think you'll need to handle quitting manually now.

The normal trial looks like this(time scale is different)

The sentence that appears before the cross is the probe question where keyboard response is allowed only for ‘f’ and ‘j’

2. The Problem

It is perfect. However, if the participant unintentionally presses ‘space’ at the ‘probe’ routine(which is separated from ‘trial’ routine and contains no code component), this somehow triggers the first word of the sentence from next trial repeat to be revealed even before the participant press ‘space’ again. In other words, the stage where the whole sentence is masked with dashes disappears if participant press ‘space’ in the previous loop of the ‘probe’ routine.

I examined the cause of the problem and tried to fix it in terms of code component of the builder view but I failed. The main cause is with the variable called ‘wordNumber’. If you see the code, at the Begin Routine stage, the wordNumber is set to -1. If the wordNumber is -1, the first appearance of the sentence is fully covered by dashes. And after the participant presses the very first ‘space’, wordNumber becomes 0 by the code at the Each Frame. And as the ‘space’ input continues, wordNumber escalates upto 6 to reveal the last word, store the RT of that ‘space’ and finish the routine.
As far as I understand, if the ‘trials’ routine is over, the keyboard component of that routine must halt too. But somehow it doesn’t and it is active until the next repeat of the whole loop starts. I tried really really (about 30 hrs) a lot to fix this but it just doesn’t seem easy. The point is, wordNumber should be -1 again after the sentence was fully revealed and it should not change until the next fully masked sentence appears. But pressing ‘space’ still works even after the ‘trials’ routine has ended eventhough I did not state ‘space’ in the ‘probe’ routine.
The list of the keys in the keyboard component of the routine ‘probe’ only states two keys ‘f’ and ‘j’.

The gif below is the summary of what happens if participant presses ‘space’ when probe sentence is on. You can see that secone sentence appears with first word(혁수가) unveiled.

I also attached two keyboard component properties, one from ‘trial’ routine and one from ‘probe’ routine.

If there are any other information I can provide, please tell me so. I didn’t attach the psyexp file because it contains settings for Korean and it might not work in most of the readers’ environment.

Thank you for reading this long post.


Hi Kyung,

Your experiment is looking great: thanks for sharing the GIF, which nicely illustrates for others how this paradigm works.

Your issue should be a simple one to fix. Keyboard events get stored in a buffer, because code is not always able to process them immediately when they occur. So I suspect what is happening is that your participants push space at some point soon after you collect the f or j response, so it isn’t immediately handled (i.e. the operating system still collects keypresses, regardless of whether or not a Builder keyboard component is running). That space bar key press remains in the buffer, and will get detected by the current code component’s event.getKeys() function in your trial routine, as if it has just occurred.

The Builder keyboard component has an option to clear these events (the “Discard previous” option), and we need to implement that in our code too. Simply go to the Begin routine tab of your code component and insert this:

    # remove any keypresses remaining in the buffer from 
    # before  this routine started:

Problem solved!

I remember try using that code but it seems I couldn’t figure out where to put it. I put that code at the top of the previous code component ‘Begin Routine’ and solved the problem. Now I have better understanding on how buffer works.

Thank you so much.