A Python library for mouse and keyboard automation on Wayland compositors. Works out of the box on Hyprland, Sway, and other wlroots-based compositors.
- Mouse — click, move, swipe (drag), and auto-click at any screen coordinate
- Keyboard — type text, press individual keys, and trigger hotkeys (e.g.
Ctrl+S) - Cursor Tracking — real-time cursor position via multiple backends (Hyprland → wl-find-cursor → xdotool → evdev)
- Convenience API — top-level functions so you can
import wayland_automation as waand go - Resilient — automatic reconnection logic for Wayland socket resets
pip install wayland-automation| Dependency | What it does | Install command |
|---|---|---|
wtype |
Required — keyboard automation | sudo pacman -S wtype (Arch) / sudo apt install wtype (Debian) / sudo dnf install wtype (Fedora) |
wayland-utils |
Screen resolution detection | sudo pacman -S wayland-utils (Arch) / sudo apt install wayland-utils (Debian) |
The library auto-detects the best backend. You only need to install the one that matches your setup:
| Backend | Compositor | Install |
|---|---|---|
hyprctl |
Hyprland | Pre-installed with Hyprland |
wl-find-cursor |
Sway / wlroots | See build from source below |
xdotool |
XWayland apps | sudo pacman -S xdotool / sudo apt install xdotool |
evdev (fallback) |
Any | pip install evdev + add user to input group (see below) |
Building wl-find-cursor from source
git clone https://github.com/cjacker/wl-find-cursor.git
cd wl-find-cursor
make
sudo cp wl-find-cursor /usr/local/bin/Setting up evdev fallback
sudo usermod -aG input $USER
# Log out and back in for the group change to take effectThe simplest way to use the library — no class instantiation needed:
import wayland_automation as wa
# Mouse
wa.click(250, 300, "left") # left-click at (250, 300)
wa.click(400, 500, "right") # right-click
wa.swipe(100, 200, 800, 200) # drag from point A to B
wa.auto_click(initial_delay=2, interval=0.1, duration=5) # auto-clicker
# Keyboard
wa.typewrite("Hello Wayland!", interval=0.05) # type text character by character
wa.press("enter") # press a single key
wa.hotkey("ctrl", "s") # key combinationFor more control, instantiate Mouse or Keyboard:
from wayland_automation import Mouse, Keyboard
mouse = Mouse()
mouse.click(250, 300, "left") # left-click at (250, 300)
mouse.click(600, 400, "nothing") # move cursor without clicking
mouse.swipe(0, 500, 1000, 500, speed=0.5) # fast swipe (0.5 s)
kb = Keyboard()
kb.typewrite("Hello!", interval=0.05)
kb.press("enter")
kb.hotkey("ctrl", "a") # select all
kb.keyDown("shift") # hold shift
kb.keyUp("shift") # release shiftStream real-time cursor coordinates:
from wayland_automation import mouse_position_generator
for x, y in mouse_position_generator(interval=0.1):
print(f"Cursor at: ({x}, {y})")
# break whenever you want to stopAfter installing the package, a wayland-automation command is available:
wayland-automation # prints statusYou can also run the individual modules directly:
# Mouse — click at (x, y)
python -m wayland_automation.mouse_controller click 250 300 left
# Mouse — swipe
python -m wayland_automation.mouse_controller swipe 100 200 800 200
# Mouse — auto-click (delay interval duration button)
python -m wayland_automation.mouse_controller autoclick 3 0.1 10 left
# Mouse — run built-in test
python -m wayland_automation.mouse_controller test
# Cursor position watcher
python -m wayland_automation.mouse_positionMove the pointer to (x, y). If button is given ("left", "right", or "nothing"), perform a click.
Drag from one point to another. speed is duration in seconds ("normal" = 1.0 s).
Wait initial_delay seconds, then click every interval seconds for duration seconds.
Type text one character at a time with an optional delay between characters.
Press and release a single key (e.g. "enter", "tab", "backspace", "space").
Press a key combination (e.g. hotkey("ctrl", "shift", "t")). Modifier keys: ctrl, alt, shift, super.
Generator yielding (x, y) tuples of the current cursor position.
| Compositor | Mouse | Keyboard | Cursor Tracking | Notes |
|---|---|---|---|---|
| Hyprland | ✅ | ✅ | ✅ hyprctl |
Full support (wlroots-based) |
| Sway | ✅ | ✅ | ✅ wl-find-cursor |
Full support (wlroots-based) |
| KDE Plasma | ❌ | ✅ via wtype |
❌ | Mouse planned for KDE 6.5 (pointer-warp-v1) |
| GNOME | ❌ | ✅ via wtype |
❌ | Requires future protocol support |
| Problem | Likely cause | Fix |
|---|---|---|
BrokenPipeError / SIGPIPE |
Compositor disconnected the client | Ensure you are on a supported compositor and the protocol is available |
WaylandProtocolError |
zwlr_virtual_pointer_manager_v1 not supported |
Switch to a wlroots-based compositor (Hyprland / Sway) |
wtype not found |
System dependency missing | Install wtype (see Installation) |
| Cursor tracking returns nothing | No backend available | Install the backend matching your compositor (see table above) |
wayland_automation/
├── __init__.py # Public API & convenience functions
├── __main__.py # CLI entry point, dependency checks
├── mouse_controller.py # Wayland socket communication for virtual pointer
├── keyboard_controller.py # Keyboard automation via wtype
├── mouse_position.py # Multi-backend cursor position tracking
└── utils/
└── screen_resolution.py # Screen resolution detection
- KDE Plasma 6.5+
pointer-warp-v1protocol support - Improved error messages for unsupported compositors
- Scroll wheel support
Contributions welcome! See CONTRIBUTING.md for guidelines.