pynput icon indicating copy to clipboard operation
pynput copied to clipboard

Is it possible to create 2 separate Threads for on_press and on_release events alongside the Main thread?

Open fabriciopirini opened this issue 4 years ago • 3 comments

Hi! I'm trying to translate keyboard keys to joystick movements on an emulator screen (BlueStacks) on my Mac Catalina.

What I'm trying to achieve is to keep the movement until the key is released so I decided to create a loop to repeat the movement until the key is released. However, the loop is blocking the Thread so I can't accomplish that easily. I tried then to create 2 Threads, 1 for on_press events and another for on_release events but that don't work either since I always get AttributeErrors from the objc for any key I press.

Part of my code:

CURRENT_STATE = 'released'
DELAY = 0.25


def on_press(key):
    try:
        global CURRENT_STATE
        CURRENT_STATE = 'pressing'

        X, Y = INITIAL['X'], INITIAL['Y']

        if key == Key.shift:
            print('UP')
            X, Y = MOVES['UP']
        elif key == Key.ctrl:
            print('LEFT')
            X, Y = MOVES['LEFT']
        elif key == Key.alt:
            print('DOWN')
            X, Y = MOVES['DOWN']
        elif key == Key.cmd:
            print('RIGHT')
            X, Y = MOVES['RIGHT']

        if key in VALID_KEYS:

            while CURRENT_STATE == 'pressing':
                device.input_swipe(INITIAL['X'], INITIAL['Y'], X, Y, DELAY * 1000)
                time.sleep(DELAY)

    except Exception as err:
        print(err)


def on_release(key):
    if key in VALID_KEYS:
        global CURRENT_STATE
        CURRENT_STATE = 'released'
        print('released')
    elif key == Key.cmd_r:
        # Stop listener
        return False


def main():
    press_listener = Listener(on_press=on_press)
    press_listener.start()
    release_listener = Listener(on_release=on_release)
    release_listener.start()

    while True:
        continue


main()

Thanks for any help and directions =)

Disclaimer: I tried to use pyinput for mouse events but I couldn't make it work on my Mac, even allowing my terminal and IDE on Accessibility (couldn't auth Python) and running with sudo so I'm using ADB.

fabriciopirini avatar Dec 12 '20 11:12 fabriciopirini

Have you considered creating a thread responsible for sending device events (device.input_swipe) that reads a global state, like:

class State(enum.Enum):
    IDLE = 0
    MOVE_DOWN = 1
   # ...
    QUIT = N

and then just update the global state from the callback? The thread body would be a simple while STATE != State.Quit-loop.

And your problems with mouse events seem strange, since keyboard events require even more privileges. Do you have a stack trace or other information? Or do you simply not receive any events?

moses-palmer avatar Dec 21 '20 16:12 moses-palmer

Thanks for the reply! I will soon try again to use pyinput and I will try out your approach and post the feedback here.

I don't have any stack trace, no events were coming indeed so I believe Mac was swallowing them.

fabriciopirini avatar Dec 23 '20 10:12 fabriciopirini

To investigate the missing events, you might want to add some debug logging here.

moses-palmer avatar Dec 23 '20 10:12 moses-palmer