Search code examples
pythonmultithreadingkeyboard

How do you terminate threading using Pyinput


I realize this question has been asked many times but I have a very difficult time understanding threading and with statement and consequently I cannot understand the other answers given. I was able to accomplish this task about 5 years ago but my threading skills have since fallen into disuse. In any case, I'm trying to register the x,y coordinates of a mouse click, store the values to a global, then terminate the keyboard listener, then do other things. In the code below, I cannot get the code to advance to where it says p("done"), even after I press the 'e' button. When I pause the code and analyse the values of the done variable it will output 1 so I don't understand why the code is not advancing to the next line. Again, I want to iterate to please not assume that I understand what you're saying when you talk about threading or with statements. I have only a very vague notion of what these things do.

from pynput import keyboard, mouse

done = 0
xa = 0
ya = 0
p = print

def on_click(x, y, button, pressed):
    global xa, ya
    print (x,y)
    xa = x
    ya = y

def on_press(key):
    global done
    if key.char == 'e':
        done = 1

def listen():
    global done
    with keyboard.Listener(on_press=on_press) as kl, \
            mouse.Listener(on_click=on_click) as ml:
        kl.join()
        ml.join()
        while 1:
            if done:
                p ('done')
                kl.terminate()
                ml.terminate()
                p ('you did it')
                return

Solution

  • Quick research: There should be stop conditions in mouse's on_click and keyboard's on_release. on_release is not presented in your example but the keyboard listener needs it implemented to accurately stop listening.

    I've changed the example a bit. Notice the lines where I put the comment "# Stop listener". They are simply a branching statement.

    from pynput import keyboard, mouse
    
    done = 0
    xa = 0
    ya = 0
    p = print
    
    
    def on_click(x, y, button, pressed):
        global xa, ya
        print(x, y)
        xa = x
        ya = y
        if not pressed:
            # Stop listener
            return False
    
    
    def on_press(key):
        global done
        try:
            if key.char == "e":
                done = 1
        except:
            pass
    
    
    def on_release(key):
        try:
            if key.char == "e":
                # Stop listener
                return False
        except:
            pass
    
    
    def listen():
        global done
        with keyboard.Listener(on_press=on_press, on_release=on_release) as kl, \
            mouse.Listener(on_click=on_click) as ml:
            kl.join()
            ml.join()
            while 1:
                if done:
                    p("done")
                    kl.stop() # .terminate() is incorrect
                    ml.stop() # .terminate() is incorrect
                    p("you did it")
                    return
    
    
    listen()