杰瑞科技汇

Python curses getkey如何实现按键捕获?

Of course! The curses library in Python is a powerful way to create terminal-based user interfaces (TUIs). A core part of any interactive application is handling user input, and curses provides several methods for this.

Python curses getkey如何实现按键捕获?-图1
(图片来源网络,侵删)

Let's break down the different ways to get key input, starting with the most common one, getkey().

stdscr.getkey() - The Simplest Method

stdscr.getkey() is the most straightforward way to get a single key press. It blocks execution, meaning your program will pause and wait until the user presses a key. It then returns the key as a string.

Key Characteristics:

  • Blocking: Your program waits.
  • Single Character: It returns one key press at a time.
  • Special Keys: For special keys (like arrow keys, function keys, Enter, Esc), it returns a multi-character string starting with an escape character (\x1b).

Basic Example

This program will wait for you to press any key and then display what key it was.

Python curses getkey如何实现按键捕获?-图2
(图片来源网络,侵删)
import curses
import time
def main(stdscr):
    # 1. Clear the screen
    stdscr.clear()
    # 2. Print instructions
    stdscr.addstr(0, 0, "Press any key to see what it is. Press 'q' to quit.")
    stdscr.refresh()
    # 3. Loop forever until 'q' is pressed
    while True:
        key = stdscr.getkey()  # This line will wait here for a key press
        # 4. Check if the key is 'q'
        if key == 'q':
            break
        # 5. Print the pressed key at the current cursor position
        # We use f-strings to show the raw key value
        stdscr.addstr(1, 0, f"You pressed: {repr(key)}")
        stdscr.refresh()
# The wrapper function handles initialization and cleanup
if __name__ == "__main__":
    curses.wrapper(main)

How to Run:

  1. Save the code as a Python file (e.g., getkey_example.py).
  2. Run it from your terminal: python getkey_example.py.
  3. Press various keys (letters, numbers, Enter, Tab, an arrow key).
  4. Press q to exit.

What you'll see:

  • Pressing a will show You pressed: 'a'.
  • Pressing Enter will show You pressed: '\n'.
  • Pressing the right arrow key will show You pressed: '\x1b[C'. This is the escape sequence for the right arrow.

stdscr.getch() - The Integer-Based Method

stdscr.getch() is very similar to getkey(), but it returns the key's integer value instead of a string. This can be useful for performance or when you want to compare keys numerically.

The integer values are often defined in the curses module (e.g., curses.KEY_RIGHT).

Basic Example

This example uses getch() and checks for the integer value of 'q' and the right arrow key.

import curses
def main(stdscr):
    stdscr.clear()
    stdscr.addstr(0, 0, "Press 'q' or the right arrow to quit.")
    stdscr.refresh()
    while True:
        # getch() returns an integer
        key_int = stdscr.getch()
        # Check for 'q' (its ASCII value is 113)
        if key_int == ord('q'):
            break
        # Check for the right arrow key (its curses constant is 261)
        if key_int == curses.KEY_RIGHT:
            stdscr.addstr(1, 0, "You pressed the RIGHT ARROW!")
            stdscr.refresh()
if __name__ == "__main__":
    curses.wrapper(main)

Handling Special Keys (Arrow Keys, F1, etc.)

As you saw, getkey() returns a string like '\x1b[C' for the right arrow. This string is called an "escape sequence". To handle these keys reliably, you should compare the result to the pre-defined string constants in the curses module.

The curses module provides helpful constants like:

  • curses.KEY_UP
  • curses.KEY_DOWN
  • curses.KEY_LEFT
  • curses.KEY_RIGHT
  • curses.KEY_HOME, curses.KEY_END
  • curses.KEY_F1 through curses.KEY_F12

Crucially, these constants are the string representations of the escape sequences.

Example: Handling Arrow Keys

This program demonstrates how to reliably detect arrow key presses.

import curses
def main(stdscr):
    stdscr.clear()
    stdscr.addstr(0, 0, "Use arrow keys to move the cursor. Press 'q' to quit.")
    y, x = 1, 1  # Initial position of the cursor
    while True:
        stdscr.addstr(y, x, 'O') # Draw the cursor
        stdscr.refresh()
        key = stdscr.getkey()
        # Erase the old cursor position
        stdscr.addstr(y, x, ' ')
        # Check for arrow keys using the curses string constants
        if key == curses.KEY_UP:
            y = max(1, y - 1)
        elif key == curses.KEY_DOWN:
            y = min(stdscr.getmaxyx()[0] - 2, y + 1)
        elif key == curses.KEY_LEFT:
            x = max(1, x - 1)
        elif key == curses.KEY_RIGHT:
            x = min(stdscr.getmaxyx()[1] - 2, x + 1)
        elif key == 'q':
            break
if __name__ == "__main__":
    curses.wrapper(main)

Non-Blocking Input (timeout)

Sometimes you don't want your program to pause. You want it to check for a key and, if none is pressed, continue with other tasks. This is called "non-blocking" input.

You can achieve this with stdscr.timeout().

  • stdscr.timeout(milliseconds): Sets a timeout for blocking functions.
    • timeout(-1): The default. Waits forever (blocking).
    • timeout(0): Non-blocking. Returns immediately with -1 if no key is pressed.
    • timeout(100): Waits for up to 100 milliseconds.

When using timeout(0)), you must check the return value ofgetkey()orgetch()for an error, which is usually-1`.

Example: Non-Blocking Input

This program will print a message every second, but it will also check if you've pressed 'q' to quit in the meantime.

import curses
import time
def main(stdscr):
    stdscr.clear()
    stdscr.addstr(0, 0, "Press 'q' to quit. The program will keep running.")
    stdscr.timeout(0)  # Set non-blocking mode
    counter = 0
    while True:
        # Check for a key without blocking
        key = stdscr.getch()
        if key == ord('q'):
            stdscr.addstr(2, 0, "Quitting...")
            stdscr.refresh()
            break
        # If no key was pressed, getch() returns -1
        if key == -1:
            # Do other work here
            counter += 1
            stdscr.addstr(1, 0, f"Running... {counter}")
            stdscr.clrtoeol() # Clear the rest of the line to avoid artifacts
            stdscr.refresh()
        # A small delay to prevent the loop from spinning too fast
        time.sleep(1)
if __name__ == "__main__":
    curses.wrapper(main)

Summary: getkey() vs. getch()

Feature stdscr.getkey() stdscr.getch()
Return Type String Integer
Use Case General purpose, easy to compare with literal strings ('q'), and curses.KEY_* constants. Performance-critical apps, or when you need to compare keys numerically.
Special Keys Returns a string like '\x1b[C'. Compare to curses.KEY_RIGHT. Returns an integer like 261. Compare to curses.KEY_RIGHT.
Blocking Yes (by default) Yes (by default)
Non-Blocking Use stdscr.timeout(0) and check for an exception or a specific return value. Use stdscr.timeout(0) and check if the return value is -1.

Best Practices

  1. Always use curses.wrapper(): It handles the necessary initialization (initscr, cbreak, noecho) and cleanup (endwin) automatically, even if your program crashes.
  2. noecho() is your friend: In most interactive
分享:
扫描分享到社交APP
上一篇
下一篇