Leggere un singolo personaggio (stile getch) in Python non funziona in Unix
Domanda
Ogni volta che utilizzo la ricetta su http://code.activestate.com/recipes/134892 / Non riesco a farlo funzionare. Genera sempre il seguente errore:
Traceback (most recent call last):
...
old_settings = termios.tcgetattr(fd)
termios.error: (22, 'Invalid argument)
La mia migliore idea è che lo sia perché lo sto eseguendo in Eclipse, quindi termios
si sta adattando al descrittore di file.
Soluzione
Funziona su Ubuntu 8.04.1, Python 2.5.2, non ricevo questo errore. Forse dovresti provarlo dalla riga di comando, eclipse potrebbe usare il suo stesso stdin, ottengo lo stesso errore esatto se lo eseguo da Wing IDE, ma dalla riga di comando funziona alla grande. Il motivo è che IDE, ad esempio Wing, utilizza la propria classe netserver.CDbgInputStream come sys.stdin quindi sys.stdin.fileno è zero, ecco perché l'errore. Fondamentalmente IDE stdin non è un tty (print sys.stdin.isatty () is False)
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
getch = _GetchUnix()
print getch()
Altri suggerimenti
Mettere il terminale in modalità raw non è sempre una buona idea. In realtà è sufficiente cancellare bit ICANON. Ecco un'altra versione di getch () con supporto timeout:
import tty, sys, termios
import select
def setup_term(fd, when=termios.TCSAFLUSH):
mode = termios.tcgetattr(fd)
mode[tty.LFLAG] = mode[tty.LFLAG] & ~(termios.ECHO | termios.ICANON)
termios.tcsetattr(fd, when, mode)
def getch(timeout=None):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
setup_term(fd)
try:
rw, wl, xl = select.select([fd], [], [], timeout)
except select.error:
return
if rw:
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
if __name__ == "__main__":
print getch()