2

I'd like my code to listen for user input, and do something if key c is pressed, and something else if key v is pressed.

I've managed to do it using global, but it feels like an ugly hack :

from pynput import keyboard

def on_press(key):
    try:
        global user_input 
        if key.char == "c":
            user_input = "c"
        elif key.char == "v":
            user_input == "v"
    except AttributeError:
        pass

def on_release(key):
    if key == keyboard.Key.esc:
        # Stop listener
        return False

def wait_for_user_input():
    global user_input
    listener = keyboard.Listener(on_press=on_press, on_release=on_release)
    listener.start()
    user_input = 0
    while user_input == 0:
        time.sleep(0.5)
        if user_input == "c":
            # do something
            listener.stop()
            break
        elif user_input == "v":
            # do something else
            listener.stop()
            break
    # other stuff

wait_for_user_input()

Is there a better way to do it ? (Maybe by having the listener stop & return the values c or v in on_press() ? If so, I couldn't find how to do it.)

Also : since wait_for_user_input() will be called multiple times, would it be better to not start and stop the listener repetitively, and instead have it start once and stop once ?

François M.
  • 4,027
  • 11
  • 30
  • 81

1 Answers1

4

You can put functions directly in on_press and then you don't need while loop. You may need only listener.join() which will wait for listener.stop()

from pynput import keyboard

def on_press(key):
    try:
        if key.char == "c":
            # do something
            return False  # Stop listener
        elif key.char == "v":
            # do something else
            return False  # Stop listener
    except AttributeError as ex:
        print(ex)

def on_release(key):
    if key == keyboard.Key.esc:
        # Stop listener
        return False

def wait_for_user_input():
    listener = keyboard.Listener(on_press=on_press, on_release=on_release)
    listener.start()
    listener.join() # wait till listener will stop
    # other stuff        

EDIT:

If you need run functions which result you need in other functions then you may stay with global user_input but you can write it little different.

from pynput import keyboard

def on_press(key):
    global user_input

    try:
        if key.char in ("c", "v"):
            user_input = key.char
            return False  # Stop listener
    except AttributeError as ex:
        print(ex)

def on_release(key):
    if key == keyboard.Key.esc:
        return False  # Stop listener

def wait_for_user_input():
    listener = keyboard.Listener(on_press=on_press, on_release=on_release)
    listener.start()
    listener.join() # wait till listener will stop

    if user_input == "c":
        # do something
    elif user_input == "v":
        # do something else
    else:
        print('You pressed ESC ?')

EDIT: If you use Windows then you could use msvcrt.getch which gives shorter and nicer code.

from msvcrt import getch

def wait_for_user_input():

    while True:
        user_input = getch()
        if user_input == "c":
            print('selected: c')
            break
        elif user_input == "v":
            print('selected: v')
            break
        elif user_input == escape:
            print('You pressed ESC ?')
            break

wait_for_user_input()

For Linux should be similar function getch() but with longer code.

See also module getch but I didn't check it.

furas
  • 134,197
  • 12
  • 106
  • 148
  • Ok, but what if I need what's returned by stuff in the `# do something` part later in `wait_for_user_input()` ? (or even later, after another function has called `wait_for_user_input()`) – François M. Jul 30 '19 at 01:46
  • then you have to stay with your current code and don't bother of "ugly hack". – furas Jul 30 '19 at 01:48
  • 1
    if you use Windows then you can use `msvcrt.getch()` in `while` loop and it will not look so ugly but very natural: [Python method for reading keypress?](https://stackoverflow.com/questions/12175964/python-method-for-reading-keypress) – furas Jul 30 '19 at 01:50
  • I created example with "ugly hack" but little nicer. – furas Jul 30 '19 at 02:03