用Python读取单个字符(getch样式)在Unix中不起作用

用Python读取单个字符(getch样式)在Unix中不起作用,python,getch,Python,Getch,每次我用这个食谱时,我似乎都无法使它起作用。它总是抛出以下错误: Traceback (most recent call last): ... old_settings = termios.tcgetattr(fd) termios.error: (22, 'Invalid argument) 我最好的想法是,这是因为我在Eclipse中运行它,所以termios对文件描述符进行了调整。这是在Ubuntu 8.04.1、Python 2.5.2上运行的,我没有收到这样的错误。可

每次我用这个食谱时,我似乎都无法使它起作用。它总是抛出以下错误:

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

我最好的想法是,这是因为我在Eclipse中运行它,所以
termios
对文件描述符进行了调整。

这是在Ubuntu 8.04.1、Python 2.5.2上运行的,我没有收到这样的错误。可能您应该从命令行尝试,eclipse可能使用它自己的stdin,如果我从WingIDE运行它,我会得到完全相同的错误,但从命令行它工作得很好。 原因是IDE例如Wing使用自己的类netserver.CDbgInputStream作为sys.stdin 因此sys.stdin.fileno为零,这就是错误的原因。 基本上IDE stdin不是tty(print sys.stdin.isatty()为False)


将终端置于原始模式并不总是一个好主意。事实上,这已经足够清理一点了。下面是另一个支持超时的getch()版本:

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()

不适用于箭头键-在缓冲区中留下额外字符。
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()