Multiple key listeners in Python?

92 views Asked by At

I'm trying to implement multile key listeners such that one combination of keys executes one function, while another executes a different function. In this simple example, the two functions print "Do something" and "Do", respectively.

This is the code I've come up with so far (apologies as I'm new to Python). It works for the first function, but doesn't seem to work for the second...ie nothing happens, though it doesn't throw an error

from pynput import keyboard
 
# The key combination to check
COMBINATIONS = [
    {keyboard.KeyCode(char='j')},
]

COMBINATIONS2 = [
    {keyboard.KeyCode(char='k')},
]
 
# The currently active modifiers
current = set()
current2 = set()
 
def execute():
    print ("Do Something")
    
def on_press(key):
    if any([key in COMBO for COMBO in COMBINATIONS]):
        current.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
            execute()
 
def on_release(key):
    if any([key in COMBO for COMBO in COMBINATIONS]):
        current.remove(key)
 
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()


 
def execute2():
    print ("Do")
    
def on_press(key):
    if any([key in COMBO for COMBO in COMBINATIONS2]):
        current2.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS2):
            execute2()
 
def on_release(key):
    if any([key in COMBO for COMBO in COMBINATIONS2]):
        current2.remove(key)
 
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()
1

There are 1 answers

2
airblast On

The issue is you arent using threading with it.

with keyboard.Listener(on_press=on_press, on_release=on_release) as 
listener:
    listener.join()

This causes the main thread to block so no other code is executed. The pynput library offers an alternative way to use it which makes use of threading.

listener = keyboard.Listener(
    on_press=on_press,
    on_release=on_release)
listener.start()

Using this allows the full flow to be executed. But since all of it is in a separate thread the main thread gets killed since there isnt anything else to do. To avoid this you can use a solution like in the example below.

from pynput import keyboard

s_combo = {keyboard.KeyCode(char='k')}
u_combo = {keyboard.KeyCode(char='j')}


class SuperCombo():

    def on_press(key):
        if key in s_combo:
            print("k pressed")

    def on_release(key):
        if key in s_combo:
            print("k released")

class UltraCombo():

    def on_press(key):
        if key in u_combo:
            print("j pressed")

    def on_release(key):
        if key in u_combo:
            print("j released")


Combos = [SuperCombo, UltraCombo]
for combo in Combos:
    listener = keyboard.Listener(on_press=combo.on_press,
                                 on_release=combo.on_release)
    listener.start()
while True:
    print("Type exit to end the program.")
    x = input()
    if x == "exit":
        break

I also recommend using classes to organize combos and their functions. It isnt ideal for when you want to use them later in the code since they would be changed to the one that was defined last.