【问题标题】:How to break out of a loop when a keyboard key is pressed? [duplicate]按下键盘键时如何跳出循环? [复制]
【发布时间】:2022-01-11 08:59:44
【问题描述】:

我有一个无休止的 while 或 for 循环,并希望在按下键盘键时break

while True:
    time.sleep(5)
    if any key is pressed:
        break

我该怎么做?


问答灵感来自:

Breaking out of an infinite FOR loop in python without interupting the loop

【问题讨论】:

  • “任意键”的用例究竟是什么? SIGINT 存在于当您想要中断正在执行的任何进程时的这种情况,在这种情况下,这将被解释为中断此循环的信号。您所要做的就是抓住KeyboardInterrupt 并跳出循环。这不仅降低了您在无意中点击错误和中断循环的可能性,而且也是每个人都显而易见的标准方式。
  • @Sahsahae 大量用例,从不正确的信号处理开始,信号未被正确线程捕获的多线程,为不精通技术的用户提供文本程序,捕获所有键以进行监控或刷新程式。我发现了多个措辞不同的问题,最终目标是做这样的事情。
  • “我发现了多个措辞不同的问题,最终目标是做这样的事情。”那他们为什么不解决你的问题呢?
  • @Bharel 你的回答很好,看起来你花了一些时间。您应该将其发布在此问题的许多现有副本之一中,而不是要求一个新的(并可能删除这个)
  • @Sahsahae 如果控制或 UI 线程不是主线程,这几乎不是必须的,Python 默认在主线程中抛出异常。这是一个比使用任何类型的侧通道重定向信号更容易的解决方案,例如设置线程全局变量、状态或信号。我提供的答案还允许捕获特定的密钥。

标签: python


【解决方案1】:

这是一个跨平台的解决方案:

import contextlib as _contextlib

try:
    import msvcrt as _msvcrt

    # Length 0 sequences, length 1 sequences...
    _ESCAPE_SEQUENCES = [frozenset(("\x00", "\xe0"))]

    _next_input = _msvcrt.getwch

    _set_terminal_raw = _contextlib.nullcontext

    _input_ready = _msvcrt.kbhit

except ImportError:  # Unix
    import sys as _sys, tty as _tty, termios as _termios, \
        select as _select, functools as _functools

    # Length 0 sequences, length 1 sequences...
    _ESCAPE_SEQUENCES = [
        frozenset(("\x1b",)),
        frozenset(("\x1b\x5b", "\x1b\x4f"))]

    @_contextlib.contextmanager
    def _set_terminal_raw():
        fd = _sys.stdin.fileno()
        old_settings = _termios.tcgetattr(fd)
        try:
            _tty.setraw(_sys.stdin.fileno())
            yield
        finally:
            _termios.tcsetattr(fd, _termios.TCSADRAIN, old_settings)

    _next_input = _functools.partial(_sys.stdin.read, 1)

    def _input_ready():
        return _select.select([_sys.stdin], [], [], 0) == ([_sys.stdin], [], [])

_MAX_ESCAPE_SEQUENCE_LENGTH = len(_ESCAPE_SEQUENCES)

def _get_keystroke():
    key = _next_input()
    while (len(key) <= _MAX_ESCAPE_SEQUENCE_LENGTH and
           key in _ESCAPE_SEQUENCES[len(key)-1]):
        key += _next_input()
    return key

def _flush():
    while _input_ready():
        _next_input()

def key_pressed(key: str = None, *, flush: bool = True) -> bool:
    """Return True if the specified key has been pressed

    Args:
        key: The key to check for. If None, any key will do.
        flush: If True (default), flush the input buffer after the key was found.
    
    Return:
        boolean stating whether a key was pressed.
    """
    with _set_terminal_raw():
        if key is None:
            if not _input_ready():
                return False
            if flush:
                _flush()
            return True

        while _input_ready():
            keystroke = _get_keystroke()
            if keystroke == key:
                if flush:
                    _flush()
                return True
        return False

def print_key() -> None:
    """Print the key that was pressed
    
    Useful for debugging and figuring out keys.
    """
    with _set_terminal_raw():
        _flush()
        print("\\x" + "\\x".join(map("{:02x}".format, map(ord, _get_keystroke()))))

def wait_key(key=None, *, pre_flush=False, post_flush=True) -> str:
    """Wait for a specific key to be pressed.

    Args:
        key: The key to check for. If None, any key will do.
        pre_flush: If True, flush the input buffer before waiting for input.
        Useful in case you wish to ignore previously pressed keys.
        post_flush: If True (default), flush the input buffer after the key was
        found. Useful for ignoring multiple key-presses.
    
    Returns:
        The key that was pressed.
    """
    with _set_terminal_raw():
        if pre_flush:
            _flush()

        if key is None:
            key = _get_keystroke()
            if post_flush:
                _flush()
            return key

        while _get_keystroke() != key:
            pass
        
        if post_flush:
            _flush()

        return key

在你的while循环中使用key_pressed()

while True:
    time.sleep(5)
    if key_pressed():
        break

您还可以检查特定键:

while True:
    time.sleep(5)
    if key_pressed("\x00\x48"):  # Up arrow key on Windows.
        break

并使用print_key()找出特殊键:

>>> print_key()
# Press up key
\x00\x48

【讨论】:

    猜你喜欢
    • 2021-03-31
    • 2017-05-23
    • 2015-01-28
    • 2013-04-29
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多