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,
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