Hook and simulate global mouse events in pure Python

Related tags

Hardwaremouse
Overview

mouse

Take full control of your mouse with this small Python library. Hook global events, register hotkeys, simulate mouse movement and clicks, and much more.

Huge thanks to Kirill Pavlov for donating the package name. If you are looking for the Cheddargetter.com client implementation, pip install mouse==0.5.0.

Features

  • Global event hook on all mice devices (captures events regardless of focus).
  • Listen and sends mouse events.
  • Works with Windows and Linux (requires sudo).
  • Works with MacOS (requires granting accessibility permissions to terminal/python in System Preferences -> Security & Privacy)
  • Pure Python, no C modules to be compiled.
  • Zero dependencies on Windows and Linux. Trivial to install and deploy, just copy the files.
  • Python 2 and 3.
  • Includes high level API (e.g. record and play.
  • Events automatically captured in separate thread, doesn't block main program.
  • Tested and documented.

This program makes no attempt to hide itself, so don't use it for keyloggers.

Usage

Install the PyPI package:

$ sudo pip install mouse

or clone the repository (no installation required, source files are sufficient):

$ git clone https://github.com/boppreh/mouse

Then check the API docs to see what features are available.

Known limitations:

  • Events generated under Windows don't report device id (event.device == None). #21
  • To avoid depending on X the Linux parts reads raw device files (/dev/input/input*) but this requries root.
  • Other applications, such as some games, may register hooks that swallow all key events. In this case mouse will be unable to report events.

API

Table of Contents

class mouse.ButtonEvent

ButtonEvent(event_type, button, time)

ButtonEvent.button

Alias for field number 1

ButtonEvent.count(self, value, /)

Return number of occurrences of value.

ButtonEvent.event_type

Alias for field number 0

ButtonEvent.index(self, value, start=0, stop=9223372036854775807, /)

Return first index of value.

Raises ValueError if the value is not present.

ButtonEvent.time

Alias for field number 2

mouse.DOUBLE

= 'double'

mouse.DOWN

= 'down'

mouse.LEFT

= 'left'

mouse.MIDDLE

= 'middle'

class mouse.MoveEvent

MoveEvent(x, y, time)

MoveEvent.count(self, value, /)

Return number of occurrences of value.

MoveEvent.index(self, value, start=0, stop=9223372036854775807, /)

Return first index of value.

Raises ValueError if the value is not present.

MoveEvent.time

Alias for field number 2

MoveEvent.x

Alias for field number 0

MoveEvent.y

Alias for field number 1

mouse.RIGHT

= 'right'

mouse.UP

= 'up'

class mouse.WheelEvent

WheelEvent(delta, time)

WheelEvent.count(self, value, /)

Return number of occurrences of value.

WheelEvent.delta

Alias for field number 0

WheelEvent.index(self, value, start=0, stop=9223372036854775807, /)

Return first index of value.

Raises ValueError if the value is not present.

WheelEvent.time

Alias for field number 1

mouse.X

= 'x'

mouse.X2

= 'x2'

mouse.version

= '0.7.1'

mouse.is_pressed(button='left')

[source]

Returns True if the given button is currently pressed.

mouse.press(button='left')

[source]

Presses the given button (but doesn't release).

mouse.release(button='left')

[source]

Releases the given button.

mouse.click(button='left')

[source]

Sends a click with the given button.

mouse.double_click(button='left')

[source]

Sends a double click with the given button.

mouse.right_click()

[source]

Sends a right click with the given button.

mouse.wheel(delta=1)

[source]

Scrolls the wheel delta clicks. Sign indicates direction.

mouse.move(x, y, absolute=True, duration=0, steps_per_second=120.0)

[source]

Moves the mouse. If absolute, to position (x, y), otherwise move relative to the current position. If duration is non-zero, animates the movement. The fps of the animation is determined by 'steps_per_second', default is 120.

mouse.drag(start_x, start_y, end_x, end_y, absolute=True, duration=0)

[source]

Holds the left mouse button, moving from start to end position, then releases. absolute and duration are parameters regarding the mouse movement.

mouse.on_button(callback, args=(), buttons=('left', 'middle', 'right', 'x', 'x2'), types=('up', 'down', 'double'))

[source]

Invokes callback with args when the specified event happens.

mouse.on_click(callback, args=())

[source]

Invokes callback with args when the left button is clicked.

mouse.on_double_click(callback, args=())

[source]

Invokes callback with args when the left button is double clicked.

mouse.on_right_click(callback, args=())

[source]

Invokes callback with args when the right button is clicked.

mouse.on_middle_click(callback, args=())

[source]

Invokes callback with args when the middle button is clicked.

mouse.wait(button='left', target_types=('up', 'down', 'double'))

[source]

Blocks program execution until the given button performs an event.

mouse.get_position()

[source]

Returns the (x, y) mouse position.

mouse.hook(callback)

[source]

Installs a global listener on all available mouses, invoking callback each time it is moved, a key status changes or the wheel is spun. A mouse event is passed as argument, with type either mouse.ButtonEvent, mouse.WheelEvent or mouse.MoveEvent.

Returns the given callback for easier development.

mouse.unhook(callback)

[source]

Removes a previously installed hook.

mouse.unhook_all()

[source]

Removes all hooks registered by this application. Note this may include hooks installed by high level functions, such as record.

mouse.record(button='right', target_types=('down',))

[source]

Records all mouse events until the user presses the given button. Then returns the list of events recorded. Pairs well with play(events).

Note: this is a blocking function. Note: for more details on the mouse hook and events see hook.

mouse.play(events, speed_factor=1.0, include_clicks=True, include_moves=True, include_wheel=True)

[source]

Plays a sequence of recorded events, maintaining the relative time intervals. If speed_factor is <= 0 then the actions are replayed as fast as the OS allows. Pairs well with record().

The parameters include_* define if events of that type should be inluded in the replay or ignored.

Comments
  • Sending mouse events doesn't work.

    Sending mouse events doesn't work.

    Everything that simulate mouse event doesn't work, except on positioning/moving the cursor. Listening to mouse event works fine. My machine running on Debian 4.19.28-2 (2019-03-18) i686 GNU/Linux.

    opened by angeloped 6
  • Add MacOS (darwin) support

    Add MacOS (darwin) support

    • Re-used code from https://github.com/boppreh/keyboard (_darwinmouse.py) and adapted it to the event data structures used in this repo
    • Tested on macos 11 (Big Sur).
    • Solves #29 #30
    opened by dorinclisu 3
  • OSError: Unsupported platform 'Darwin'

    OSError: Unsupported platform 'Darwin'

    I'm getting the following error message:

    Traceback (most recent call last): File "count_keystrokes.py", line 1, in <module> import keyboard, mouse File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/mouse/__init__.py", line 51, in <module> raise OSError("Unsupported platform '{}'".format(_platform.system())) OSError: Unsupported platform 'Darwin'

    opened by kylefoley76 3
  • Capturing active window with mouse/keyboard events?

    Capturing active window with mouse/keyboard events?

    Are there plans to capture the active window that is beneath the mouse/keyboard events? This would help when one wants to ensure that the keyboard is replayed in the correct window.

    opened by reckoner 3
  • mouse.on_double_click not working

    mouse.on_double_click not working

    Hi,

    I have the issue where callback passed to mouse.on_double_click isn't invoked.

    I took a quick peek and it seems that handlermethod defined in mouse.on_button gets called twice successively. Each ButtonEvent passed to the handler has button = 'left' and event_type = 'down' members, instead of button = 'left' and event_type = 'double' which the handler checks for.

    This is the code I'm talking about.

    def on_button(callback, args=(), buttons=(LEFT, MIDDLE, RIGHT, X, X2), types=(UP, DOWN, DOUBLE)):
        """ Invokes `callback` with `args` when the specified event happens. """
        if not isinstance(buttons, (tuple, list)):
            buttons = (buttons,)
        if not isinstance(types, (tuple, list)):
            types = (types,)
    
        def handler(event):
            if isinstance(event, ButtonEvent):
                if event.event_type in types and event.button in buttons:
                    callback(*args)
        _listener.add_handler(handler)
        return handler
    

    I'm a little busy at the moment, but if I find time I'll make an attempt at fixing this.

    opened by dino8890 3
  • mouse.move doesnt accept a list

    mouse.move doesnt accept a list

    Doing this:

    button_left = [400, 960]
    button_middle = [480, 960]
    button_right = [580, 960]
    button_choices = [button_left, button_middle, button_right]
    mouse.move(random.choice(button_choices))
    
    TypeError: move() missing 1 required positional argument: 'y'
    

    Is there some other way i can do this?

    opened by Motzumoto 2
  • [help with code] high cpu usage

    [help with code] high cpu usage

    So, currently this is my code, i need to constantly check if the left mouse button is pressed, but, this code is taking about 25% of my CPU. How i can solve this problem?

    import mouse

    def main():

    while True:
        if mouse.is_pressed(button='left'):
            print('Left mouse is down!')
    

    if name == 'main': main()

    opened by skhrlx 2
  • mouse.move not moving to correct coordinates

    mouse.move not moving to correct coordinates

    When using mouse.move(), the coordinates are not correct, ie: if I have this:

    mouse.move(0, 1080, absolute=True)
    print(mouse.get_position())
    

    it should go to the bottom left (which it does) yet getting the mouse position reveals its actually 863. If I then do mouse.move(0, 863, absolute=True), it puts me at the bottom left again, further testing reveals it isn't going to the correct spot. This also happens on the x-axis, giving me a max of 1535.

    opened by Underslash12 2
  • Remove claim to support MacOS X from setup.py

    Remove claim to support MacOS X from setup.py

    It's kind of highly misleading to claim MacOS X support in setup.py while the code does in fact not support it. Other people might get confused as well. So removing this bit would be only fair: Operating System :: MacOS :: MacOS X

    See also #30.

    opened by deeplook 2
  • cannot figure out how to use mouse.on_double_click on Windows

    cannot figure out how to use mouse.on_double_click on Windows

    With the following code, I think the sayHello function should print out something when double clicking left mouse button , but none , so what's wrong here ?

    import mouse
    
    
    def sayHello():
        print(mouse.get_position(),'sayHello')
    mouse.on_double_click(sayHello)  # lambda: print(11111111111) callback, args=()
    
    mouse.wait(button='left', target_types=('double',))
    
    

    Tested on Win7 32 bit, Python 3.5.2

    opened by redstoneleo 2
  • PyPi MacOS Support

    PyPi MacOS Support

    I'm writing a small package that is dependent on mouse. However, for MacOS, I've found the only way to utilize mouse is to build using git+https://github.com/boppreh/mouse.git. Unfortunately, PyPi doesn't allow direct dependencies like this. Is there any plan to release a MacOS supported version to PyPi? If not, I'll refactor to not be dependent on mouse. Thanks for your work!

    opened by gansel51 1
  • get_position altered after importing pyautogui

    get_position altered after importing pyautogui

    Hi,

    After importing pyautogui, it appears that the screen size is altered and so for position given by get_position function.

    import mouse
    mouse.get_position()
    import pyautogui
    mouse.get_position()
    

    Here's what I get when I position my mouse in the bottom right corner, i get:

    >>> import mouse
    >>> mouse.get_position()
    (1279, 719)
    >>> import pyautogui
    >>> mouse.get_position()
    (1919, 1079)
    

    Is this normal behaviour ? Any workaround ?

    Versions: mouse 0.7.1 PyAutoGUI 0.9.53 Python 3.8.5 Windows 11

    opened by asasa137 0
  • Touchscreen support - Question

    Touchscreen support - Question

    so i was wondering if we have touchscreen support via mouse.

    my testing program:

    import mouse
    import time
    
    events = []
    mouse.hook(events.append)
    while 1:
        mouse._listener.queue.join()
        for event in events:
            print(event)
        del events[:]
        time.sleep(0.25)
    

    and if i touch and release the touchscreen i get:

    ButtonEvent(event_type='down', button='?', time=1664808330.854423)
    ButtonEvent(event_type='up', button='?', time=1664808331.035416)
    

    now i tried to trigger a callback-function via mouse.on_button But it looks like this doesnt work - since button "?" is not implemented?

    opened by Frankstar 0
  • not DPI aware

    not DPI aware

    Modern monitors may have a DPI much higher than 96, but unless an application tells Windows that it knows that, Windows assumes the application believes the DPI to be 96 and does some stretching . That means that you can have your resolution set to 1920x1080 and mouse.get_position() will still report the bottom right as (1535, 863).

    The solution is ctypes.windll.shcore.SetProcessDpiAwareness(2). Users of this library could import ctypes and set this in the application code themselves, but it would probably be better to put it into _winmouse.py.

    opened by snoyes 3
  • Is there a way to detect either up or down mouse wheel scrolling?

    Is there a way to detect either up or down mouse wheel scrolling?

    I am writing a script that needs to be triggered by each scroll up and down.

    mode = int(mode)
    if mode == 1:
        a_key = 1
        b_key = #scroll down
    elif mode == 2:
        a_key = -1
        b_key = #scroll up
    else:
        sys.exit()
    
    while True:
        if keyboard.is_pressed(key)
            while a < 30:
                mouse.wheel(a_key)
                time.sleep(1)
        if |**scroll detect**| (b_key)
            while a < 30:
                mouse.wheel(a_key)
                time.sleep(1)
    

    The full script looks like this I want to detect the top and bottom at this "Scroll detect" part. Since it is not allowed to scroll in the same direction as a_key, we can use other modules than the mouse module, but we prefer the mouse module as much as possible. Please help me.

    opened by YuATools 0
  • Docker support

    Docker support

    I would like to package an application that can access mouse movement as a docker container. It is possible to pass many other devices (webcams etc) to docker by mounting them as volumes/devices. Unfortunately, when I attempt that here, I receive a seg fault, but cannot determine how to troubleshoot it.

    Why docker? It is an easy way to develop on any machine, and then test/deploy anywhere.

    Reproducing the issue This can easily be reproduced by creating the following files:

    # main.py
    import mouse
    print(mouse.get_position())
    
    # Dockerfile
    FROM python:3.9.13
    WORKDIR /app
    RUN pip3 install mouse
    COPY main.py ./
    CMD [ "python", "./main.py"]
    
    # docker-compose.yaml
    version: "3.3"
    services:
      pymouse:
        build: .
        privileged: true
        devices:
          - /dev/mouse0
    

    Then simply run docker-compose up and the app will exit with code 139 (128+ 11) The log shows Segmentation fault (core dumped)

    When I run dmesg, I see the following:

    [ 7377.836267] python3[21490]: segfault at e0 ip 00007f2db4688000 sp 00007ffcf9085a98 error 4 in libX11.so.6.4.0[7f2db4672000+8c000]
    [ 7377.836278] Code: 07 48 03 b7 e8 00 00 00 48 8b 46 10 c3 66 66 2e 0f 1f 84 00 00 00 00 00 66 90 8b 87 e0 00 00 00 c3 66 0f 1f 84 00 00 00 00 00 <48> 63 87 e0 00 00 00 48 c1 e0 07 48 03 87 e8 00 00 00 48 8b 40 10
    

    Any thoughts on how to investigate this? Thanks

    opened by day1118 0
Releases(v0.7.1)
Owner
BoppreH
BoppreH
A python script to poll RPi GPIO pins and subscribe and publish their state via MQTT

MQTT-GPIO A python script to poll RPi GPIO pins and subscribe and publish their state via MQTT using TLS. This script is short and meant to be edited

23 Oct 12, 2021
The software that powers the sPot: a 4th generation

This code is meant to accompany this project in which a Spotify client is built into an iPod "Classic" from 2004. Everything is meant to run on a Raspberry Pi Zero W.

Guy Dupont 683 Dec 28, 2022
a weather application for the raspberry pi and the Pimorioni Inky pHAT.

raspi-weather a weather application for the raspberry pi and the Inky pHAT

Derek Caelin 59 Oct 24, 2022
Tools and documentation to aid in modifying the ADI ADALM Pluto firmware

Pluto firmware modifications This repository contains tools and documentation to aid in modifying the ADI ADALM Pluto firmware. Extraction of the Plut

Daniel Estévez 28 Dec 21, 2022
Programming of Robotics Systems course at the University of Aveiro, Portugal, 2021-2022.

Programação de Sistemas Robóticos Miguel Riem Oliveira Universidade de Aveiro 2021-2022 Projeto AtlasCar Projecto RACE IROS 2014 AtlasCar2 ATOM IROS 2

Miguel Riem de Oliveira 22 Jul 13, 2022
Robo Arm :: Rigging is a rigging addon for Blender that helps animating industrial robotic arms.

Robo Arm :: Rigging Robo Arm :: Rigging is a rigging addon for Blender that helps animating industrial robotic arms. It construct serial links(a kind

2 Nov 18, 2021
Testing out some (stolen) DMA code for RP2040 Micropython

RP2040_micropython_dma testing out some (stolen) DMA code for RP2040 Micropython. Heavy inspiration and some code from https://iosoft.blog/2021/10/26/

2 Dec 29, 2022
Keystroke logging, often referred to as keylogging or keyboard capturing

Keystroke logging, often referred to as keylogging or keyboard capturing, is the action of recording the keys struck on a keyboard, typically covertly, so that a person using the keyboard is unaware

Bhumika R 2 Jan 11, 2022
MicroPython driver for 74HC595 shift registers

MicroPython 74HC595 A MicroPython library for 74HC595 8-bit shift registers. There's both an SPI version and a bit-bang version, each with a slightly

Mike Causer 17 Nov 29, 2022
ESP32 recording button presses, and serving webpage that graphs the numbers over time.

ESP32-IoT-button-graph-test ESP32 recording button presses, and serving webpage via webSockets in order to graph the responses. The objective was to t

f-caro 1 Nov 30, 2021
Turns a compatible Raspberry Pi device into a smart USB drive for PS4/PS5.

PSBerry A WIP project for Raspberry Pi, which turns a compatible RPI device into a smart USB drive for PS4/PS5. Allows for save management of PS4 game

Filip Tomaszewski 2 Jan 15, 2022
Raspberry Pi Pico Escape Room game.

Pico Escape Room Raspberry Pi Pico Escape Room game. Parts Raspberry Pi Pico Set of 2 x 20-pin Headers for Raspberry Pi Pico 4PCS Breadboards Kit Incl

Kevin Thomas 5 Feb 02, 2022
A python module for interacting with rolimon's, a roblox value site.

rpi - rolimon's python interaction rpi is an open source python-based rolimon's api wrapper. It provides an end-to-end pipeline in which each componen

Acier 11 Nov 08, 2022
Shotgrid Toolkit Engine for Gaffer

Shotgun toolkit engine for Gaffer Contact : Diego Garcia Huerta Overview Implementation of a shotgun engine for Gaffer. It supports the classic bootst

Diego Garcia Huerta 12 May 21, 2022
OctoPrint is the snappy web interface for your 3D printer!

OctoPrint OctoPrint provides a snappy web interface for controlling consumer 3D printers. It is Free Software and released under the GNU Affero Genera

OctoPrint 7.1k Jan 03, 2023
Rasberry Pie GPIO memory game. Press the corresponding key to the lit LED.

RPie-keyboard-game Rasberry Pie GPIO memory game. Press the corresponding key to the lit LED. Randem LED (general output) is lit up on rasberrypi rand

Shawn Dowling 1 Oct 24, 2021
Using a raspberry pi, we listen to the coffee machine and count the number of coffee consumption

A typical datarootsian consumes high-quality fresh coffee in their office environment. The board of dataroots had a very critical decision by the end of 2021-Q2 regarding coffee consumption.

dataroots 51 Nov 21, 2022
Sensor of Temperature Feels Like for Home Assistant.

Please ⭐ this repo if you find it useful Sensor of Temperature Feels Like for Home Assistant Installation Install from HACS (recommended) Have HACS in

Andrey 60 Dec 25, 2022
Claussoft Personal Digital Assistant

Claussoft Personal Digital Assistant Install on Linux $ sudo apt update $ sudo apt install espeak ffmpeg libespeak1 portaudio19-dev $ pip install -r r

Christian Clauss 3 Dec 14, 2022
A python library written for the raspberry pi.

A python package for using certain components on the raspberry pi.

Builder212 1 Nov 09, 2021