I’ve developed a modified Simon Task using the Builder (using PsychoPy 1.84 on Mac OS X), with various code components. In short, trial value is presented followed by either a blue or yellow circle presented to the left or right side of the screen and responses are indicated using the z (blue) or m (yellow) key.
However, I’m now aware (from reading Jon’s comments on an old thread: https://groups.google.com/forum/#!topic/psychopy-users/Y_zF3Q2Oxws) that when using getKeys() with the Builder, the program checks whether a key is pressed each frame, and consequently, the temporal resolution is restricted to the frame rate (i.e., every ~16ms).
Using “event.waitKeys” appears to offer a solution to; however, I’m struggling to work out how this could be best added to what I have already. Is it possible to add this as a code component in the Builder view? And if so, how exactly might I be able to do this?
Thanks in advance,
Harry
p.s., alternatively, if the only solution is to insert this in the coder, I have also appended the code (below) for the trial where I would like to include this.
# ------Prepare to start Routine "trial"-------
t = 0
trialClock.reset() # clock
frameN = -1
continueRoutine = True
# update component parameters for each repeat
polygon.setFillColor(targetcolour)
polygon.setPos((targetx, 0))
key_resp_2 = event.BuilderKeyResponse()
# keep track of which components have finished
trialComponents = [text, polygon, key_resp_2]
for thisComponent in trialComponents:
if hasattr(thisComponent, 'status'):
thisComponent.status = NOT_STARTED
# -------Start Routine "trial"-------
while continueRoutine:
# get current time
t = trialClock.getTime()
frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
# update/draw components on each frame
# *text* updates
if t >= 0.0 and text.status == NOT_STARTED:
# keep track of start time/frame for later
text.tStart = t
text.frameNStart = frameN # exact frame index
text.setAutoDraw(True)
frameRemains = 0.0 + 1.0- win.monitorFramePeriod * 0.75 # most of one frame period left
if text.status == STARTED and t >= frameRemains:
text.setAutoDraw(False)
# *polygon* updates
if t >= 1 and polygon.status == NOT_STARTED:
# keep track of start time/frame for later
polygon.tStart = t
polygon.frameNStart = frameN # exact frame index
polygon.setAutoDraw(True)
# *key_resp_2* updates
if t >= 1 and key_resp_2.status == NOT_STARTED:
# keep track of start time/frame for later
key_resp_2.tStart = t
key_resp_2.frameNStart = frameN # exact frame index
key_resp_2.status = STARTED
# keyboard checking is just starting
win.callOnFlip(key_resp_2.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if key_resp_2.status == STARTED:
theseKeys = event.getKeys(keyList=['m', 'z'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
key_resp_2.keys = theseKeys[-1] # just the last key pressed
key_resp_2.rt = key_resp_2.clock.getTime()
# was this 'correct'?
if (key_resp_2.keys == str(CorrectAns)) or (key_resp_2.keys == CorrectAns):
key_resp_2.corr = 1
else:
key_resp_2.corr = 0
# a response ends the routine
continueRoutine = False
# check if all components have finished
if not continueRoutine: # a component has requested a forced-end of Routine
break
continueRoutine = False # will revert to True if at least one component still running
for thisComponent in trialComponents:
if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
continueRoutine = True
break # at least one component has not yet finished
# check for quit (the Esc key)
if endExpNow or event.getKeys(keyList=["escape"]):
core.quit()
# refresh the screen
if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
win.flip()
# -------Ending Routine "trial"-------
for thisComponent in trialComponents:
if hasattr(thisComponent, "setAutoDraw"):
thisComponent.setAutoDraw(False)
# check responses
if key_resp_2.keys in ['', [], None]: # No response was made
key_resp_2.keys=None
# was no response the correct answer?!
if str(CorrectAns).lower() == 'none':
key_resp_2.corr = 1 # correct non-response
else:
key_resp_2.corr = 0 # failed to respond (incorrectly)
# store data for trials (TrialHandler)
trials.addData('key_resp_2.keys',key_resp_2.keys)
trials.addData('key_resp_2.corr', key_resp_2.corr)
if key_resp_2.keys != None: # we had a response
trials.addData('key_resp_2.rt', key_resp_2.rt)
if Condition == 1:#If this is a congruent trial
if key_resp_2.corr and key_resp_2.rt <= ResponseSpeed_CON: #check if response was correct and faster than current threshold for CONGRUENT TRIALs
ResponseSpeed_CON = ResponseSpeed_CON - .025 #if RT was quick enough, reduce threshold
elif key_resp_2.corr and key_resp_2.rt >= ResponseSpeed_CON: #check if response was correct but too slow, is so then increase RT.
ResponseSpeed_CON = ResponseSpeed_CON + .025
else: #if it is not a congruent trial then adjust RT for incgronguent trials
if key_resp_2.corr and key_resp_2.rt <= ResponseSpeed_INC: #check if response was correct and faster than current threshold for CONGRUENT TRIALs
ResponseSpeed_INC = ResponseSpeed_INC - .025 #if RT was quick enough and correct, reduce threshold
elif key_resp_2.corr and key_resp_2.rt >= ResponseSpeed_INC: #check if response was correct but too slow, is so then increase RT.
ResponseSpeed_INC = ResponseSpeed_INC + .025
trials.addData('ResponseSpeed_CON', ResponseSpeed_CON) # save updated response
trials.addData('ResponseSpeed_INC', ResponseSpeed_INC) # save updated response