Handling Non-Blocking Input with Curses in Python

What will you learn?

In this tutorial, you will delve into managing non-blocking input using Python’s curses library. You’ll grasp a practical approach to utilize getch() without pausing your application, essential for interactive terminal-based programs.

Introduction to the Problem and Solution

When developing terminal-based applications in Python, such as games or interactive tools, efficiently handling user inputs without stalling the program flow is crucial. The conventional method of using curses.getch() for capturing keystrokes inherently halts program execution until an input is received. This behavior isn’t suitable for scenarios requiring continuous screen updates or concurrent tasks.

To tackle this challenge, we’ll harness the capabilities of the curses module to establish a non-blocking input mechanism. This involves configuring getch() to operate in a non-blocking mode and integrating it within an event loop to maintain application responsiveness. By the end of this guide, you’ll have acquired the skills to implement a basic yet effective solution for managing user inputs asynchronously in a Python curses application.


import curses

def main(stdscr):
    # Initialize curses window
    stdscr.nodelay(True)  # Set getch() non-blocking

    stdscr.addstr("Press 'q' to exit...\n")

    while True:
        char = stdscr.getch()

        if char == ord('q'):  # Exit loop if 'q' is pressed
        elif char != -1:  # Check if any key was pressed (-1 indicates no key press)
            stdscr.addstr(f"Key pressed: {chr(char)}\n")

        # Insert any additional code for background tasks here


# Initialize curses application

# Copyright PHD


The provided code snippet illustrates how to configure and utilize curses.getch() in a non-blocking manner within a Python script. Here are the key components explained:

  • Curses Initialization: Safely initialize and terminate the curses application using curses.wrapper(main) by passing our main function.
  • Non-Blocking Configuration:
    • Call stdscr.nodelay(True) on the standard screen object (stdscr) from the wrapper function to make getch() return immediately.
    • When no key is pressed, -1 is returned by getch(), allowing continuous checking of new inputs while executing other tasks.
  • Event Loop: The infinite loop (while True:) acts as our event processor where keyboard inputs are detected and handled.

By following these steps, we create an environment where user interactions can be dynamically captured without disrupting ongoing processes or animations within our terminal-based application.

  1. How do I install the curses module?

  2. On Linux and macOS, curses is included in Python’s standard library. For Windows users, install windows-curses via pip:

  3. pip install windows-curses
  4. # Copyright PHD
  5. Can I capture special keys like arrow keys using getch()?

  6. Yes, enable keypad mode with stdscr.keypad(True) so that special keys are interpreted correctly by curses.

  7. How do I clear the screen?

  8. Use stdscr.clear() before drawing new content during each iteration of your main loop.

  9. Is there a way to read strings instead of single characters?

  10. For reading strings or handling complex input scenarios, consider using text boxes or forms from higher-level libraries built on top of curses like npyscreen.

  11. Does nodelay mode affect CPU usage?

  12. Enabling nodelay makes your loop execute continuously without pause which might increase CPU usage; adding a small delay (e.g., time.sleep(0.01)) inside your loop can mitigate this effectively.


Exploring asynchronous input handling with Python’s curse library showcases one aspect of constructing interactive terminal applications that are pivotal for creating dynamic and responsive interfaces. Leveraging such functionalities requires understanding fundamental programming constructs alongside specific library features tailored for efficient IO operations.

Leave a Comment