Skip to content

Repository files navigation

๐ŸŽฎ Joy-Con Mouse & Universal Media Remote for Linux

License: MIT Python 3.8+ Platform CI Release Dependencies PRs Welcome

Transform Nintendo Switch Joy-Cons into a wireless precision desktop mouse, couch media remote, and terminal companion on Linux with zero external dependencies.


Joy-Con Mouse for Linux Banner

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.


๐ŸŒŸ Key Features

  • 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:
    1. Desktop Mouse (modes/air_mouse.py): Precision analog stick pointer with hybrid acceleration curve ($x^{1.6}$) and zero drift.
    2. 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}$).
    3. Interactive Terminal Controller (modes/terminal.py): Hands-free AI pair programming & shell companion (Enter, History Up/Down, Tab auto-complete, Esc, Ctrl+C interrupt, Ctrl+L clear, and smooth buffer scrolling).
    4. Gaming & Macro Hotkeys (custom_modes/gaming_hotkeys.py): Quick Save/Load, Map, Inventory, and F13-F16 macro keys.
    5. Wireless Presentation Clicker (custom_modes/presentation.py): Slideshow control for Google Slides, Impress, and PowerPoint.
  • 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.json for 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 / Windows key (Application Overview).
    • Hold Home / Capture (โ‰ฅ 0.38s): Emits PrintScreen (Instant Screenshot with haptic double-click).

๐Ÿ“ Repository Structure

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

๐Ÿš€ Quick Start

1. Interactive 1-Click Installer (Recommended)

Simply run the installer to set up Joy-Con Mouse in under 30 seconds:

./install.sh

The installer will guide you through:

  • Smart Location Selection: Installs into ~/.local/share/joycon-mouse by default (no root needed), keeps in-place if you cloned via git, or allows entering any custom directory.
  • Global Command Link: Installs the joycon-mouse command globally into your PATH.
  • Hardware Permissions: Automatically checks Linux input group 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.

2. Interactive Setup Wizard (joycon-mouse --setup)

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.sh

3. Clean Uninstaller (joycon-mouse --uninstall)

Cleanly remove Joy-Con Mouse, background services, and binary links anytime:

# Via global CLI command:
joycon-mouse --uninstall

# Or via script in project folder:
./uninstall.sh

4. Running the Driver Manually

List connected controllers:

joycon-mouse -l

Launch the desktop driver:

joycon-mouse

๐Ÿ”„ Automatic Background Startup (Systemd)

Run 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-service

๐ŸŽฎ Real-Time Button & Stick Diagnostic Tool

Run the interactive button tester to inspect real-time raw scancodes, values, and mapped mode actions:

joycon-mouse --test-buttons

โš™๏ธ Configuration (~/.config/joycon-mouse/config.json)

Customize 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
}

๐ŸŽฎ Controller Layouts & Modes

Cycle through active modes anytime by pressing + (Right Joy-Con) or - (Left Joy-Con).

Mode 1: Desktop Mouse

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

Mode 2: Universal Media Remote

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 ($\pm 5 ext{s}$)

Mode 3: Interactive Terminal Controller

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

Mode 4: Gaming & Macro Hotkeys (Community 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)

Mode 5: Wireless Presentation Clicker (Community Mode)

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)

๐Ÿงฉ Modular Plugins & Community Modes

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.

CLI Mode Management

# 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_mode

Standalone Mode Testing

Every 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.py

๐Ÿ”’ Security Module

To use the optional local authentication / sudo injection system:

  1. Copy security_manager.py.example to security_manager.py:
    cp security_manager.py.example security_manager.py
  2. Configure your secret unlock sequence:
    joycon-mouse --set-code
  3. Credentials and local salt hashes are encrypted via /etc/machine-id and stored strictly in your user directory ~/.config/joycon-mouse/security_config.json. These files are ignored in .gitignore.

๐Ÿค Contributing & Community Standards

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.md to 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!

๐Ÿ“œ Changelog, Security & License

  • Releases & Changes: See CHANGELOG.md for detailed version history.
  • Security Policy: See SECURITY.md for vulnerability disclosure guidelines.
  • License: Distributed under the MIT License. Designed and crafted for the Linux and open-source gaming community.

About

Zero-dependency Linux desktop mouse driver, media remote, and terminal companion for Nintendo Switch Joy-Cons and gamepads via native uinput & evdev.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages