My use case
I need to know when a (specific) key is pressed and held down. The use case after detection is fairly easy. When the key is released, send a signal to stop the callback (which I know already).
Desired behavior
Here is a rough scheme of how the algo looks like:
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
I should mention that any kinda listener which blocks the execution is okay as it will run in its own thread (already running pynput.keyboard.Listener
in a thread so not a problem)
What I've tried
I used pynput
and its pynput.keyboard.Listener
to detect key-presses and invoke callbacks accordingly but I couldn't make that work to detect when a key is HELD down.
the current solution looks roughly like:
# 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()`
I have a very strong feeling that I can make this work by adding on_release=another_callback_that_handles_releases
(available within pynput.keyboard.listener
).
Perhaps by storing the last known pressed keystroke, and checking if the key released was the same as the hotkey which was pressed earlier but I'm not sure how would I go about it and can that even work?
Then I decided to give keyboard
(different lib) a go.
I wrote the below code for the same which can detect keys being held down. This below code achieves almost nearly what I want:
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)
The issue with this solution is, it's not very well suited for OSX and Ubuntu. And it has some issues working with special keys. Moreover, I have the hotkey stored as pynput.keyboard.Key.f7
(for eg) or pynput.keyboard.KeyCode(char='s') # for character keys
and these enums have different values than what keyboard
uses to scan key IDs (using keyboard.hook()
).
The final question
How should I go about detecting a key being HELD down. I'd prefer to achieve this using pynput
as the rest of the code base uses it but 'keyboard
is fine too.
Again I have a feeling that using on_press=a_callback
and on_release=another_callback
this might be achieved but I'm not entirely sure about it. Lastly, the solution is preferred to be cross platform (I'm fine with using three different functions depending on value of platform.system()
).
How would you go about achieving it?
EDIT-1
HERE is what I wrote as an attempt (and MCVE) after suggestion by Isak. This works almost perfectly with just 1 flaw. And that is that it doesn't listen to keypresses right from the program start.
It takes some time for some unknown reason before it starts to actually detect any keypress. Good thing is that once it detects the keypress for the first time, it works flawlessly.
What am I missing there?