检测一个键是否被按住 - python
Detecting if a key is HELD down - python
我的用例
我需要知道何时按下并按住(特定)键。检测后的用例相当简单。释放按键时,发送一个信号以停止回调(我已经知道了)。
期望的行为
这是算法的粗略方案:
def the_callback():
if key_held == the_hotkey:
someObj.start() # this class Obj works totally well so no issues here on
elif key_released == the_hotkey:
someObj.stop()
else:
# we don't care. continue looking for Keyboard events
# here any kinda listener or just a loop which passes events to the callback
我应该提一下,任何阻塞执行的监听器都是可以的,因为它会 运行 在它自己的线程中(已经 运行ning pynput.keyboard.Listener
在一个线程中所以不是问题)
我试过的
我使用 pynput
及其 pynput.keyboard.Listener
来检测按键并相应地调用回调,但我无法检测按键何时被按下。
当前的解决方案大致如下:
# not real code. just rough scheme
def on_pressed(key):
if key == my_hotkey:
if running_already: # this part works well already
obj.stop()
else:
obj.start()
else:
# we don't care
with pynput.keyboard.Listener(on_press=on_pressed) as listener:
listener.join() # blocking call until SystemExit, `return False` from callback or `listener.stop()`
我有一种非常强烈的感觉,我可以通过添加 on_release=another_callback_that_handles_releases
(在 pynput.keyboard.listener
内可用)来完成这项工作。
也许可以通过存储最后一次按下的已知键击,并检查释放的键是否与之前按下的热键相同,但我不确定我将如何处理它,甚至可以工作吗?
然后我决定试试 keyboard
(不同的库)。
我写了下面的代码,它可以检测按下的键。下面的代码几乎达到了我想要的效果:
import keyboard as kb, time
while 1:
while kb.is_pressed('q'):
print('Key is held')
time.sleep(0.5) # sleep added just to stop it from spamming the stdout
else:
print('No it\'s Not')
time.sleep(0.5)
此解决方案的问题是,它不太适合 OSX 和 Ubuntu。它在使用特殊键时存在一些问题。此外,我将热键存储为 pynput.keyboard.Key.f7
(例如)或 pynput.keyboard.KeyCode(char='s') # for character keys
,这些枚举的值与 keyboard
用于扫描密钥 ID(使用 keyboard.hook()
)的值不同。
最后一题
我应该如何检测被按住的键。我更喜欢使用 pynput
来实现这一点,因为代码库的其余部分使用它,但 'keyboard
也很好。
我再次感觉到使用 on_press=a_callback
和 on_release=another_callback
可能会实现,但我对此并不完全确定。最后,解决方案最好是跨平台的(我可以根据 platform.system()
的值使用三个不同的函数)。
您将如何实现它?
编辑-1
HERE 是我在 Isak 的建议下作为尝试(和 MCVE)写的。这几乎可以完美地解决 just 1 缺陷。那就是它不会在程序启动时立即监听按键。
由于某些未知原因,它需要一些时间才能开始实际检测到任何按键。好的是,一旦它第一次检测到按键,它就可以完美地工作。
我错过了什么?
尝试检查特定键上的 the key_pressed
事件,直到事件变为 key_released
。因此,当您检测到单击该键时,您将执行您的代码,当它检测到该键的释放时,代码停止
我弄明白了为什么 My Approach 在启动 Listener
之前花费大量时间进行初始化。这是因为 while 循环没有任何 time.sleep()
调用,它可能会干扰系统(尽管我不希望它在自己的线程中运行时发生这种情况,但可能是 while
循环不会释放 GIL
因为它只是在循环中没有任何延迟地执行任何操作)。
我刚刚在 while 循环(外部循环)中添加了 time.sleep(0.2)
。任何延迟都将释放 GIL
一段时间,并且 Listener
线程将被处理并激活。
编辑:接受 Isak 的回答,因为这是正确的方法。
我的用例
我需要知道何时按下并按住(特定)键。检测后的用例相当简单。释放按键时,发送一个信号以停止回调(我已经知道了)。
期望的行为
这是算法的粗略方案:
def the_callback():
if key_held == the_hotkey:
someObj.start() # this class Obj works totally well so no issues here on
elif key_released == the_hotkey:
someObj.stop()
else:
# we don't care. continue looking for Keyboard events
# here any kinda listener or just a loop which passes events to the callback
我应该提一下,任何阻塞执行的监听器都是可以的,因为它会 运行 在它自己的线程中(已经 运行ning pynput.keyboard.Listener
在一个线程中所以不是问题)
我试过的
我使用 pynput
及其 pynput.keyboard.Listener
来检测按键并相应地调用回调,但我无法检测按键何时被按下。
当前的解决方案大致如下:
# not real code. just rough scheme
def on_pressed(key):
if key == my_hotkey:
if running_already: # this part works well already
obj.stop()
else:
obj.start()
else:
# we don't care
with pynput.keyboard.Listener(on_press=on_pressed) as listener:
listener.join() # blocking call until SystemExit, `return False` from callback or `listener.stop()`
我有一种非常强烈的感觉,我可以通过添加 on_release=another_callback_that_handles_releases
(在 pynput.keyboard.listener
内可用)来完成这项工作。
也许可以通过存储最后一次按下的已知键击,并检查释放的键是否与之前按下的热键相同,但我不确定我将如何处理它,甚至可以工作吗?
然后我决定试试 keyboard
(不同的库)。
我写了下面的代码,它可以检测按下的键。下面的代码几乎达到了我想要的效果:
import keyboard as kb, time
while 1:
while kb.is_pressed('q'):
print('Key is held')
time.sleep(0.5) # sleep added just to stop it from spamming the stdout
else:
print('No it\'s Not')
time.sleep(0.5)
此解决方案的问题是,它不太适合 OSX 和 Ubuntu。它在使用特殊键时存在一些问题。此外,我将热键存储为 pynput.keyboard.Key.f7
(例如)或 pynput.keyboard.KeyCode(char='s') # for character keys
,这些枚举的值与 keyboard
用于扫描密钥 ID(使用 keyboard.hook()
)的值不同。
最后一题
我应该如何检测被按住的键。我更喜欢使用 pynput
来实现这一点,因为代码库的其余部分使用它,但 'keyboard
也很好。
我再次感觉到使用 on_press=a_callback
和 on_release=another_callback
可能会实现,但我对此并不完全确定。最后,解决方案最好是跨平台的(我可以根据 platform.system()
的值使用三个不同的函数)。
您将如何实现它?
编辑-1
HERE 是我在 Isak 的建议下作为尝试(和 MCVE)写的。这几乎可以完美地解决 just 1 缺陷。那就是它不会在程序启动时立即监听按键。
由于某些未知原因,它需要一些时间才能开始实际检测到任何按键。好的是,一旦它第一次检测到按键,它就可以完美地工作。
我错过了什么?
尝试检查特定键上的 the key_pressed
事件,直到事件变为 key_released
。因此,当您检测到单击该键时,您将执行您的代码,当它检测到该键的释放时,代码停止
我弄明白了为什么 My Approach 在启动 Listener
之前花费大量时间进行初始化。这是因为 while 循环没有任何 time.sleep()
调用,它可能会干扰系统(尽管我不希望它在自己的线程中运行时发生这种情况,但可能是 while
循环不会释放 GIL
因为它只是在循环中没有任何延迟地执行任何操作)。
我刚刚在 while 循环(外部循环)中添加了 time.sleep(0.2)
。任何延迟都将释放 GIL
一段时间,并且 Listener
线程将被处理并激活。
编辑:接受 Isak 的回答,因为这是正确的方法。