【问题标题】:Detecting if a key is HELD down - python检测一个键是否被按下 - python
【发布时间】:2021-07-14 16:21:45
【问题描述】:

我的用例

我需要知道何时按下并按住(特定)键。检测后的用例相当简单。当按键被释放时,发送一个信号来停止回调(我已经知道了)。

期望的行为

以下是算法外观的粗略方案:

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

我应该提一下,任何阻止执行的侦听器都可以,因为它会在自己的线程中运行(已经在线程中运行 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_callbackon_release=another_callback 这可能会实现,但我并不完全确定。最后,该解决方案最好是跨平台的(我可以根据platform.system() 的值使用三个不同的函数)。

你将如何实现它?

EDIT-1

HERE 是我在 Isak 建议后写的尝试(和 MCVE)。这与 just 1 缺陷几乎完美配合。那就是它不会从程序开始就听按键。

由于某种未知原因,它需要一些时间才能真正开始检测到任何按键。好消息是,一旦它第一次检测到按键,它就可以完美运行。

我错过了什么?

【问题讨论】:

    标签: python callback keyboard keyboard-events pynput


    【解决方案1】:

    尝试检查特定键上的the key_pressed 事件,直到事件变为key_released。因此,当您检测到您执行代码的键时,当检测到该键的释放时,代码停止

    【讨论】:

    • HERE 是我作为尝试(和 MCVE)写的。这几乎完美地适用于 just 1 缺陷。那就是它不会从程序开始就听按键。由于某种未知原因,它需要一些时间才能开始实际检测到任何按键。好消息是,一旦它第一次检测到按键,它就可以完美运行。我在那里错过了什么?
    • @PSSolanki 延迟可能是因为导入键盘模块需要时间。
    • 感谢您的回复,希德!但实际上我并没有在脚本中import keyboard。关于pynput.keyboard.Listener 实例,我有一个更大的脚本,它可以导入更多的东西,包括这个mcve 中的东西,并且可以立即运行。 @Sid
    【解决方案2】:

    我知道为什么My Approach 在启动Listener 之前要花很多时间进行初始化。这是因为没有任何time.sleep() 调用的while 循环,它可能与系统混淆(虽然我不希望发生这种情况,因为它在自己的线程中运行,但可能while 循环没有'不要释放GIL,因为它只是在循环中,几乎什么都不做,没有任何延迟)。

    我刚刚在 while 循环(外部循环)内添加了 time.sleep(0.2)。任何延迟都会导致GIL 释放一段时间,Listener 线程将被处理并激活。

    编辑:接受 Isak 的回答,因为这是正确的方法。

    【讨论】:

      猜你喜欢
      • 2021-01-27
      • 2018-06-26
      • 2016-10-31
      • 2015-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-04
      • 1970-01-01
      相关资源
      最近更新 更多