Skip to content

NicolasPogorzelski/controller-manager

Repository files navigation

Controller Manager

Python Linux D-Bus systemd License: MIT

A small system-wide daemon that remaps game controllers between protocols on Linux, controlled from a tray icon. It presents a physical controller to applications under a different identity — for example, exposing a Sony DualSense as an Xbox 360 pad so that applications which only speak the XInput protocol see a controller they understand.

About

Many games and applications support only one controller protocol. A title that expects XInput (the Xbox protocol) will not recognise a controller that registers itself as a PlayStation device, even though both are ordinary gamepads. The usual workarounds are per-application and fragile.

Controller Manager solves this once, at the system level: it grabs the physical device on the kernel's input layer and re-emits its events through a virtual controller of the target type, before any application enumerates devices. The remap is selected per controller from a tray menu and applies uniformly to every launcher and application — there is no per-application configuration.

This repository is a self-contained tool and a worked example of a Linux input pipeline: evdev device grabbing, uinput virtual devices, raw HID access control, and a StatusNotifierItem tray served directly over D-Bus.

Features

  • Per-controller remapping — each connected controller has its own mode (native or remapped), chosen from the tray.
  • Multiple controllers at once — two identical pads are tracked independently via a stable per-device identity, so one can be native while the other is remapped.
  • Launcher-agnostic — works at the device layer, so every application sees the result regardless of how it was started.
  • Raw HID gating — closes the double-input gap that an evdev grab alone leaves open, including against processes that opened the pad before the gate (Steam Input) (see the hidraw gate decision).
  • Lightbar status colours (DualSense) — the pad shows its active mode at a glance: blue = native, green = Xbox emulation. Games may take the lightbar over while they run; the resting colour returns when they exit (see Steam coexistence).
  • Hotplug aware — controllers may be connected and disconnected at any time; the tray menu updates automatically.
  • No daemon dependencies beyond the standard desktop stackpython-evdev, dbus-python, and PyGObject.

How it works

Physical controller (evdev /dev/input/eventX)
   │
   ├── native mode ──────────► device passes through unchanged
   │
   └── remap mode
         ├── evdev grab (EVIOCGRAB)     exclusive kernel access to the source
         ├── uinput virtual device      the target-protocol controller
         ├── event loop                 forward EV_KEY / EV_ABS / EV_REL
         └── hidraw gate                hide the source's raw HID node from applications

A StatusNotifierItem tray icon (served over D-Bus, no toolkit dependency) exposes the per-controller mode menu. See docs/architecture/overview.md for the full design.

Requirements

  • A modern Linux desktop with a user systemd session.

  • A tray host that implements the StatusNotifierItem specification (most desktops do, some require an extension).

  • Write access to /dev/uinput (granted by group membership on most distributions).

  • Runtime packages:

    Package (typical name) Purpose
    python3-evdev read input devices, create uinput virtual devices
    python3-dbus (dbus-python) serve the tray item and menu over D-Bus
    python3-gi (PyGObject) GLib main loop

Installation

git clone https://github.com/NicolasPogorzelski/controller-manager.git
cd controller-manager
./install.sh

install.sh deploys the user-space daemon and service, then installs the root-owned hidraw gate helper, its udev rule and its sudoers rule (this step asks for a password). For the full procedure with verification and rollback, follow the installation runbook.

If you use Steam: set Settings → Controller → PlayStation controller support to "Enabled in Games w/o Support" (not "Enabled", not off). The Steam client then holds the pad permanently, but the daemon classifies game-vs-idle and restores the resting lightbar colour whenever no game runs; titles keep their native DualSense features. Also set Xbox controller support off. Turning PlayStation support off entirely is the one broken middle ground — Steam still opens the pad to identify it and latches the lightbar for no benefit. Details and trade-offs: Steam coexistence.

Enable autostart with the desktop session:

systemctl --user enable --now controller-manager.service

Usage

Open the tray icon to see every connected controller and its available modes as radio items. Selecting a mode applies it immediately and persists it.

Controller family Modes offered
PlayStation (DualSense) Native · Output as Xbox
Xbox Native

The reverse direction (output a PlayStation identity from an Xbox pad) is intentionally not offered; see output protocol constraints for why.

Configuration

Modes are persisted per device in ~/.config/controller-modes.json. The key is the controller's stable identity (its uniq, e.g. the Bluetooth MAC) so that two identical controllers keep separate settings:

{
  "ac:36:1b:70:70:e8": "ps5-xbox",
  "48:18:8d:53:37:6e": "ps5-native"
}

The file is managed by the daemon; it is normally not edited by hand. A stored mode that is no longer offered for a controller family falls back to that family's native default.

Supported controllers

Controllers are recognised by vendor plus gamepad capability, not a fixed product-ID list, so unlisted models of a known vendor still work. Product IDs are used only for nicer display names. Tested families: Sony DualSense and Microsoft Xbox One / Series pads, over USB and Bluetooth.

Documentation

Contributing

Contributions are welcome — see CONTRIBUTING.md for the commit format, validation script, and documentation conventions.

License

MIT

About

PS5 DualSense → Xbox/XInput remapper for Linux. System tray, per-device modes, hidraw gating — works with Steam, Proton, and any launcher. Python · evdev · uinput · D-Bus.

Topics

Resources

License

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors