我需要大致执行以下操作:
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
这是一个潜在的解决方案。它的工作原理是检查感兴趣的事件被触发的时间。请参阅下面的文档字符串和评论:
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()
的调用就会被拒绝。