命令行上无缓冲的非阻塞键盘输入



我想以非阻塞的方式立即在命令行上捕获"所有"键盘输入(无需等待新行)。

此问题演示如何使用 select() 以非阻塞方式读取stdin。这是它的工作原理:

while True:
    if select.select([sys.stdin], [], [], 0)[0] == [sys.stdin]:
        print(sys.stdin.read(1))
    ... do other stuff ...

不幸的是,您只有在按 RETURN 后才能获得结果。

我的第一个猜测是stdin只是行缓冲,所以在阅读这个问题后,我将我的代码变成了

ubuf_stdin = os.fdopen(sys.stdin.fileno(), 'rb', buffering=0)
while True:
    if select.select([ubuf_stdin], [], [], 0)[0] == [ubuf_stdin]:
        print(ubuf_stdin.read(1))
    ... do other stuff ...

这段代码效果更好 - 缓冲区被完全读取而不会中断 - 但它仍然等待RETURN被按下。

我也试图detach stdin

ubuf_stdin = os.fdopen(sys.stdin.detach().fileno(), 'rb', buffering=0)

按键后如何立即对键盘输入做出反应?

使用 getch 模块一次获取一次一次按键,如本问题中所述。

我不认为你能够以一种非阻塞但一次字符的方式阅读 stdin,它真的不是为了这个目的。

好的,

这个可以做到,但它有一些缺点:

  • 使用对我来说似乎有点重的curses模块
  • 输入必须轮询 - 尚无法select()
  • 键盘输入仍会打印到终端

.. 但它:)有效。

import curses
def read_stdin(self):
    def cb(screen):
        result = []
        screen.nodelay(1)
        while True:
            try:
                result.append(screen.getkey())
            except curses.error:
                return result
    # contains a list of keys pressed since last call
    return curses.wrapper(cb)

最新更新