psychopy.org | Reference | Downloads | Github

Keypress using event.watiKeys not working until after mouse click

It appears that neither the escape key or return key are able to perform their jobs until after the user has made a mouse click somewhere on the screen. I think this has something to do with the event.Mouse() I call in order for the user to use the mouse wheel to provide a continuous rating of the video on screen. If anyone can point out what is happening, that would be much appreciated- or direct me to the documentation that will explain.

from psychopy import visual 
from psychopy import gui, data, core,event
import csv
import time
from time import localtime, strftime, gmtime
from datetime import datetime
import os.path

# Kill switch for Psychopy3 
esc_key= 'escape'
def quit():
    """ quit programme"""
    print ('User exited')
    win.close()
    core.quit()
# call globalKeys so that whenever user presses escape, quit function called
event.globalKeys.add(key=esc_key, func=quit)

# User should set cwd to the experiment directory 
os.chdir('\\\\storage.its.york.ac.uk\\pshome\\blam500\\Downloads\\movie_study_0.8')
# User should set directory for output files to be stored 
save_path= '\\\\storage.its.york.ac.uk\\pshome\\blam500\\Downloads\\movie_study_0.8\\output\\continuous'

# instructions for the task can be updated here 
fear = """You will be presented with several videos.
\nThese videos will contain dangerous behaviour, strong language, disturbing images,threat and violence.If you find these types of videos distressing ,please do not participate and let the experimenter know.
\nIf at any point, you become distressed and would like to stop the task, please inform the experimenter.
You will not be penalised for withdrawing from the study. 
\nPlease continuously rate how frightening you feel the video is moment-to-moment using the wheel of the mouse. 
\nPress Enter to begin."""

uc = """You will be presented with several videos.
\nThese videos will contain dangerous behaviour, strong language, disturbing images,threat and violence.If you find these types of videos distressing ,please do not participate and let the experimenter know.
\nIf at any point, you become distressed and would like to stop the task, please inform the experimenter.
You will not be penalised for withdrawing from the study. 
\nPlease continuously rate how uncertain you feel the threat in the video is moment-to-moment using the wheel of the mouse. 
\nPress Enter to begin."""


# Create a dictionary to store information from the dialogue box
inputbox = {'expdate': datetime.now().strftime('%Y%m%d_%H%M'),'part_number':'','videoCondition':'','ratingCondition':''}
# Create dialogue box
# user enters participant number + video condition + rating required 
dlg=gui.DlgFromDict(inputbox, title = 'Input participation info',
                  	fixed='expdate',
                  	order=['expdate', 'part_number','videoCondition','ratingCondition'])

# If the user doesn't press ok, the programme will quit and inform user.
if not dlg.OK:
	print ("User exited")
	core.quit()

# Store participant number, videoCondition, ratingCondition and expdate provided by user as variables for later use 
part_number = inputbox['part_number']
videoCondition = inputbox['videoCondition']
expdate = inputbox['expdate']
ratingCondition = inputbox ['ratingCondition']

# create filename based on user input 
filename = '{}_{}_{}_{}.csv'.format(part_number, expdate, videoCondition,ratingCondition)
# update filename to include absolute path so that it is stored in output directory 
completeName = os.path.join(save_path, filename)
# open file for writing 
outputfile = open(completeName, "w",newline='')

# Create list of headers for output csv file 
fieldnames = ['videoName','Timestamp', 'Rating']

# create variable which calls DictWriter to write to outputfile and specifies fieldnames 
writer = csv.DictWriter(outputfile, fieldnames)
# writes headers using fieldnames as specified above when creating writer variable
writer.writeheader()

