CtrlAssist brings "controller assist" functionality to Linux gaming by allowing multiple physical controllers to operate as a single virtual input device. This enables collaborative play and customizable gamepad setups, making it easier for players of all ages and abilities to enjoy games together. While similar features exist on modern game consoles, CtrlAssist is an open source project that enhances accessibility for PC gaming, offering additional quality-of-life improvements through virtual input devices on Linux.
- ๐ฎ Combine physical controllers into one virtual gamepad
- Controllers are assigned as either Primary or Assist
- ๐๏ธ Customizable multiplexing modes for buttons and axes
- Logically merging or preempting events is flexible
- ๐ Hide physical controllers for improved game compatibility
- Multiple hiding strategies for avoiding interference
- ๐น๏ธ Spoof gamepad vendor for in-game layout recognition
- Mimic either Primary or Assist controller hardware
- ๐ซจ Rumble pass-through from virtual to physical devices
- Forward force feedback to either or both controllers
- ๐ฑ๏ธ System tray interface for graphical desktop environments
- Configure controllers and mux options via the taskbar
- Start/stop muxing with live status feedback
- Desktop notifications for status changes
- Persistent user settings across restarts
- ๐ Priority (default): Assist controller overrides when active
- Axes: Prioritize Assist when active (exceeds deadzone)
- Buttons: Prioritize Assist when button released
- Triggers: Prioritize largest value from either
- Ideal for partial and asynchronous assistance
- E.g. Assist for movement while Primary for actions
- Axes: Prioritize Assist when active (exceeds deadzone)
- โ๏ธ Average: Blend weighted inputs from both controllers
- Axes: Averaged when both are active (exceed deadzone)
- Buttons: logically OR'ed between pressed controllers
- Triggers: Averaged when both are active (exceed deadzone)
- Ideal for cooperative input and subtle corrections
- E.g. For counter steer/brake assist in racing games
- Axes: Averaged when both are active (exceed deadzone)
- ๐ Toggle: Switch Active controller on demand
- All inputs forwarded from currently active controller
- Toggle Active controller via the Mode button on Assist
- Immediately synchronizes input to current Active state
- Ideal when fine-grain conflict-free control is needed
- E.g. Game menu navigation or precise interventions
- All inputs forwarded from currently active controller
The following installation methods are available:
- ๐ฆ Cargo (Rust package manager)
- Ideal for customization and unsandboxed use
- Suitable for development and contributing
- E.g. fork custom features and upstream fixes
- ๐ฆ Flatpak (Linux application sandbox)
- Ideal for easy install on SteamOS, Bazzite, etc.
- Suitable for immutable Linux distributions
- E.g. where installing build tools is a hassle
- Build dependencies
- Rust toolchain
- https://rust-lang.org/tools/install/
- configure
PATHper Notes linked above
Add the --force flag to upgrade to latest version:
cargo install ctrlassist- Runtime dependencies
- Flatpak (likely already installed)
Download latest bundle from releases page and install:
export VERSION=v0.2.0
wget https://github.com/ruffsl/ctrlassist/releases/download/$VERSION/ctrlassist.flatpak
flatpak install --user ctrlassist.flatpakRun and test via Flatpak using the application ID:
flatpak run io.github.ruffsl.ctrlassist --helpOr launch as system tray via installed desktop icon.
Use the --help flag for information on each CLI subcommand:
$ ctrlassist --help
Multiplex multiple controllers into virtual gamepad
Usage: ctrlassist <COMMAND>
Commands:
list List all detected controllers and respective IDs
mux Multiplex connected controllers into virtual gamepad
tray Launch system tray app for graphical control
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print versionLaunch the system tray app for graphical control:
$ ctrlassist tray
CtrlAssist system tray started
Configure and control the mux from your system tray
Press Ctrl+C to exitThe system tray provides:
- Controller selection menus for Primary and Assist
- Configuration options for mux mode, hiding, spoofing, and rumble
- Start/Stop buttons with visual feedback
- Live status indicator in the tray icon
- Desktop notifications for status changes
- Persistent settings saved to
~/.config/ctrlassist/config.toml
Options are greyed out while the mux is running but show current active selections.
List all detected controllers and respective IDs:
$ ctrlassist list
(0) Microsoft Xbox One
(1) PS4 ControllerMultiplex first two detected controllers by default:
$ ctrlassist mux
Primary: (0) Microsoft Xbox One
Assist: (1) PS4 Controller
...
Mux Active. Press Ctrl+C to exit.Manually specify Primary and Assist controllers via IDs:
$ ctrlassist mux --primary 1 --assist 0
Primary: (1) PS4 Controller
Assist: (0) Microsoft Xbox One
...Manually specify mode for merging controllers:
$ ctrlassist mux --mode priority
...Mimic controller hardware for in-game layout recognition:
$ ctrlassist mux --spoof primary
Primary: (0) Microsoft Xbox One
Assist: (1) PS4 Controller
Virtual: (2) Microsoft X-Box One pad (Firmware 2015)Warning
Combining spoofing with some hiding strategies may also hide the virtual device.
Target force feedback to either or both physical controllers:
$ ctrlassist mux --rumble both
...There are multiple hiding strategies to avoid input conflicts:
| Strategy | Access/Compatibility | Granularity | Restart Required |
|---|---|---|---|
| Steam | No root, Flatpak compatible | Vendor/Product ID | Steam only |
| System | Root required, no Flatpak | Per-device | Game/Launcher |
For example, use Steam when running CtrlAssist via Flatpak. For 2v1 scenarios, where the third player not using CtrlAssist shares the same controller make and model, use System to avoid hiding the third player's gamepad.
Automatically configure Steam's controller blacklist:
$ ctrlassist mux --hide steam
...Note
Restart Steam for blacklist to take effect; CtrlAssist reverts config on exit.
Warning
Combining this hiding strategy with spoofing may also hide the virtual device.
Restrict device tree permissions system-wide:
$ sudo ctrlassist mux --hide system
...Note
Restart game/launcher to force rediscovery; CtrlAssist reverts change on exit.
Important
Not possible via Flatpak sandbox for security. Use --hide steam instead.
The system tray saves settings to $XDG_CONFIG_HOME/ctrlassist/config.toml:
# Last selected controllers (by name for best-effort matching)
primary_name = "Microsoft Xbox One"
assist_name = "PS4 Controller"
# Mux configuration
mode = "Priority"
hide = "Steam"
spoof = "None"
rumble = "Both"Settings are loaded on startup and saved when starting the mux. Controllers are matched by name (best-effort) if IDs change between sessions.
- System hiding requires root access
- temporarily modifies group permissions for selected devices
- Hiding must be done before starting games or launchers
- processes with open file handles may retain device access
- Reconnecting a hidden controller may revert its visibility
- Steam hiding persists across reconnects while CtrlAssist is running
- System hiding: custom udev rules needed for persistent permissions
- Steam hiding affects all controllers of the same make and model
- blacklists by vendor/product ID, not individual devices
- Steam hiding requires Steam restart
- Steam only checks controller_blacklist config on startup
- Toggle mode requires pressing all buttons and axes after startup
- gilrs lazily initializes gamepad state used for synchronization

