Running keyboard and mouse listener at the same time

I am trying to make something with pynput that will detect when I press a key or move my mouse and open a tab depending on what I press. Here’s what the code looks like:

from pynput.keyboard import Listener as KeyboardListener
from pynput.mouse import Listener as MouseListener
import webbrowser

def on_press(key):
    if key:
        webbrowser.open('www.youtube.com')

def on_release(key):
    if key:
        webbrowser.open('www.youtube.com')

def on_move(x, y):
    print('Mouse moved')

with KeyboardListener(
        on_press=on_press,
        on_release=on_release) as keyboard_listener:
    keyboard_listener.join()

with MouseListener(
        on_move=on_move) as mouse_listener:
    mouse_listener.join()

The problem is that I can’t get it to detect mouse and keyboard inputs at the same time, if I delete the keyboard listener block all together, it detects my mouse movements just fine, but as it stands, it will not detect the mouse movement at all. How can I get it to detect them at the same time?

Hello, @pattydaone. (Sorry for very late answer). asyncio module is very useful for doing tasks concurrently. You can have a look at this documentation:
https://docs.python.org/3/library/asyncio.html
And, you may want to try this code below:

from pynput.keyboard import Listener as KeyboardListener
from pynput.mouse import Listener as MouseListener
import webbrowser,asyncio

def on_press(key):
    if key:
        webbrowser.open('www.youtube.com')

def on_release(key):
    if key:
        webbrowser.open('www.youtube.com')

def on_move(x, y):
    print('Mouse moved')
    
async def listenKeyboard():
	with KeyboardListener(on_press=on_press,on_release=on_release) as keyboard_listener:
	   keyboard_listener.join()
    
async def listenMouse():
	with MouseListener(on_move=on_move) as mouse_listener:
		mouse_listener.join()

async def main():
    # Schedule two calls *concurrently*:
    await asyncio.gather(listenKeyboard(),listenMouse())

asyncio.run(main()) 

I hope, that will help you.

1 Like

pynput.mouse.Listener and pynput.keyboard.Listener both ultimately inherit from threading.Thread. Shouldn’t there be some way to listen to both mouse and keyboard without resorting to use of asyncio? Years ago I wrote a mouse/keyboard watcher, but was never happy with the cruftiness of monitoring mouse and keyboard. It already uses the tkinter main loop. Mixing in threading (even if implicit) and asyncio seems like a recipe for fragility.

I tried this (XUbuntu 20.04 running XOrg, not Wayland). I got key press & release events. I never got a mouse move event.

Yes, I have just realized that. Thank you, @smontanaro . I tried some other ways to do the same process and found a way which works better than others -although it’s also not a so pretty way- :

import pynput.mouse as mouse
import pynput.keyboard as keyboard
import time,webbrowser

def on_move():
    print('Mouse moved')

def on_press():
        webbrowser.open('www.youtube.com')

def on_release():
    webbrowser.open('www.youtube.com')

def checkMouseEvents():
    with mouse.Events() as mouseEvents:
        mouseEvent = mouseEvents.get(0.1)
        if mouseEvent != None:
            if "Move" in str(mouseEvent):
                on_move()
def checkKeyboardEvents():
    with keyboard.Events() as keyboardEvents:
        keyboardEvent = keyboardEvents.get(0.1)
        if keyboardEvent != None:
            if "Press" in str(keyboardEvent):
                on_press()
            elif "Release" in str(keyboardEvent):
                on_release()
while True:
    time.sleep(0.05)
    checkKeyboardEvents()
    checkMouseEvents()