#function to present break and end screen
def break_end(video_name, participant_number, last=0):
    # Present break screen at the end of each set of questions
    if last==0:
        stim.setText("""You are welcome to take a break if you need to.
        \nPress enter when you are ready to continue.""")
        stim.draw()
        win.flip()
        # Wait for user to press Return to continue 
        key = event.waitKeys(keyList=(['return']), timeStamped = True)

    else:
        # Presents end screen at the end of task 
        stim.setText("""You have reached the end of the experiment. 
        \nPlease let the experimenter know you have finished. 
        \nThank you for your participation.""")
        stim.draw()
        win.flip()
        # Waits for user to press escape to exit experiment
        key = event.waitKeys(keyList=(['return']), timeStamped = True)
        

# Create white window for stimuli to be presented on throughout task 
win = visual.Window(size=[1024, 768], color=[1,1,1,], monitor="testMonitor", fullscr= True, allowGUI = False)

# Create text stimuli to be updated for start screen, break and end 
stim = visual.TextStim(win, "", color = [-1,-1,-1], wrapWidth = 1300, units = "pix", height=40)

# Use trialhandler to sequentially present films listed in filmlist csv file 
filmDict = data.TrialHandler(nReps = 1, method = 'sequential', trialList = data.importConditions('references\\filmList.csv'), name = 'filmList') 

# Create sliding scale to take continuous rating of uncertainty or fear while movie plays
if ratingCondition == 'uc':
    slidingscale = visual.Slider(win, ticks = [0,100], labels = ['certain', 'uncertain'], pos = (0.0, -0.7), granularity = 0)
elif ratingCondition == 'f':
    slidingscale = visual.Slider(win, ticks = [0,100], labels = ['frightening', 'not frightening'], pos = (0.0, -0.7), granularity = 0)

# Name mouse to be able to use for continuous rating below
mouse = event.Mouse()

# Update and show text to include instructions for task depending on rating condition entered in inputbox
if ratingCondition == 'f':
    stim.setText(fear)
    stim.draw()
    win.flip()
    # Wait for user to press Return to continue 
    key = event.waitKeys(keyList=(['return']), timeStamped = True)
else:
    stim.setText(uc)
    stim.draw()
    win.flip()
    # Wait for user to press Return to continue 
    key = event.waitKeys(keyList=(['return']), timeStamped = True)


# Loop through each film stored in filmDict created above using trialhandler 
for film in filmDict:
    
    # Store video name in thisRunDict to write to outputfile  
    thisRunDict= {'videoName': film[videoCondition] }
    
    # present movie using moviestim3
    mov = visual.MovieStim3 (win, film[videoCondition], size=(720,480), flipVert=False, flipHoriz=False, loop=False) #TO DO: fix size of video 

    # create a clock at the start of movie presentation 
    clock = core.Clock()
    clock.reset()  

    # set position of marker to middle of slider at the start of each video 
    slidingscale.markerPos = 50
    
    
    # create variable to use in loop to record rating every n seconds 
    rtscaleframe = 0

    # While moving is playing, present slidingscale and record marker position and timestamp in outputfile 
    while mov.status != visual.FINISHED:
        
        slidingscale.markerPos += mouse.getWheelRel()[1] # move marker according to mouse wheel movement
        slidingscale.draw()
        mov.draw()
        win.flip()
        # Run every 0.5 sec 
        if rtscaleframe % 30 == 0:
            rating = slidingscale.markerPos # store marker position as rating 
            thisRunDict['Rating'] = str(rating) # store rating in thisRunDict to write to outputfile
            thisRunDict['Timestamp'] = str(clock.getTime()) # store Timestamp of video to write to outputfile  
            # write responses and timings stored in thisRunDict to outputfile 
            writer.writerows([thisRunDict])
        rtscaleframe += 1 # needed to collect rating every 0.5 sec 

    # If statement to either present break screen or end screen
    nextTrial = filmDict.getFutureTrial(n=1) #fixes error for end screen  
    if nextTrial is None or nextTrial[videoCondition] != None:
        break_end(film[videoCondition], part_number) 
    else:
        break_end(film[videoCondition], part_number,1)

    outputfile.flush()