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
Cow Feeder is a bot automatically execute trade on cowswap

Cow Feeder is a bot automatically execute trade on cowswap, includes functions: Monitoring Ethereum network gas price and execute trade whe

6 Apr 20, 2022
KIRI - Keyboard Interception, Remapping, and Injection using Raspberry Pi as an HID Proxy.

KIRI - Keyboard Interception, Remapping and Injection using Raspberry Pi as a HID Proxy. Near limitless abilities for a keyboard warrior. Features Sim

Viggo Falster 10 Dec 23, 2022
Code for the paper "Planning with Diffusion for Flexible Behavior Synthesis"

Planning with Diffusion Training and visualizing of diffusion models from Planning with Diffusion for Flexible Behavior Synthesis. Guided sampling cod

Michael Janner 310 Jan 07, 2023
A script and GUI for controlling stepper motors from an arduino

A script and GUI for controlling stepper motors from an arduino (nema 23 in my case but should work for others in general)

Pip 2 Aug 01, 2022
A Macropad using the Raspberry Pi Pico, programmed with CircuitPython.

A Macropad using the Raspberry Pi Pico, programmed with CircuitPython.

15 Oct 14, 2022
Using a GNSS module (Beidou + GPS) and the mapquest static map API

Using a GNSS module (Beidou + GPS) and the mapquest static map API

Kongduino 1 Nov 04, 2021
View your medication from Medisafe Cloud in Home Assistant

Medisafe View your medication from Medisafe Cloud in Home Assistant. This integration adds sensors for today's upcoming, taken, skipped, and missed do

Sam Steele 12 Dec 27, 2022
Smart EQ connect - Custom Integration for Home Assistant

Smart EQ Connect platform as a Custom Component for Home Assistant.

Rene Nulsch 2 Jan 04, 2022
ENC28J60 Ethernet chip driver for MicroPython (RP2)

micropy-ENC28J60 ENC28J60 Ethernet chip driver for MicroPython v1.17 (RP2) Rationale ENC28J60 is a popular and cheap module for DIY projects. At the m

11 Nov 16, 2022
Various programs in Atari BASIC for #FujiNet for Atari 8-bit

FujiNet Various programs in Atari BASIC for #FujiNet for Atari 8-bit FujiNet-3D Tic Tac Toe In 1978, Scott Adams wrote a 3-D Tic Tac Toe game, for pla

Kay Savetz 2 Jan 01, 2022
Python script for printing to the Hanshow price-tag

This repository contains Python code for talking to the ATC_TLSR_Paper open-source firmware for the Hanshow e-paper pricetag. Installation # Clone the

12 Oct 06, 2022
Programmable Rainbow Redstone Computer

Programmable Rainbow Redstone Computer Table of contents What is it? Program flasher How to use it What is it? PRRC is Programmable Rainbow Redstone C

Fern H 2 Jun 07, 2022
Create a low powered, renewable generation forecast display with a Raspberry Pi Zero & Inky wHAT.

GB Renewable Forecast Display This Raspberry Pi powered eInk display aims to give you a quick way to time your home energy usage to help balance the g

Andy Brace 32 Jul 02, 2022
Turn your Raspberry Pi Pico into a USB Rubber Ducky

pico-ducky Turn your Raspberry Pi Pico into a USB Rubber Ducky Install Requirements CircuitPython for the Raspberry Pi Pico adafruit-circuitpython-bun

Konstantinos 5 Nov 08, 2022
ESP32 micropython implementation of Art-Net client

E_uArtnet ESP32 micropython implementation of Art-Net client Instalation Use thonny Open the root folder in thonny and upload the Empire folder like i

2 Dec 07, 2021
LED effects plugin for klipper

This plugin allows Klipper to run effects and animations on addressable LEDs, such as Neopixels, WS2812 or SK6812.

Julian Schill 238 Jan 04, 2023
Python module for controlling Broadlink RM2/3 (Pro) remote controls, A1 sensor platforms and SP2/3 smartplugs

Python module for controlling Broadlink RM2/3 (Pro) remote controls, A1 sensor platforms and SP2/3 smartplugs

Matthew Garrett 1.2k Jan 04, 2023
Projet d'integration SRI 3A ROS

projet-integration-sri-2021-2022 Projet d'intégration ROS SRI 2021 2022 Organization: Planification de tâches Perception Saisie: Cédérick Mouliets Sim

AIP Primeca Occitanie 3 Jan 07, 2022
🐱🖨Cat printer is a portable thermal printer sold on AliExpress for around $20.

Cat printer is a portable thermal printer sold on AliExpress for around $20. This repository contains Python code for talking to the cat printer over

671 Jan 05, 2023
This application works with serial communication. Use a simple gui to send and receive serial data from arduino and control leds and motor direction

This application works with serial communication. Use a simple gui to send and receive serial data from arduino and control leds and motor direction

ThyagoKZKR 2 Jul 18, 2022