I'm setting up an experiment on psychopy in which a stimulus is displayed on the screen for a set period of time (say 0.5s), after which a blank screen is presented with a fixation. I'm using event.waitKeys() in order to get Keyboard input.
I have written the following code.
for i in range (1, 21):
answer = cf.Stimulus() #This is a function for generating the stimulus
img = visual.ImageStim(
win=win,
image="temp.jpg",
units="pix"
)
img.draw() #This is the first screen
fixation.draw()
win.flip()
core.wait(0.5)
fixation.draw() #This is the second screen
win.flip()
keysarray = event.waitKeys()
os.remove('temp.jpg')
The problem which I'm running into here is that, if the keyboard input has been received before the wait time of 0.5 ends in the first screen, events.waitKeys() doesn't register this key entry and still waits on the second screen for the keyboard input. The program only moves forward if a key entry is received for the second screen.
Instead, I want the program to go to the next stimulus whenever a keyboard input is presented between the start of screen 1 to the end of screen 2. That is, if the keyboard input is received in screen 1 itself (before the end of 0.5s), I want the input to be registered and the program to move on to the next stimulus (either by moving to screen 2 for a very short duration of time, or by skipping screen 2 all together). I can't seem to figure out how this can be achieved.
The short answer here is that event.waitKeys() defaults to clearing the event queue, so that only new keypresses are detected. You can get the behaviour you want by overriding that:
keysarray = event.waitKeys(clearEvents=False)
But I think that keys pressed prior to calling the function would not have useful reaction times recorded (although keyboard handling has changed a lot in version 3.1).
Having said that, there are a bunch of other issues with this code that could be improved to fit a more optimal PsychoPy style. I'd suggest posting it at the user forum at https://discourse.psychopy.org. That forum is better suited to back-and-forth discussions than the single question/answer format here at SO.
Related
I was experimenting with pygame and noticed it raised a VideoExpose event when I press alt+tab and the window is fullscreen. when I switch press alt+tab again, everything on the screen is moved to the bottom left.
I know that this is supposed to mean that 'portions of the window must be redrawn', but how am I supposed to redraw them and what why does pygame even have this event in the first place?
If you are writing a program to use the windowing Event Model, the windowing environment sends the program events to notify it of environmental changes - window resize, mouse move, need to re-paint, etc.
Not handling these events will cause your application to be considered "non responsive" by the environment. Here on SO, there's about one question a week with PyGame and exactly this issue.
When working with PyGame re-drawing event handling may seem superfluous as the majority of PyGame games redraw the entire screen every frame, e.g.: 60 FPS. But if unnecessary, this method is a complete waste of resources (CPU-time, electricity, etc.) It is quite simple though, so good for beginners.
Say you were writing a card game like Solitaire... the screen updates only when interacting with the user. In terms of CPU, it's doing nothing 99.9% of the time while the user contemplates their next move. In this case, the program could be written to only re-draw the screen when necessary. When is it necessary? When the player gives input, or the program receives a pygame.VIDEOEXPOSE event from the widowing environment.
If your program is redrawing the window constantly, you can simply ignore the message. If not, when receiving the message call whatever block of code is normally used to render the window. The expose message may come with the region of the screen that needs to be re-drawn, in this case a really good application would only update that section of the display.
First scene with first mouse press
That first onMousePress function makes the background change.
Second scene with second mouse press
This second onMousePress function is planned to make the barrels disappear but it just kind of replaces the first onMousePress and makes it so that's the only one that works. Also ignore the 2 and the fact that it actually makes a rectangle, the 2 made it not work so I can click on the future tp and the rect is for testing purposes
You can set flag of first click and some small wait time. If the event is triggered second time it is double click, otherwise it is single click when time runs out. You need to set wait time in parallel thread or use something like timer. And don't forget to reset your flag everytime.
I'm new to Python and I'm programming a simple psychology experiment. In a nutshell, I'm presenting participants with a series of randomized images and having them to press one key if they detect a face in a given image.
One of my problems is that the program crashes when participant presses the key too fast - that is, I've noticed that the program logs responses even if the participant is pressing a key when there is no image present. Each image will only be present on the screen for 10 seconds. Participant usually takes ~0.5 second on average to make a response.
Is there a key for me to program the experiment so that that Psychopy will only log key presses ONCE, AFTER image is presented on screen? I've pasted my code below.
Thanks so much.
StimList=['Face1.png','Face2.png',]
StimList.extend(['Noise1.png','Noise2.png'])
# randomize lists:
numpy.random.shuffle(StimList)
outstr=""
for TrialNo in range(len(StimList)):
# load our image:
img=visual.ImageStim(
win=win,
image=StimList[TrialNo],
)
# draw the fixation cross and wait for trial start:
win.flip()
time.sleep(1) # wait 1 second on fixation cross
# start a trial: loop until a key has been pressed (or trial times out)
FaceDetected=0 # same as false
Responded=0 #revise
timer=core.Clock()
timer.reset()
while (not Responded) and (timer.getTime()<TimeOut): #remove not responded
img.draw()# outside loop
win.flip() #outside loop
keys=event.getKeys(keyList=['y','Y', 'n','N'], modifiers=False, timeStamped=timer)
if keys:
if (keys[0][0]=='y') | (keys[0][0]=='Y'):
FaceDetected=True
Responded=True
RT=keys[0][1]
elif (keys[0][0]=='n') | (keys[0][0]=='N'):
FaceDetected=False
Responded=True
RT=keys[0][1]
outstr=outstr+str(TrialNo)+", "+ StimList[TrialNo] +", "+str(FaceDetected)+", "+str(RT)+"\n"
print(outstr)
# first open the file:
outfile=open('tmpdata.csv', 'w')
outfile.write(outstr)
outfile.close()
win.close()
There are a bunch of Python issues with the code above, which I suspect are due to negative transfer from another programming language. For example, in Python you should use or in logical comparisons, not |, which in Python is the operator for bitwise 'OR', a different beast. Also, you might want to try out the more Pythonic for TrialNo, stimulus in enumerate(StimList): in place of for TrialNo in range(len(StimList)):, and avoid standard Python functions like time.sleep() when you could have more precise control using PsychoPy's timing classes or screen refresh counting.
But in PsychoPy API-specific terms relevant to your main question, you need to call event.clearEvents() prior to first drawing your stimulus (e.g. when you reset the trial timer). That will clear the keyboard buffer of any previously-pressed keys.
In further PsychoPy-specific hints, avoid creating objects repeatedly. e.g. the timer only needs to be created once, at the start of the script. Then you just reset it once per trial. At the moment, the reset is actually redundant, as the timer is zeroed when it is created. Timers are simple and multiple creation doesn't really impact performance, but stimuli are more complicated and you should definitely avoid creating them over and over again. e.g. here just create your image stimulus once. Then on each trial, just update its image property. That itself takes time to do, as the file needs to be read from disk. So ideally you would be doing that during the fixation stimulus period, or between trials as it is currently.
Your code really shows a few issues rather than just the one you raised in the question. hence, you might find the forum at https://discourse.psychopy.org more useful than the single question and answer format here at SO.
So I have this script for controlling an LCD plate where I want the backlight to change every time you press a button, but also want to do other things as well. Currently this doesn't work and it doesn't display the messages I want it to.
This is the change backlight bit of code:
while True:
for b in btn:
if lcd.buttonPressed(b):
lcd.backlight(col[randint(0,5)])
And then I want to go on and run a bit of code that prints a string to the lcd and stuff, in this way:
lcd.message("This is a string")
but the script doesn't ever print the string, it just stays on the backlight change-y bit.
Basically I'm creating an index of letters that you can move through using the LCD buttons, and want the backlight to change each time you press a button.
The standard way is to have a single loop containing both. In the loop you first handles any input or state changes. Then at the end of your loop you update display. This is a fairly common paradigm in game programming see pygame for tons of examples. You would then only break once your program is terminating. One thing worth pointing out is that you would not want to block on checking for key press (or any input), otherwise you would hold up your display waiting for input.
sudo code would be something like:
while True:
for event in key_presses():
handle_event(event) # stuff that happens as a result of input
update_state() # stuff that happens regardless of input
update_display() # everything that changes the display (backlight, text, anything)
I wrote a simple python script that gives control over the cursor to a joystick. My way to find out how this works is documented here. Now that works flawlessly but, as soon as I start the script to use the joystick, the mouse is useless, because my python routine sets the value back to its original, whenever a new joystick event comes in.
Thus I want my joystick events to be ignored as long as a key of the keyboard is pressed. I came across the pygame.key.get_pressed() method but this seems to work only, if the pygame window is in focus. I want this script running in background. Should I start using non-pygame events to listen to the keyboard or are there ways to keep track of the keyboard events analogue to the joystick events, which are recognized in background, via pygame?
I expect pygame sets up its own "sandbox" so that it's hard to detect input from outside its window. Your previous question indicates that you are also using the win32api module. We can use that to detect global key presses.
The correct way to detect key presses at the global scope is to set up a keyboard hook using SetWindowsHookEx. Unfortunately, win32api does not expose that method, so we'll have to use a less efficient method.
The GetKeyState method can be used to determine whether a key is down or up. You can continuously check the state of a key to see if the user has pressed or released it lately.
import win32api
import time
def keyWasUnPressed():
print "enabling joystick..."
#enable joystick here
def keyWasPressed():
print "disabling joystick..."
#disable joystick here
def isKeyPressed(key):
#"if the high-order bit is 1, the key is down; otherwise, it is up."
return (win32api.GetKeyState(key) & (1 << 7)) != 0
key = ord('A')
wasKeyPressedTheLastTimeWeChecked = False
while True:
keyIsPressed = isKeyPressed(key)
if keyIsPressed and not wasKeyPressedTheLastTimeWeChecked:
keyWasPressed()
if not keyIsPressed and wasKeyPressedTheLastTimeWeChecked:
keyWasUnPressed()
wasKeyPressedTheLastTimeWeChecked = keyIsPressed
time.sleep(0.01)
Warning: as with any "while True sleep and then check" loop, this method may use more CPU cycles than the equivalent "set a callback and wait" method. You can extend the length of the sleep period to ameliorate this, but the key detection will take longer. For example, if you sleep for a full second, it may take up to one second between when you press a key and when the joystick is disabled.
when your window gains or looses focus you get an ACTIVEEVENT. It's gain and state attributes tell you which state you've gained or lost. The easisest solution would probably be to catch this events in your main event loop and use them to keep track weather you have focus or not. Then you can just ignore joystick events if you don't have the focus.