如何在不阻塞整个应用程序的情况下读取单个按键? [英] How to read single keystrokes without blocking the whole application?
问题描述
因为我没有找到更好的方法来读取命令行,所以我目前正在使用 getch()
.
Because I didn't find a better way to read keystrokes on command line I'm currently using getch()
.
不幸的是,像这样使用 getch()
会停止在 stdout
上输出:
Unfortunately using getch()
like this stops output on stdout
:
while True:
handle_keystroke(getch())
按下按钮会触发 handle_keystroke()
和 stdout
在终端上打印-每次击键都逐行打印.
Pressing buttons triggers handle_keystroke()
and stdout
is being printed in the terminal - line by line for each keystroke.
在此处提供的建议没有帮助.
Recommendations provided here didn't help.
我该怎么办?
顺便说一句:我不需要使用 getch()
.有没有更好的方法(例如,使用 select()
)?
Btw: I do not need to use getch()
. Is there a better way (e.g. using select()
)?
更新 :(已更改标题)
仅当您使用多个线程时,所有这些才成为问题.因此,看起来 getch
(这是一个非Python函数)不会释放GIL,因此所有其他线程均被挂起,因此不仅
All this becomes a problem only when you're using more than one thread. So it looks like getch
(which is a non Python function) doesn't release the GIL, so all other threads are suspended, so not only stdout
is affected.
推荐答案
好,找到了一种使用 select
代替 getch()
的方法.诀窍是将 sys.stdout
的模式设置为 cbreak
:
Ok, found a way to use select
instead of getch()
. The trick is to set the mode of sys.stdout
to cbreak
:
import select
import tty
import termios
from contextlib import contextmanager
@contextmanager
def cbreak(stream):
"""Set fd mode to cbreak"""
old_settings = termios.tcgetattr(stream)
tty.setcbreak(stream.fileno())
yield
termios.tcsetattr(stream, termios.TCSADRAIN, old_settings)
with cbreak(sys.stdin):
while True:
select.select([sys.stdin], [], []) == ([sys.stdin], [], [])
key = sys.stdin.read(1)
handle_keystroke(key)
这篇关于如何在不阻塞整个应用程序的情况下读取单个按键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!