Mat*_*ete 5 python stdin blocking
我正在编写一个需要显式解析所有键盘输入的 python 应用程序。因此我写了一个小循环,不断从标准输入读取。这工作正常,但是, stdin.read(1) 会阻塞,直到我们键入一个字符。现在我希望它在(例如)1 秒后超时,以便其他事情可能发生。我在 python 中阅读了 select 模块,现在我有以下内容:
def getch(timeout):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
ch = None
try:
tty.setraw(fd)
rlist, _, _ = select([sys.stdin], [], [], timeout)
if len(rlist) > 0:
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
Run Code Online (Sandbox Code Playgroud)
这段代码的问题是,当我按下箭头键时,我只收到“\x1b”。select 函数永远不会为剩余的 '[' 和 'D' 触发。
如何正确读取这些箭头键字符?或者我怎样才能再次触发 select 函数(因为 stdin 上仍有可用的数据)。
谢谢!
箭头键是ANSI scape 序列。它们以 Escape(十六进制:\x1b、八进制:\033、十进制:)开头27,后跟括号[。以下是关键代码:
import sys, termios, tty
esc = 27
up = "\033[A"
down = "\033[B"
right = "\033[C"
left = "\033[D"
if __name__ == "__main__":
fd_input = sys.stdin.fileno()
# save previous terminal attributes
term_attrs_old = termios.tcgetattr(fd_input)
# Set terminal to raw mode. It gives you back what ever was typed,
# as raw bytes without any processing
tty.setraw(fd_input)
# read 4 bytes and encode it
ch = sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
if len(ch) == 1:
# if it is 1 char, and non-printable, return its Unicode code
if ord(ch) < 32 or ord(ch) > 126:
ch = ord(ch)
elif ord(ch[0]) == 27:
# if the input is more that 1 char and it starts with 27,
# user has entered a scape sequence
# read its rest
ch = "\033" + ch[1:]
if ch == down:
ch = "down"
if ch == up:
ch = "up"
if ch == right:
ch = "right"
if ch == left:
ch = "left"
# reset terminal back to its setting (disable raw mode again)
termios.tcsetattr(fd_input, termios.TCSADRAIN, term_attrs_old)
print(ch)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
340 次 |
| 最近记录: |