使用msvcrt的python按键输入逻辑

问题描述 投票:0回答:1

我需要大致执行以下操作:

while True:
    if *a key is pressed within 5 seconds of some prior event*:
        print(*the specific key that was pressed)
    elif *5 seconds pass with no key press*
        print("No key pressed")

我在另一个问题中发布了我的具体需求(使用 msvcrt.getch() 读取特定密钥或在设定时间后继续,无需输入),但我认为这种格式更容易理解。这里的关键部分是我必须知道按下了什么键。我一直在尝试使用

msvcrt.getch() amd msvcrt.kbhit()
,但似乎我需要某种混合动力。

有人能解决这个问题吗?

Windows 11、Python 3.11.0

python msvcrt
1个回答
0
投票

这是一个潜在的解决方案。它的工作原理是检查感兴趣的事件被触发的时间。请参阅下面的文档字符串和评论:

import msvcrt
import time


class KeyboardChecker:
    """Checks for input."""
    
    def __init__(self):
        self.last_event_trigger_time = None

    def event_triggered(self):
        """Call this when your event is triggered."""
        self.last_event_trigger_time = time.perf_counter()
        print(
            round(self.last_event_trigger_time, 3),
            '[KeyboardChecker]: Event triggered.',
        )

    def _read_all_input(self):
        """Read all available input."""
        input_data = b''
        while msvcrt.kbhit():
            # Read and store input until no more is available.
            input_data += msvcrt.getch()

        return input_data

    def check_input(self):
        """Check if we have received input within 5 seconds of the last event."""
        if self.last_event_trigger_time is None:
            # If the trigger time is still `None`, the
            # event has not been triggered yet.

            # Don't run the next part of the code.
            return None  # This is the same as `return`.

        current_time = time.perf_counter()
        if current_time - self.last_event_trigger_time > 5:
            # If the event was last triggered more than 5
            # seconds ago, don't do anything with the input.

            # OPTIONAL: Read input but don't use it. This
            # means you won't have anything waiting to be
            # read the next time you want to read any
            # input, which may be useful.
            _not_used = self._read_all_input()

            # Don't run the next part of the code.
            return None

        # By the time we reach this point (if at all), we
        # know that the event was triggered and that it was
        # 5 seconds ago or less. We can now read our input,
        # if we have any.
        if msvcrt.kbhit():
            # If we have received input, read it all.
            return self._read_all_input()

        # If we do not have any input, return an empty
        # bytestring to distinguish from the rejection
        # cases above.
        return b''

每当您触发事件时,您都可以调用

.event_triggered()
,并调用
.check_input()
来检查我们是否有输入,并且现在获取它还不算太晚(基于事件上次触发的时间)。

这是一个使用示例...

# Create a `KeyboardChecker` instance so we can do all of
# our checking.
keyboard_checker = KeyboardChecker()

# This gets called when the event is triggered. We will
# call it here for demonstration.
keyboard_checker.event_triggered()

# Now, we run a while loop that loops every half-second
# until calls to `keyboard_checker.check_input()` are
# rejected (when it starts reurning None).
while True:
    # Record the time.
    timestamp = round(time.perf_counter(), 3)

    # Check for input.
    received_input = keyboard_checker.check_input()

    # Handle all cases.
    if received_input is None:
        # Event was triggered more than 5 seconds ago.
        print(timestamp, 'The call to `.check_input()` was rejected! Stopping loop...')
        break  # Stop the loop.

    elif received_input == b'':
        # Input was checked, but none was received.
        print(timestamp, 'No characters received.')

    else:
        # Input was checked and data was received.
        print(timestamp, f'Received the following data: {received_input}.')

    # Wait for half a second.
    time.sleep(0.5)

...以及我运行它时生成的输出。

1491860.076 [KeyboardChecker]: Event triggered.
1491860.076 Received the following data: b'f'.
1491860.578 Received the following data: b'o'.
1491861.081 Received the following data: b'o'.
1491861.584 No characters received.
1491862.085 Received the following data: b'b'.
1491862.588 Received the following data: b'a'.
1491863.091 Received the following data: b'r'.
1491863.593 No characters received.
1491864.095 No characters received.
1491864.597 No characters received.
1491865.098 The call to `.check_input()` was rejected! Stopping loop...

请注意,一旦超过 5 秒标记,对

.check_input()
的调用就会被拒绝。

© www.soinside.com 2019 - 2024. All rights reserved.