Control your mouse cursor with a gamepad on Linux.
gamepad-mouse is a tiny, dependency-light daemon that reads a gamepad through
evdev and emits mouse movement, clicks, and scroll through a virtual uinput
device. Because the output happens at the kernel input layer, it works the
same under X11 and Wayland — and even at the display-manager login screen —
without any desktop application or GUI configuration.
It was written for a machine that had no mouse attached, so everything is configured in code and runs as a systemd service; there is nothing to click through.
| Control | Action |
|---|---|
| D-pad | Move the cursor (starts slow, accelerates while held) |
| B | Left click |
| A | Right click |
| L | Scroll up |
| R | Scroll down |
All of this is defined by constants at the top of gamepad-mouse.py — edit and
restart the service to change it.
Tested with a generic wireless SNES-style USB gamepad:
- USB device string:
Homertech MICREAL GAMEPAD for XBox - The Linux
xpaddriver exposes it as:Microsoft X-Box 360 pad - The D-pad is reported as
ABS_HAT0X/ABS_HAT0Y; face buttons asBTN_SOUTH(physical B on this adapter) andBTN_EAST(physical A); shoulders asBTN_TL/BTN_TR.
Any pad that the kernel presents with a standard gamepad button layout should
work. The script also falls back to treating the left analog stick
(ABS_X / ABS_Y) as directional input, so most controllers are covered.
Note on A/B: many SNES→USB adapters swap A and B relative to the Xbox layout. This project ships with B = left click, A = right click, which matched the tested adapter. If yours feels reversed, swap
LEFT_BTNandRIGHT_BTNingamepad-mouse.py.
- Linux with systemd
- Python 3
python3-evdev(installed automatically byinstall.shon Debian/Ubuntu/Pop!_OS)- The
uinputkernel module (loaded automatically byinstall.sh)
git clone <your-repo-url> gamepad-mouse
cd gamepad-mouse
sudo ./install.shThe installer will:
- install the
python3-evdevdependency, - load the
uinputmodule (and make it load at boot), - copy
gamepad-mouse.pyto/usr/local/bin/, - install and enable the
gamepad-mousesystemd service so it starts on every boot, - start it immediately.
Then grab the gamepad and move the D-pad — the cursor should follow.
sudo systemctl status gamepad-mouse # is it running?
sudo systemctl restart gamepad-mouse # after editing the script
sudo systemctl stop gamepad-mouse # stop for now
sudo systemctl disable --now gamepad-mouse # stop and don't start at boot
journalctl -u gamepad-mouse -e # view logsOpen /usr/local/bin/gamepad-mouse.py (or edit the repo copy and re-run
install.sh) and adjust the constants near the top:
| Constant | Meaning |
|---|---|
BASE |
Initial cursor speed (pixels per tick) |
MAXV |
Maximum cursor speed |
ACCEL |
How fast it accelerates while a direction is held |
SCROLL_TICKS |
Lower = faster scrolling |
LEFT_BTN / RIGHT_BTN |
Which physical buttons click |
SCROLL_UP_BTN / SCROLL_DOWN_BTN |
Which buttons scroll |
Restart the service after any change.
If some buttons don't behave, list what your pad actually sends:
sudo apt-get install -y evtest
sudo evtest # pick your gamepad, then press buttons and read the codesMap the reported BTN_* / ABS_* names onto the constants in the script.
By default the service runs as root, which can always write to
/dev/uinput. If you prefer to run the script as your own user, install the
udev rule and join the input group:
sudo install -m 644 99-uinput.rules /etc/udev/rules.d/99-uinput.rules
sudo udevadm control --reload-rules && sudo udevadm trigger /dev/uinput
sudo usermod -aG input "$USER" # then log out and back insudo ./uninstall.shMIT — see LICENSE.
