在Unix系统中,使用Python读取单个字符(类似于getch)的方法不起作用

4
每次我使用http://code.activestate.com/recipes/134892/上的配方时,似乎都无法正常工作。它总是抛出以下错误:
Traceback (most recent call last):
    ...
    old_settings = termios.tcgetattr(fd)
termios.error: (22, 'Invalid argument)

我认为问题可能是因为我在Eclipse中运行它,所以termios对文件描述符感到不满。

2个回答

9
这在Ubuntu 8.04.1,Python 2.5.2上可以正常工作,我没有遇到这样的错误。也许您应该尝试从命令行运行它,因为Eclipse可能正在使用自己的标准输入,如果我从Wing IDE运行它,我会得到完全相同的错误,但是从命令行运行它非常好。 原因是IDE(例如Wing)使用自己的类netserver.CDbgInputStream作为sys.stdin,因此sys.stdin.fileno为零,这就是错误的原因。 基本上,IDE的标准输入不是tty(print sys.stdin.isatty()为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()

不支持箭头键 - 在缓冲区中留下额外的字符。 - anatoly techtonik

5

将终端设置为原始模式并不总是一个好主意。实际上,只需要清除ICANON位。这是另一个支持超时的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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接