Search code examples
pythoninputkeypygamekeydown

How can I efficiently hold a key in Pygame?


I've found two related questions:

But I want to be specific. How can I do it?

while not done:
    for e in event.get():
        if e.type == KEYDOWN:
            keys = key.get_pressed()
            if e.type == QUIT or keys[K_ESCAPE]:
                done = True
            if keys[K_DOWN]:
                print "DOWN"

When I press the down arrow, it prints, but it prints just once. If I want to print it another time, I need to press it again.

If I use the while keyword instead,

while keys[K_DOWN]:
    print "DOWN"

I get an infinite loop for some obscure reason.

This logical alternative is also useless:

if ((e.type == KEYDOWN) and keys[K_DOWN]):
    print "DOWN"

And there is this other one that somehow cleans the events and you can use while:

while not done:
    for e in event.get():
        if e.type == KEYDOWN:
            keys = key.get_pressed()
            if e.type == QUIT or keys[K_ESCAPE]:
                done = True
            while keys[K_DOWN]:
                print "DOWN"
                event.get()
                keys = key.get_pressed()

But you press the down key for less than one second and it prints thousands of times. (Moving a player would be impossible, and adjusting clock for this does not seem to be the right way to deal with it (And I've tried and I've failed miserably.).)

To press and execute the block thousands of times is useless. What I want, is to press the key and keep going with the action while I don't release it, within the defined game clock speed.


Solution

  • Don't mix up event.get() and key.get_pressed().


    If you press or release a key, and event is put into the event queue, which you query with event.get(). Do this if you're actually interested if a key was pressed down physically or released (these are the actual keyboard events. Note that KEYDOWN get's added multiple time to the queue depending on the key-repeat settings).

    Also, there's no need to query the state of all keys while handling a KEYDOWN event, since you already know which key is pressed down by checking event.key


    If you're interested in if a key is hold down (and ignoring the key-repeat, which you probably want), then you should simply use key.get_pressed(). Using a bunch of flags is just unnecessary and will clutter up your code.

    So your code could simplified to:

    while not done: 
        keys = key.get_pressed() 
        if keys[K_DOWN]: 
            print "DOWN" 
        for e in event.get(): 
            pass # proceed other events. 
                 # always call event.get() or event.poll() in the main loop