Quick answer: Call pygame.event.get() every frame without exception. If your game loop has long operations (file I/O, network, heavy computation), the event queue fills up (128 events max) and silently drops new events. Filter unneeded event types with set_blocked() and use get_pressed() for continuous input alongside KEYDOWN for one-shot input.

Here is how to fix Pygame event queue overflow losing inputs. Your game drops key presses. The player mashes the jump button and nothing happens. You press Escape to pause and it takes three tries. Mouse clicks vanish. The game worked fine during light testing but falls apart during real play when lots of inputs happen quickly. The underlying cause is almost always the event queue overflowing because your main loop does not drain it fast enough.

The Symptom

Key presses are intermittently missed. KEYDOWN events that should fire never appear in the event loop. The problem gets worse during frame rate drops, loading sequences, or when the game performs heavy computation. QUIT events are also missed, making it impossible to close the window cleanly. The OS may show a “not responding” dialog on Windows because the application is not processing window messages.

Continuous input (holding a key to move) works fine because get_pressed() checks current key state. But one-shot actions (jumping, attacking, menu selection) use KEYDOWN events, and those are lost.

What Causes This

1. Event queue has a fixed size. Pygame’s internal event queue holds approximately 128 events. Every key press, key release, mouse motion, mouse button, window focus, and system event goes into this queue. If event.get() or event.pump() is not called frequently enough, the queue fills up and new events are silently discarded.

2. Long operations block the main loop. Loading a large file, computing pathfinding, or making a network call on the main thread can block for hundreds of milliseconds. During that time, the OS queues input events. If more than 128 accumulate, the oldest are dropped.

3. Mouse motion floods the queue. Moving the mouse generates a MOUSEMOTION event for every pixel of movement. A single fast mouse swipe can generate 50-100 events, filling most of the queue and pushing out keyboard events that happened during the same frame.

The Fix

Step 1: Drain the event queue every frame, unconditionally.

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True

while running:
    # ALWAYS drain the queue first, every frame
    events = pygame.event.get()

    for event in events:
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.jump()
            elif event.key == pygame.K_ESCAPE:
                toggle_pause()

    # Use get_pressed for continuous movement
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player.move_left()
    if keys[pygame.K_RIGHT]:
        player.move_right()

    update(clock.get_time())
    render(screen)
    pygame.display.flip()
    clock.tick(60)

Step 2: Block event types you do not need.

# Block mouse motion events if you only care about clicks
pygame.event.set_blocked(pygame.MOUSEMOTION)

# Or allow only the events you care about
pygame.event.set_allowed(None)  # Block everything first
pygame.event.set_allowed([
    pygame.QUIT,
    pygame.KEYDOWN,
    pygame.KEYUP,
    pygame.MOUSEBUTTONDOWN,
    pygame.MOUSEBUTTONUP,
])

Step 3: Pump events during long operations. If you cannot avoid blocking the main thread, pump the event queue periodically:

def load_level(path):
    # Process in chunks, pumping events between each
    chunks = split_file_into_chunks(path, chunk_size=4096)
    for chunk in chunks:
        process_chunk(chunk)
        pygame.event.pump()  # Prevent queue overflow and OS "not responding"

“The event queue is a buffer, not a log. When it is full, new events do not wait — they vanish. Call event.get() like your game depends on it, because it does.”

Why This Works

Pygame’s event system is built on SDL, which receives raw input from the OS and queues it in a fixed-size buffer. event.get() empties the buffer into a Python list, making room for new events. event.pump() processes the OS event queue without returning events to Python, but still clears the internal buffer. Both are essential for keeping the pipeline flowing. Without either, the OS-level queue backs up, the SDL buffer fills, and events are discarded from the front to make room for new system events.

Using get_pressed() for continuous input is resilient to queue overflow because it reads the current keyboard state directly from SDL, bypassing the event queue entirely. Combining both patterns — events for one-shot actions, state polling for continuous actions — gives you robust input handling even during frame drops.

Related Issues

If your game loop has consistent frame rates but still misses inputs, the issue may be frame-rate-dependent input. See Fix: Pygame Clock Tick Drifting Over Time for stable timing patterns that ensure your input processing runs at a predictable rate.

If QUIT events are missed and the window freezes, ensure event.get() or event.pump() runs even during loading screens and cutscenes. The OS requires event processing to consider the application responsive.

event.get() every frame. Block MOUSEMOTION if you do not need it. Pump during long loads.