Home > Enterprise >  Reading the keyboard in python without getting into a blocking call?
Reading the keyboard in python without getting into a blocking call?

Time:01-15

I am writing a python code that tracks the mouse and the keyboard. I want the tracking of both to be in a single while loop like the following:

while True:
    mouse_x, mouse_y = get_mouse_pos()
    key_pressed = get_key_pressed()
    print(key_pressed   " is down")
    print(f"The mouse position is: {mouse_x}, {mouse_y}")

Is there any way to do so without opening a thread for the keyboard reading?

I couldn't find a method that reads the keyboard without waiting for an input. I tried kbhit() in msvcrt module, but it only returns 0 no matter what I press, and the keyboard module can read only a specific key non blockingly as far as I know.

CodePudding user response:

As far as I know, you will need to use two threads to monitor both the keyboard and the mouse at the same time, without blocking. You can create event listeners to monitor for both.

Note that I have incorporated an exit key x which will exit the program when pressed.

Here is an example of how that could be achieved:

Code:

from pynput import mouse, keyboard
import sys
import threading

exit_program = False

def on_press(key):
    global exit_program
    try:
        print(f'Key {key.char} was pressed.')
        if key.char == "x":
            exit_program = True
            sys.exit()
    except AttributeError:
        print(f'Special key {key} was pressed.')

def on_move(x, y):
    global exit_program
    if exit_program:
        sys.exit()
    else:
        print(f'Mouse moved to (x:{x} , y:{y})')


# Collect events from both keyboard and mouse
def start_listener_keyboard():
    with keyboard.Listener(on_press=on_press) as listener:
        listener.join()

def start_listener_mouse():
    with mouse.Listener(on_move=on_move) as listener:
        listener.join()

threading.Thread(target=start_listener_keyboard).start()
threading.Thread(target=start_listener_mouse).start()

Output:

Mouse moved to (x:1543 , y:210)
Mouse moved to (x:1543 , y:208)
Mouse moved to (x:1544 , y:206)
Mouse moved to (x:1544 , y:205)
Mouse moved to (x:1544 , y:201)
Mouse moved to (x:1544 , y:197)
Mouse moved to (x:1544 , y:195)
Mouse moved to (x:1544 , y:193)
Key d was pressed.
Mouse moved to (x:1544 , y:192)
Mouse moved to (x:1544 , y:188)
Mouse moved to (x:1543 , y:187)
Special key Key.backspace was pressed.
Key x was pressed.

CodePudding user response:

I found I can use pygame.event.get() to iterate through the events, catch a key down or a key up event, and get the unicode of the key that was down/up.

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            break

        elif event.type == pygame.KEYDOWN:
            print(str(event.unicode)   " is down")

        elif event.type == pygame.KEYUP:
            print(str(event.unicode)   " is up")
  • Related