Reading a single character (getch style) in Python does not work on Unix

Every time I use a recipe at http://code.activestate.com/recipes/134892/ , I cannot get it to work. It always throws the following error:

Traceback (most recent call last): ... old_settings = termios.tcgetattr(fd) termios.error: (22, 'Invalid argument) 

My best thought is that this is due to the fact that I am running it in Eclipse, so termios throws the fit into the file descriptor.

+4
source share
2 answers

This works on Ubuntu 8.04.1, Python 2.5.2, I do not get such an error. Maybe you should try it from the command line, eclipse can use its own stdin, I get the same error if I run it from the Wing IDE, but from the command line it works fine. The reason is that the IDE, for example, Wing uses its own class netserver.CDbgInputStream as sys.stdin so sys.stdin.fileno is zero, which is why the error. Basically the IDE stdin is not 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() 
+9
source

Turning the terminal into raw mode is not always a good idea. In fact, this is enough to clear the ICANON bit. Here is another version of getch () with timeout support:

 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() 
+3
source

All Articles