【问题标题】:keyboard input with timeout and without press enter键盘输入超时且不按回车
【发布时间】:2015-04-01 20:50:12
【问题描述】:

我正在用 Python 编写一个在我的 Raspberry Pi 上运行的程序。众所周知,Raspberry 可以接收多种输入方式。我正在使用键盘和另一个外部输入源。这只是为了上下文化,对问题本身并不重要。

在我的程序中,我等待键盘输入,如果在短时间内没有输入,我会跳过并寻找其他来源的输入。为此,我使用以下代码:

import sys
import time
from select import select

timeout = 4  
prompt = "Type any number from 0 up to 9"
default = 99 

def input_with(prompt, timeout, default):
    """Read an input from the user or timeout"""
    print prompt,
    sys.stdout.flush()
    rlist, _, _ = select([sys.stdin], [], [], timeout)
    if rlist:
        s = int(sys.stdin.read().replace('\n',''))
    else:
        s = default
        print s
    return s

我将在没有全键盘的情况下运行 Raspberry Pi,这意味着我将没有返回键。以这种方式将无法验证键盘输入。

我的疑问是是否可以在不按 enter 并保持输入超时的情况下获取用户输入。

我看到很多话题都在谈论这两个问题(超时和输入而不按返回),但两者都没有。

提前感谢您的帮助!

【问题讨论】:

标签: python-2.7 input timeout


【解决方案1】:

我认为按照你想要的方式来做这件事并不简单,即读取在线等待的内容,即使没有按下 Enter(对吗?)。

我能提供的最佳建议是,您在按下每个字符时捕获它,并在时间过去后调用。您可以通过设置 cbreak 模式来捕获每个字符的输入:tty.setcbreak()

import sys
from select import select
import tty
import termios

try:
    # more correct to use monotonic time where available ...
    from time33 import clock_gettime
    def time(): return clock_gettime(0)
except ImportError:
    # ... but plain old 'time' may be good enough if not.
    from time import time

timeout = 4  
prompt = "Type any number from 0 up to 9"
default = 99 

def input_with(prompt, timeout, default):
    """Read an input from the user or timeout"""
    print prompt,
    sys.stdout.flush()

    # store terminal settings
    old_settings = termios.tcgetattr(sys.stdin)

    buff = ''
    try:    
        tty.setcbreak(sys.stdin) # flush per-character

        break_time = time() + timeout

        while True:

            rlist, _, _ = select([sys.stdin], [], [], break_time - time())
            if rlist:
                c = sys.stdin.read(1)

                # swallow CR (in case running on Windows)
                if c == '\r':
                    continue
                # newline EOL or EOF are also end of input
                if c in ('\n', None, '\x04'):
                    break # newline is also end of input
                buff += c

                sys.stdout.write(c) # echo back
                sys.stdout.flush()

            else: # must have timed out
                break

    finally:
        # put terminal back the way it was
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)

    if buff:
        return int(buff.replace('\n','').strip())
    else:
        sys.stdout.write('%d' % default)
        return default

【讨论】:

  • time.time() 可以重新设置。这是time.monotonic() implementation for Python 2.7 on Ubuntu
  • 您可能还应该允许eofeol 字符来终止输入(除了b'\n')——参见stty -a
  • 谢谢,不过我不确定你对time.time 的意思。是否暗示由于这个原因它不可靠?我不认为 EOL 是树莓派的一个问题。在非 *nix 平台上,您可能会支持它,但可能应该完全忽略它。
  • Use a monotonic clock to compute timeouts。使用Ctrl+D (eof) 尝试您的代码。
  • 我在评论中提到的 eol 与 Windows 没有任何关系。见Special Characters
猜你喜欢
  • 2012-12-23
  • 2022-01-12
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多