如何在不阻塞整个应用程序的情况下读取单个按键? [英] How to read single keystrokes without blocking the whole application?

查看:59
本文介绍了如何在不阻塞整个应用程序的情况下读取单个按键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为我没有找到更好的方法来读取命令行,所以我目前正在使用 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,因此所有其他线程均被挂起,因此不仅 stdout 受到了影响.

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