0

I'm new to psychopy and python. I'm trying to program a way to quit a script (that I didn't write), by pressing a key for example. I've added this to the while loop:

while n < total
  start=time.clock()
  if len(event.getKeys()) > 0:
    break
  # Another while loop here that ends when time is past a certain duration after 'start'.

And it's not working, it doesn't register any key presses. So I'm guessing key presses are only registered during specific times. What are those times? What is required to register key presses? That loop is extremely fast, sending signals every few milliseconds, so I can't just add wait commands in the loop.

If I could just have a parallel thread checking for a key press that would be good too, but that sounds complicated to learn.

Thanks!

Edits: The code runs as expected otherwise (in particular no errors). "core" and "event" are included. There aren't any other "event" command of any kind that would affect the "key press log".

Changing the rest of the loop content to something that includes core.wait statements makes it work. So for anybody else having this difficulty, my original guess was correct: key presses are not registered during busy times (i.e. in my case a while statement that constantly checks the time), or possibly only during specific busy times... Perhaps someone with more knowledge can clarify.

zorgkang
  • 45
  • 1
  • 8
  • Do you call ``event.getKeys()`` elsewhere in the while-loop? It deletes all events if you do and that would explain the ``len``=0. – Jonas Lindeløv Oct 03 '14 at 11:54
  • Added a few details in the question. Short answer: no. – zorgkang Oct 03 '14 at 15:45
  • If core.wait() helps try also window.flip() (provided you create a visual.window object). If it all works you may write an answer to you question. I do not know the internals of psychopy so I'm not going to speculate why you experience these problems. However, bear in mind that core.wait() is generally recommended in tight loops to let the operating system "breathe" and thus avoid its intrusions at unpredicted times. – mmagnuski Oct 04 '14 at 12:28
  • @Impon The pulses are sent every few milliseconds so too fast for `window.flip()`. And I was hoping for a specific answer to: "When are key presses registered?" I only have a very partial answer based on about an hour of experience with PsychoPy... Also, good tip for letting the loop "breathe", that version indeed makes much more sense to me. – zorgkang Oct 04 '14 at 15:41
  • Another idea: can you get keypresses if you replace event.getKeys() with event.waitKeys()? It should halt everything and wait for any keypress. If not, try to run a Coder --> demo --> input, to see if they work. If they don't it's probably something about your system. If these work, I'm pretty clueless here. event.getKeys() returns a list of key-names since last call to event.getKeys() or since psychopy.event was loaded. – Jonas Lindeløv Oct 04 '14 at 18:52
  • @Jonas The input demo works, and again it works with `core.wait`. As you said `waitKeys` would wait so no reason to think that wouldn't work. Evidently, key events aren't registered or are buffered somewhere in the system while it is busy. I could research this behavior further, but I honestly don't have the time... which is why I asked for an expert opinion here. If someone wants to try, an infinite (or very long) loop with the if statement as in my post should be sufficient to reproduce what I saw. Possibly a PS2 keyboard might work where a USB wouldn't. Not sure what I had at work. – zorgkang Oct 04 '14 at 23:23

2 Answers2

2

....So I'm guessing key presses are only registered during specific times. What are those times? What is required to register key presses?....

To try and answer your specific question, the psychopy api functions/methods that cause keyboard events to be registered are ( now updated to be literally every psychopy 1.81 API function to do this):

  • event.waitKeys()[1]
  • event.clearEvents()[1]
  • event.getKeys()[2]
  • event.Mouse.getPressed()
  • win.flip()
  • core.wait()
  • visual.Window.dispatchAllWindowEvents()

1: These functions also remove all existing keyboard events from the event list. This means that any future call to a function like getKeys() will only return a keyboard event if it occurred after the last time one of these functions was called.

2: If keyList=None, does the same as *, else removes keys from the key event list that are within the keyList kwarg.

Note that one of the times keyboard events are 'dispatched' is in the event.getKeys() call itself. By default, this function also removes any existing key events.

So, without being seeing the full source of the inner loop that you mention, it seems highly likely that the event.getKeys() is never returning a key event because key events are being consumed by some other call within the inner loop. So the chance that an event is in the key list when the outer getKeys() is called is very very low.

Update in response to OP's comment on Jonas' test script ( I do not have enough rep to add comments to answers yet):

... Strange that you say this ..[jonas example code].. works and from Sol's answer it would seem it shouldn't. – zorgkang

Perhaps my answer is giving the wrong understanding, as it is intended to provide information that shows exactly why Jonas' example should, and does, work. Jonas' example code works because the only time key events are being removed from the event buffer is when getKeys() is called, and any events that are removed are also returned by the function, causing the loop to break.

Sol Simpson
  • 101
  • 3
  • If this is correct, then the inner loop code shouldn't matter other than the fact it did not contain any of these. But from Jonas' example, there may be others that should be on this list, maybe 'pass'? – zorgkang Oct 23 '14 at 06:29
1

This is not really an answer. Here's an attempt to minimally reproduce the error. If the window closes on keypress, it's a success. It works for me, so I failed to reproduce it. Does it work for you?

from psychopy import event, visual, core
win = visual.Window()
clock = core.Clock()
while True:
    clock.reset()
    if event.getKeys():
        break

    while clock.getTime() < 1:
        pass

I don't have the time module installed, so I used psychopy.core.Clock() instead but it shouldn't make a difference, unless your time-code ends up in an infinite loop, thus only running event.getKeys() once after a few microseconds.

Jonas Lindeløv
  • 5,442
  • 6
  • 31
  • 54
  • Not sure why, but I never got notified about this answer. I doubt I'll have a chance to try this soon, but the code did not do an infinite loop, it worked as expected and produced a pulse per outer loop iteration. Strange that you say this works and from Sol's answer it would seem it shouldn't... – zorgkang Oct 23 '14 at 06:14