Python – select 在无缓冲标准输入上

Python – select on unbuffered stdin

我在 python3 中真的很难缓冲。我正在尝试实现一个简单的收音机。

我有一个接收器class。它向用户显示可用的电台。这些电台是动态的,所以它们会出现和消失。

Welcome to the radio, select station you want to listen to.
> 1) Rock Station
  2) Hip Hop Station
  3) Country Station

因此接收器必须等待输入:来自 Pipe(有关新站的信息显示 up/disappearing)和来自 Stdin(用户可以使用向上和向下箭头更改站)。

此外,当用户使用箭头键更改电台时,我必须一次从标准输入读取一个字符。

这就是标准 select.select 不起作用的原因(它等待用户按下 ENTER 键):


class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch


self.char_reader = _GetchUnix()
[...]

def __read_order_from_user(self,):
    k = self.char_reader()
    # Check for up/down arrow keys.
    if k == '\x1b':
        k = self.char_reader()
        if k != '[':
            return
        k = self.char_reader()
        if k == 'A':
            self.__arrow_down()
        if k == 'B':
            self.__arrow_up()

    # And check for enter key.
    if k == '\r':
        self.menu[self.option].handler()


def __update_stations(self,):
    [...]

def run(self):
    self.display()
    while True:
        rfds, _, _ = select.select([pipe, sys.stdin], [], [])

        if pipe in rfds:
                self.__update_stations()

        if sys.stdin in rfds:
            self.__read_order_from_user()

我在互联网上找到了如何从标准输入中一个一个地读取字符:Python read a single character from the user 它确实有效,但与 select.select.

一起使用时无效

我在此处粘贴 VPfB 评论中的解决方案:

"The raw tty mode is turned on to only to read one character and then turned off. When the select is active, it is turned off, because the routine to get the one character is called after the select. You should turn on raw tty input before the select loop and restore the tty setting after exiting the loop."