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
ModbusTCP2MQTT - Sungrow & SMA Solar Inverter addon for Home Assistant

ModbusTCP2MQTT Sungrow & SMA Solar Inverter addon for Home Assistant This addon will connect directly to your Inverter using Modbus TCP. Support model

Teny Smart 40 Dec 21, 2022
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
Example Python code for building RPi-controlled robotic systems

RPi Example Code Example Python code for building RPi-controlled robotic systems These python files have been compiled / developed by the Neurobionics

Elliott Rouse 2 Feb 04, 2022
Python application, displaying currently played track from Spotify on OLED display connected via I2C

RaspberryPi Spotify OLED Display This application will display currently played track on SSD1306 OLED display connected to RaspberryPi. Displayed stuf

Wojciech Olech 2 Dec 30, 2021
Andreas Frisch 1 Jan 10, 2022
A script for performing OTA update over BLE on ESP32

A script for performing OTA update over BLE on ESP32

Felix Biego 18 Dec 15, 2022
Parametric open source reconstructions of Voron printed parts

The Parametric Voron This repository contains Fusion 360 reconstructions of various printed parts from the Voron printers

Matthew Lloyd 26 Dec 19, 2022
Volta: A Virtual Assistant which increases your productivity with time as you use it…

Volta Official Documentation Overview & Purpose Volta: A Virtual Assistant which increases your productivity with time as you use it… Volta, developed

Abeer Joshi 1 Jan 14, 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
Code reimplementation of some papers published in SAIL-Lab

SAIL SAIL-Lab统一代码库 Motivation 创建这个项目的动机最早来源于实验室组内成员相互Debug代码的时候遇到的麻烦。

Jianwen Chen 8 Nov 15, 2022
DIY split-flap display

The goal is to make a low-cost display that's easy to fabricate at home in small/single quantities (e.g. custom materials can be ordered from Ponoko or similar, and other hardware is generally availa

Scott Bezek 2.5k Jan 05, 2023
Toy robot that traverses on a finite surface

Toy Robot Challenge - Release Notes November 12, 2021 New features Initialisation - Users can set the home position and heading of the robot. Position

Ze Fei Teo 0 Feb 03, 2022
Switch predictor for Home Assistant with AppDeamon

Home Assistant AppDeamon - Event predictor WORK IN PROGRESS - CURRENTLY NOT COMPLETE AND NOT WORK This is an idea under development (when I have free

37 Dec 17, 2022
Better support for Nuki devices to the Home Assistant

Another attempt to add a better support for Nuki devices to the Home Assistant Features: Lock interface implementation Uses local webhook from bridge

Konstantin 105 Jan 07, 2023
A Home Assistant sensor that tells you what holiday is next

Next Holiday Sensor This sensor tells you what holiday is coming up next. You can use it to set holiday light colors or other scenes. The state of the

Nick Touran 20 Dec 04, 2022
Tool to create 3D printable terrain with integrated path/road part files (Single material 3d printer)

BACKGROUND This has been an ongoing project of mine for a few months now. I run trails a lot and original the goal was to create a function to combine

9 Apr 26, 2022
Minimal and clean dashboard to visualize some stats of Pi-Hole with an E-Ink display attached to your Raspberry Pi

Clean Dashboard for Pi-Hole Minimal and clean dashboard to visualize some stats of Pi-Hole with an E-Ink display attached to your Raspberry Pi.

Alessio Santoru 104 Dec 14, 2022
A simple small scale electric car was build which can be driven by remote control and features a fully autonomous parking procedure.

personal-autonomous-parking-car-raspberry A simple electric car model was build using Raspbery pi. The car has remote control and autonomous operation

Kostas Ziovas 2 Jan 26, 2022
Pihole-eink-display - A simple Python script to display PiHole statistics on an eInk Display

Pihole-eink-display - A simple Python script to display PiHole statistics on an eInk Display

Mark McIntyre 64 Oct 11, 2022
Testing additional addon devices, and their working scripts

ESP32-addon-devices-potpurri Testing additional addon devices, and their micropython working scripts 📑 List of device addons tested so far Ethernet P

f-caro 0 Nov 26, 2022