Transform Nintendo Switch Joy-Cons into a wireless precision desktop mouse, couch media remote, and terminal companion on Linux with zero external dependencies.
Tip
๐ Tested on a different Linux distro, Steam Deck, or controller?
We'd love your feedback! Open an issue or testing report to share your distro and hardware setup, or submit a custom mode PR via CUSTOM_MODES.md.
-
Zero External Dependencies: Pure Python using standard library (
fcntl,struct,select,math,os,threading,importlib). No pip dependencies or wrappers. - Physical Haptic / Rumble Feedback: Joy-Con provides physical vibration clicks when switching modes, capturing screenshots, or unlocking credentials.
- Universal Modular Plugin Engine: Fully decoupled mode architecture. Every mode is a standalone, hot-discoverable Python plugin.
-
Built-in & Community Modes:
-
Desktop Mouse (
modes/air_mouse.py): Precision analog stick pointer with hybrid acceleration curve ($x^{1.6}$ ) and zero drift. -
Universal Media Remote (
modes/media_remote.py): Dedicated side-rail volume (SL/SR), subtitles (C), instant rewind (-10s), and analog stick continuous seek ($\pm 5\text{s}$ ). -
Interactive Terminal Controller (
modes/terminal.py): Hands-free AI pair programming & shell companion (Enter, HistoryUp/Down,Tabauto-complete,Esc,Ctrl+Cinterrupt,Ctrl+Lclear, and smooth buffer scrolling). -
Gaming & Macro Hotkeys (
custom_modes/gaming_hotkeys.py): Quick Save/Load, Map, Inventory, and F13-F16 macro keys. -
Wireless Presentation Clicker (
custom_modes/presentation.py): Slideshow control for Google Slides, Impress, and PowerPoint.
-
Desktop Mouse (
-
CLI Mode Manager: Manage, toggle, and scaffold modes directly via CLI (
--list-modes,--enable-mode,--disable-mode,--create-mode). -
Standalone Mode Execution: Every mode script can run independently (
python3 modes/terminal.py) to output complete visual cheatsheets. -
1-Click Auto-Start Background Service: Set up automatic background startup with
joycon-mouse --install-service. -
Live Button & Stick Diagnostic Tool: Interactive diagnostic visualizer (
joycon-mouse --test-buttons). -
User Configuration File: Persistent settings in
~/.config/joycon-mouse/config.jsonfor sensitivity, speeds, deadzones, rumble, and disabled modes. -
Auto-Dormant Game Detection: Non-blocking background thread yields hardware grabbing (
EVIOCGRAB) when Steam games or emulators launch. - Dual Joy-Con Pairing: Detects simultaneously connected Left and Right Joy-Cons and prompts to bind them into a single unified desktop controller.
-
Smart Dual-Action Buttons:
-
Tap Home / Capture (< 0.38s): Emits
Super/Windowskey (Application Overview). -
Hold Home / Capture (โฅ 0.38s): Emits
PrintScreen(Instant Screenshot with haptic double-click).
-
Tap Home / Capture (< 0.38s): Emits
joycon-mouse/
โโโ .gitignore # Excludes credentials, caches, and local virtualenvs
โโโ README.md # Public documentation
โโโ CUSTOM_MODES.md # Modular architecture guide & custom modes manual
โโโ CONTRIBUTING.md # Community contribution guidelines
โโโ LICENSE # MIT License
โโโ install.sh # Interactive 1-click installer & directory manager
โโโ setup.sh # Interactive setup wizard launcher
โโโ setup_wizard.py # Visual configuration wizard (modes, speeds, rumble)
โโโ uninstall.sh # Clean interactive uninstaller
โโโ joycon-mouse.py # Main polling loop, auto-dormant manager, mode manager
โโโ test_buttons.py # Interactive live button and stick diagnostic tool
โโโ security_manager.py.example # Open-source template for security features
โโโ modes/ # Built-in core modes (BaseMode subclasses)
โ โโโ __init__.py # Dynamic plugin auto-loader & template generator
โ โโโ base.py # BaseMode abstract class & Linux keycode constants
โ โโโ air_mouse.py # Mode 1: Precision Desktop Mouse & browser controls
โ โโโ media_remote.py # Mode 2: Universal media remote with side-rail volume
โ โโโ terminal.py # Mode 3: Interactive Terminal & Shell Controller
โโโ custom_modes/ # Community & user custom modes (Plug-and-Play)
โโโ gaming_hotkeys.py # Couch gaming hotkeys & F13-F16 macro keys
โโโ presentation.py # Wireless slideshow presentation clicker
Simply run the installer to set up Joy-Con Mouse in under 30 seconds:
./install.shThe installer will guide you through:
- Smart Location Selection: Installs into
~/.local/share/joycon-mouseby default (no root needed), keeps in-place if you cloned via git, or allows entering any custom directory. - Global Command Link: Installs the
joycon-mousecommand globally into yourPATH. - Hardware Permissions: Automatically checks Linux
inputgroup and loads/dev/uinput. - Bluetooth Reconnect Optimization: Automatically optimizes BlueZ so Joy-Cons reconnect immediately upon pressing any button.
- Guided Setup Wizard: Chains directly into the visual setup wizard to customize your enabled modes, sensitivity, and autostart daemon.
Re-adjust modes, mouse sensitivity presets, haptic rumble, and background autostart anytime:
# Via global CLI command:
joycon-mouse --setup
# Or via script in project folder:
./setup.shCleanly remove Joy-Con Mouse, background services, and binary links anytime:
# Via global CLI command:
joycon-mouse --uninstall
# Or via script in project folder:
./uninstall.shList connected controllers:
joycon-mouse -lLaunch the desktop driver:
joycon-mouseRun the driver automatically in the background on startup:
# Install and enable background service
joycon-mouse --install-service
# View live background service logs
journalctl --user -u joycon-mouse.service -f
# Uninstall service
joycon-mouse --uninstall-serviceRun the interactive button tester to inspect real-time raw scancodes, values, and mapped mode actions:
joycon-mouse --test-buttonsCustomize speeds, deadzones, and features in ~/.config/joycon-mouse/config.json:
{
"sensitivity": 1.0,
"speed_x": 36.0,
"speed_y": 36.0,
"dead_zone": 0.08,
"accel_exponent": 1.6,
"rumble_enabled": true,
"auto_dormant_enabled": true,
"scroll_repeat_ms": 70
}Cycle through active modes anytime by pressing + (Right Joy-Con) or - (Left Joy-Con).
| Button | Right Joy-Con | Left Joy-Con | Action |
|---|---|---|---|
| Trigger | ZR |
ZL |
Left Mouse Click |
| Bumper | R |
L |
Right Mouse Click |
| Side Rail SL | SL |
SL |
Escape (ESC) |
| Side Rail SR | SR |
SR |
Enter / Open (ENTER) |
| Face Up | X |
Up |
Scroll Up |
| Face Down | B |
Down |
Scroll Down |
| Face Left | Y |
Left |
Browser Back |
| Face Right | A |
Right |
Browser Forward |
| Stick Click | R3 |
L3 |
Middle Mouse Click |
| Home / Capture | Home |
Capture |
Tap: Super / Win |
| Button | Right Joy-Con | Left Joy-Con | Action |
|---|---|---|---|
| Trigger | ZR |
ZL |
Play / Pause |
| Bumper | R |
L |
Mute / Unmute Audio |
| Side Rail SL | SL |
SL |
Volume Down |
| Side Rail SR | SR |
SR |
Volume Up |
| Face Up | X |
Up |
Toggle Subtitles / Captions (C) |
| Face Down | B |
Down |
Instant Rewind (-10s) |
| Face Left | Y |
Left |
Previous Track |
| Face Right | A |
Right |
Next Track |
| Stick Click | R3 |
L3 |
Fullscreen Toggle (F) |
| Stick Left / Right | Tilt Left / Right | Tilt Left / Right | Continuous Seek ( |
| Button | Right Joy-Con | Left Joy-Con | Universal Controller | Action |
|---|---|---|---|---|
| Primary Trigger | ZR |
ZL |
RT / R2 |
Enter / Submit Command |
| Bumper | R |
L |
RB / R1 |
Tab Auto-Complete |
| Side Rail SL | SL |
SL |
LT / L2 |
Escape / Normal Mode |
| Side Rail SR | SR |
SR |
LB / L1 |
Cancel / Interrupt (Ctrl+C) |
| Face Up | X |
Up |
D-Pad Up |
Previous Command (History Up) |
| Face Down | B |
Down |
B / Circle |
Backspace / Erase Character |
| Face Left | Y |
Left |
D-Pad Down |
Next Command (History Down) |
| Face Right | A |
Right |
A / Cross |
Enter / Confirm Prompt |
| Stick Click | R3 |
L3 |
X / Square |
Clear Screen (Ctrl+L) |
| Analog Stick Tilt | Stick Up/Down | Stick Up/Down | Stick Up/Down | Smooth Terminal Buffer Scroll |
| Home / Capture | Home |
Capture |
Guide |
Tap: Super / Win | Hold: Screenshot |
| Plus / Minus | + |
- |
+ / Start |
Cycle Controller Mode |
| Button | Right Joy-Con | Left Joy-Con | Action |
|---|---|---|---|
| Trigger | ZR |
ZL |
Jump / Action (Space) |
| Bumper | R |
L |
Target / Tab (Tab) |
| Side Rail SL | SL |
SL |
User Macro 1 (F13) |
| Side Rail SR | SR |
SR |
User Macro 2 (F14) |
| Face Up | X |
Up |
Inventory (I) |
| Face Down | B |
Down |
Quick Load (F9) |
| Face Left | Y |
Left |
Map (M) |
| Face Right | A |
Right |
Quick Save (F5) |
| Stick Click | R3 |
L3 |
Character Sheet (C) |
| Button | Right Joy-Con | Left Joy-Con | Action |
|---|---|---|---|
| Trigger | ZR |
ZL |
Next Slide (Space) |
| Bumper | R |
L |
Previous Slide (Backspace) |
| Face Up | X |
Up |
Start Slideshow (F5) |
| Face Down | B |
Down |
Black Screen (B) |
| Face Left / Right | Y / A |
Left / Right |
Prev / Next Slide |
| Stick Click | R3 |
L3 |
Exit Slideshow (Esc) |
Joy-Con Mouse features a hot-discoverable plugin system. You can create custom modes, disable built-in modes you don't use, and share modes with the community.
For full architectural details, tutorials, and contribution guides, see CUSTOM_MODES.md.
# List all discovered built-in and community modes
joycon-mouse --list-modes
# Disable a mode from cycle loop (e.g. presentation)
joycon-mouse --disable-mode presentation
# Re-enable a mode
joycon-mouse --enable-mode presentation
# Scaffold a brand-new mode template in custom_modes/
joycon-mouse --create-mode my_custom_modeEvery mode script is completely standalone and runnable directly with Python without a controller:
python3 modes/terminal.py
python3 custom_modes/presentation.py
python3 custom_modes/gaming_hotkeys.pyTo use the optional local authentication / sudo injection system:
- Copy
security_manager.py.exampletosecurity_manager.py:cp security_manager.py.example security_manager.py
- Configure your secret unlock sequence:
joycon-mouse --set-code
- Credentials and local salt hashes are encrypted via
/etc/machine-idand stored strictly in your user directory~/.config/joycon-mouse/security_config.json. These files are ignored in.gitignore.
Contributions are warmly welcomed! Joy-Con Mouse was designed from the ground up to be modular and community-friendly. If you want to create a custom controller mode, enhance button mappings, or report hardware quirks:
- Read
CUSTOM_MODES.mdto see how to create and submit community modes. - Read the Contributing Guide for code style and standards.
- Please review our Code of Conduct.
- Open an Issue for feature requests or gamepad compatibility.
- Submit a Pull Request to share your mode with other Linux users!
- Releases & Changes: See
CHANGELOG.mdfor detailed version history. - Security Policy: See
SECURITY.mdfor vulnerability disclosure guidelines. - License: Distributed under the MIT License. Designed and crafted for the Linux and open-source gaming community.