I'm coding an experiment for an EyeTracker machine using PsychoPy.
As suggested in PsychoPy's google group, I've used the Builder View to create the basic structure of the experiment, compiled the script and then added modifications on the Coder View, so the way to handle user's input is the standard generated by PsychoPy. Since I need the user to write his/her input and then advancing to the next question by pressing the Enter key, I have 2 key response objects, so the first one collects user's input, while the second triggers when pressing the Enter key. For example:
# *B1_P2_key_01* updates
if t >= 0.0 and B1_P2_key_01.status == NOT_STARTED:
# keep track of start time/frame for later
B1_P2_key_01.tStart = t # underestimates by a little under one frame
B1_P2_key_01.frameNStart = frameN # exact frame index
B1_P2_key_01.status = STARTED
# keyboard checking is just starting
win.callOnFlip(B1_P2_key_01.clock.reset) # t=0 on next screen flip
if B1_P2_key_01.status == STARTED:
#theseKeys = event.getKeys(keyList=['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'])
theseKeys = event.getKeys(keyList=['num_1', 'num_2', 'num_3', 'num_4', 'num_5', 'num_6', 'num_7', 'num_8', 'num_9', 'num_0'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0 and b1p2_counter < 3: # at least one key was pressed
B1_P2_key_01.keys.extend(theseKeys) # storing all keys
B1_P2_key_01.rt.append(B1_P2_key_01.clock.getTime())
print "accepted key"
b1p2_counter += 1
# *B1_P2_key_02* updates
if t >= 0.0 and B1_P2_key_02.status == NOT_STARTED:
# keep track of start time/frame for later
B1_P2_key_02.tStart = t # underestimates by a little under one frame
B1_P2_key_02.frameNStart = frameN # exact frame index
B1_P2_key_02.status = STARTED
# keyboard checking is just starting
win.callOnFlip(B1_P2_key_02.clock.reset) # t=0 on next screen flip
event.clearEvents(eventType='keyboard')
if B1_P2_key_02.status == STARTED:
theseKeys = event.getKeys(keyList=['return'])
# check for quit:
if "escape" in theseKeys:
endExpNow = True
if len(theseKeys) > 0: # at least one key was pressed
B1_P2_key_02.keys = theseKeys[-1] # just the last key pressed
B1_P2_key_02.rt = B1_P2_key_02.clock.getTime()
# a response ends the routine
msg2='finish_b1p2_'+paths_list[imagecounter]
print msg2
#tracker.sendMessage(msg2)
continueRoutine = False
Please note that I need the user's input to be displayed on the screen as he/she types it, so I've implemented a solution based on the use of another TextStim object, as suggested on the group too:
# *B1_P2_resp_01* updates
if t >= 0.0 and B1_P2_resp_01.status == NOT_STARTED:
# keep track of start time/frame for later
B1_P2_resp_01.tStart = t # underestimates by a little under one frame
B1_P2_resp_01.frameNStart = frameN # exact frame index
B1_P2_resp_01.setAutoDraw(True)
displaystring=" ".join(B1_P2_key_01.keys) #convert list of pressed keys to string
displaystring=displaystring.replace(' ','') #remove intermediate spaces
# Do some text cleanup...replacing key names with puntuation and effectively disabling keys like 'back','shift', etc.
displaystring=displaystring.replace('space',' ')
displaystring=displaystring.replace('comma',',')
displaystring=displaystring.replace('lshift','')
displaystring=displaystring.replace('rshift','')
displaystring=displaystring.replace('period','.')
displaystring=displaystring.replace('back','')
displaystring=displaystring.replace('num_1','1')
displaystring=displaystring.replace('num_2','2')
displaystring=displaystring.replace('num_3','3')
displaystring=displaystring.replace('num_4','4')
displaystring=displaystring.replace('num_5','5')
displaystring=displaystring.replace('num_6','6')
displaystring=displaystring.replace('num_7','7')
displaystring=displaystring.replace('num_8','8')
displaystring=displaystring.replace('num_9','9')
displaystring=displaystring.replace('num_0','0')
#displaystring=displaystring.replace('backspace','')
#set text of AnswerDisplay to modified string
B1_P2_resp_01.setText(displaystring)
#print displaystring
Now my issue here is how to prevent the user from advancing if he/she hasn't typed anything, or if the values provided are outside of a given range (example: values can only go from 0 to 100). I'm aware that there are some alternatives out there, but using a structure different from PsychoPy's default one. And I need this input control to be implemented on the currently provided one.
I've tried to handle the Enter event, but the text object still records the enter key being pressed, so it changes its text. I've also tried to control it from the first key_response object, but then the other one in charge of handling the Enter key stops working.
Long story short, I need to set up a condition for the second key_response object (the one handling the Enter key) to decide if the user can advance to the next trial, while sticking to this format, plus not affecting the on-screen display of input.
Help on this subject would be much appreciated.
You haven't included the critical part, which is the loop around your first code snippet. This loop is probably something like
... which runs the code until continueRoutine is set to
False
which happens when the user presses return. You want to add one more condition. So something like this:You can be very flexible with these conditions, e.g. if you want a minimum of 5 seconds to pass, you would do