detect key press in python, where each iteration can take more than a couple of seconds?
Asked Answered
L

4

8

Edit: The below answer to use keyboard.on_press(callback, suppress=False) works fine in ubuntu without any issues. But in Redhat/Amazon linux, it fails to work.

I have used the code snippet from this thread

import keyboard  # using module keyboard
while True:  # making a loop
    try:  # used try so that if user pressed other than the given key error will not be shown
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop
    except:
        break  # if user pressed a key other than the given key the loop will break

But the above code requires the each iteration to be executed in nano-seconds. It fails in the below case:

import keyboard  # using module keyboard
import time
while True:  # making a loop
    try:  # used try so that if user pressed other than the given key error will not be shown
        print("sleeping")
        time.sleep(5)
        print("slept")
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop
    except:
        print("#######")
        break  # if user pressed a key other than the given key the loop will break
Litigant answered 2/3, 2020 at 13:47 Comment(4)
Your program will detect nothing during the sleep call. What are you trying to do?Sauterne
@Sauterne The above program is just a illustration. Problem is, key press is not detected if each iteration in while loop is taking more than a couple of seconds.Litigant
Check this examples https://mcmap.net/q/49357/-what-39-s-the-simplest-way-of-detecting-keyboard-input-in-a-script-from-the-terminalVanya
Did you try with another library? like evemu and python-evdev, keyboard had been inconsistent (for me at least)Snailfish
M
7

You can make use of event handlers in keyboard module to achieve the desired result.

One such handler is keyboard.on_press(callback, suppress=False): Which invokes a callback for every key_down event. You can refer more at keyboard docs

Here is the code you can try:

import keyboard  # using module keyboard
import time

stop = False
def onkeypress(event):
    global stop
    if event.name == 'q':
        stop = True

# ---------> hook event handler
keyboard.on_press(onkeypress)
# --------->

while True:  # making a loop
    try:  # used try so that if user pressed other than the given key error will not be shown
        print("sleeping")
        time.sleep(5)
        print("slept")
        if stop:  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop
    except:
        print("#######")
        break  # if user pressed a key other than the given key the loop will break
Masonmasonic answered 2/3, 2020 at 13:58 Comment(3)
@NarenBabuR You have to run this program as a root user, as mentioned in the docs of keyboard.Masonmasonic
before running the program, executing sudo su solves the problemLitigant
@NarenBabuR Yep, that will do.Masonmasonic
C
2

for people that might need this in the future, you can use keyboard.wait() which will basically wait untill the key gets pressed

keyboard.wait("o")
print("you pressed the letter o")

Do keep in mind that it blocks code execution after it. if you want to run code if the key is not being pressed i'd suggest doing

if keyboard.is_pressed("0"): 
    #do stuff
else: 
    #do other stuff
Caledonian answered 20/5, 2022 at 13:37 Comment(2)
Is there a way to use keyboard.wait() to wait for ANY key event, either a key up or key down?Caravan
@Caravan There is!, With trigger_on_release= if true, the callback is invoked on key release instead of key press. In the case below it triggers when the key is released keyboard.wait("o", trigger_on_release=True) print("you released the letter o")Caledonian
A
-1

Edit: never mind, the other answer uses pretty much the same approach

This is what i could come up with, using the same "keyboard" module, see in-code comments below

import keyboard, time
from queue import Queue 

# keyboard keypress callback
def on_keypress(e): 
    keys_queue.put(e.name)

# tell keyboard module to tell us about keypresses via callback
# this callback happens on a separate thread
keys_queue = Queue() 
keyboard.on_press(on_keypress)

try:
    # run the main loop until some key is in the queue
    while keys_queue.empty():  
        print("sleeping")
        time.sleep(5)
        print("slept")
    # check if its the right key
    if keys_queue.get()!='q':
        raise Exception("terminated by bad key")
    # still here? good, this means we've been stoped by the right key
    print("terminated by correct key")
except:
    # well, you can 
    print("#######")
finally:
    # stop receiving the callback at this point
    keyboard.unhook_all()
Ardy answered 14/3, 2020 at 4:43 Comment(0)
V
-3

You could use a thread

import threading

class KeyboardEvent(threading.Thread):
    def run(self):
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop

keyread = KeyboardEvent()
keyread.start()

This would run in parallel to anything in the main thread and be dedicated to listening for that key press essentially.

Vizier answered 2/3, 2020 at 13:55 Comment(1)
If I'm not mistaken, though, it would just check for the keypress once the thread was started, and then the thread would exit. Did you mean while not keyboard.is_pressed instead?Sulphurbottom

© 2022 - 2024 — McMap. All rights reserved.