Trouble converting coder to builder using keyboard library

Hi all!

I am designing an experiment that shows a square at variable positions and at variable durations. This is followed by a response screen where participants try and mimic the amount of time that the square was onscreen for. The code below works in coder view:

from psychopy import visual, event, core
from psychopy.hardware import keyboard


kb = keyboard.Keyboard()

win = visual.Window()

win.flip()

rect = visual.Rect(
    win, # Where to display
    units="norm", # What unit
    width=.1, # Original width
    height=.1,# Original height
    pos=[0,0],
    fillColor=[-1,-1,-1], # Black
    lineColor=[-1,-1,-1]  # Black
    )

for i in range(5):
    rect.draw()
    win.flip()
    core.wait(1)

    continuing = True

    while continuing:
        core.wait(0.5)
        remainingKeys = kb.getKeys(waitRelease=True)
        if remainingKeys:
            for key in remainingKeys:
                if key.name=='space':
                    print(key.duration)
                    continuing = False
    win.flip()

However, when I try and set this up in Builder I run into some issues!

I have a loop of 5 trials that contains a square routine and a feedback routine. The square routine is really just a square presented for one second, there isn’t much point to doing variable positions and durations if I can’t get the keypresses to work yet!

I am confused about whether the feedback component should just be a code snippet or if there should also be a keyboard object.

I have tried it both ways with poor results. When I just have the code snippet it shows the square, but never stops showing it.

When I have the code snippet + the keyboard object it sporadically shows nothing or the square.

I apologize if this has been asked before, and appreciate the time and effort!

Thank you! :smile:

When using code in Builder, you have to operate within some constraints. namely Builder scripts have their own drawing and event loop cycle. That is, Builder aims to update the screen and check for responses on every screen refresh (typically 60 times per second). So the Builder script issues its own win.flip() once per cycle: you should never call that yourself, or you will muck up its careful timing. Similarly, you should never call core.wait() in a Builder script: that will completely disrupt its win.flip() drawing cycle for the duration of the wait period.

Having said all that, you haven’t really described what it is you want to do. It’s quite possible that no code is required at all. Please just describe the task sequence and let’s go from there.

Hi Michael,

Thank you for the reply and for this tips. I can see now why using win.flip and core.wait inside of builder would cause some inconsistencies (and it explains a few of the error messages!).

Overall, the experiment I am building has four conditions. Two of those conditions require logging a keypress that is held down. From what I have seen by playing around with Builder and the Keyboard object, as soon as it registers a keypress (whether held down or not) it advances to the next trial.

The task I am working on involves displaying a square that is either in a sine-wave motion or in variable positions on the screen. In both conditions the square is shown for a variable duration as well. The task is for participants to try and replicate the duration they believe the square was shown for with a keypress.

For example:

If the square was shown for 1s the participant would press Space and release it (total duration = 1s). For a square that is shown for .5s we would expect a .5s keypress.

This is a video of what the task should look like (this is using coder only). You will also see this is a minimal example with no durational or positional variations.

I hope this isn’t too long of a response, I just wanted to make sure that I explained myself properly. Thank you so much!

I managed to get it to work by using a code snippet in builder:

from psychopy import event

kb = keyboard.Keyboard()

continuing = True

while continuing:
    remainingKeys = kb.getKeys(waitRelease=True)
    if remainingKeys:
        for key in remainingKeys:
            if key.name=='space':
                continuing = False

I have the square as one routine, a blank text object as a routine, and the code snippet as a routine.

Now to convert this to JS…