python tty.setraw Ctrl + C 不起作用(获取)

python tty.setraw Ctrl + C doesn't work (getch)

这是我的代码。

def getch():
    fd = sys.stdin.fileno()
    old_Settings = termios.tcgetattr(fd)
    try: 
        tty.setraw(sys.stdin.fileno())
        sys.stdin.flush()
    except KeyboardInterrupt:
        print ("[Error] Abnormal program termination")
    finally:
        termios.tcsetattr(fd,termios.TCSADRAIN,old_settings)
    return ch

在此代码中,KeyboardInterrupt 异常不起作用。

谢谢

是的,当您将 TTY 设置为原始模式时——或者,特别是当您禁用 termios 设置时 ISIG——您将不再获得相应的行为:

  ISIG   When any of the characters INTR, QUIT, SUSP, or DSUSP are
         received, generate the corresponding signal.

换句话说,字符 INTR,即大多数终端中的 ^C,不再生成 SIGINT 信号,即 is what Python uses to raise a KeyboardInterrupt.

这就是像 emacs 这样的全屏程序可以使用 ^C 作为控制字符而不只是退出的方式。

所以,有两个选择:


不要调用 setraw,而是设置你想要的一组 termios 标志,确保不要禁用 ISIG

值得查看 Python 的 tty.setraw 的源代码,以了解它到底做了什么,用作基准。

你可以在没有 ISIG 的情况下做同样的事情。但实际上,您应该阅读文档以了解其中每一项的含义。

并确保man termios在您自己的系统上,不要在线搜索;在 Linux 与 macOS/*BSD 上有些不同,甚至在相同 OS.

的版本之间也存在细微差别

即使阅读了文档并自己进行了试验,也可能并不完全清楚每个设置的效果。 This article 似乎很好地解释了进入原始模式的内容,以及每个相关标志的实际含义(尽管我只是快速浏览了一下——而且。再一次,你仍然需要阅读 man termios适用于您的平台)。


或者,您可以手动处理 ^C

您已经在使用 sys.stdin.read(1) 一次读取一个字符,因此当有人点击 ^C 时,您将读取一个 '\x03' 字符。

发生这种情况时,您可以为所欲为,包括 raise KeyboardInterrupt


附带说明,如果这是 Python 3,您可能希望以二进制模式阅读:

ch = sys.stdin.buffer.raw.read(1)
sys.stdin.flush()

(然后您将检查 b'\x03' 而不是 '\x03'。当然。)

在文本模式下,您应该一次获取一个完整的字符,即使它是 UTF-8(或您的语言环境)中的多字节字符。起初 似乎 更简单——但这实际上可能会产生误导,因为单个字符仍然可能只是击键的一部分。例如,对于大多数终端,向上箭头发送 3 个字符 ('\x1B[A'), butread(1)` 只会给您第一个字符。