Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
eef2ad1
docs: add Steam Controller v2 (2025) HID protocol notes + capture har…
C0rn3j Aug 2, 2026
0b8e61e
gui: offer all 4 grips + right-stick press in modeshift combo chooser
Patola Jun 15, 2026
723c894
gui: add 2nd grips + right-stick press to remaining button choosers
Patola Jun 15, 2026
54c6b4d
sc2/gui: bind capacitive stick touch; label left stick
Patola Jun 15, 2026
f3d4234
sc2/gui: bind capacitive handle grip sensing (Steam Controller only)
Patola Jun 15, 2026
5476881
gui: dedicated v2 (Steam Controller 2025) image + stick-touch/grip-se…
C0rn3j Aug 2, 2026
ed7d2d7
fix: Ignore X11 errors
C0rn3j Jul 19, 2026
466b86e
osd: per-controller binding display with a v2 (Steam Controller 2025)…
Patola Jun 18, 2026
211d2be
gui: "Edit Bindings" opens the OSD-keyboard bindings editor (sc-contr…
Patola Jun 18, 2026
6062bcb
gui: remove the abandoned controller-driven OSD edit mode (osd_mode)
C0rn3j Aug 30, 2026
0ddd1ab
gui: add "Act on release" (inverted button) for always-on sensors
Patola Jun 19, 2026
5fbdb52
daemon: remember each controller's profile across (re)connects
Patola Jun 19, 2026
978d3d1
gui: replace the per-controller profile bars with a controller selector
Patola Jun 20, 2026
60fe6bf
fix(gui): make "Restart emulation" wait for the old daemon to exit
Patola Jun 20, 2026
a00f1f0
fix(usb/sc_dongle): keep the v1 dongle alive when GET_SERIAL stalls
C0rn3j Jul 12, 2026
43f081a
fix(osd): Add input locking to prevent stuck keys
C0rn3j Jul 15, 2026
422a8d9
fix(daemon): release a held action when locking so its key-up isn't lost
Patola Jul 3, 2026
bd580b0
fix(osd): keep generic face-button icons for the v2 quick menu
Patola Jul 3, 2026
7810039
fix(osd): cancel the quick-menu auto-timeout on quit
Patola Jul 3, 2026
a1fce84
fix(gui): Input Test mode — selected controller, viewBox cursor, re-a…
Patola Jun 28, 2026
8b19b5b
feat(controller-images): Input Test highlights and test-area fixes (S…
Patola Jun 28, 2026
9c86b8b
fix(gui,images): correct Deck back-button mapping + stick-touch Input…
Patola Jun 28, 2026
6beb53e
fix(config): default "disable emulation on close" ON for Steam Deck
Patola Jun 28, 2026
c9f9b22
feat(gui,images): per-controller button-image override + Deck back-bu…
Patola Jun 28, 2026
4b1d612
fix(packaging,images): package per-controller icon dirs; Deck icons t…
Patola Jun 28, 2026
6d88c79
feat(images): consistent around-controller icons for Deck & SC2 (from…
Patola Jun 28, 2026
9e6e049
fix(images): lighten the Deck Steam/QAM button infill
Patola Jul 3, 2026
1c52e4d
fix(gui): SC v1 mislayout
Patola Jun 28, 2026
bd8d738
fix(gui): Deck button layout — D-Pad to top, Steam to the left column
Patola Jun 28, 2026
78eb7ab
fix(gui,osd): invisible OSD submenus
C0rn3j Aug 17, 2026
3829d7e
feat(gui): show the Steam logo on the Steam Controller v1 C button
Patola Jun 29, 2026
5c61e68
fix(gui): size the SC v1 Steam logo to the generic C button
Patola Jun 29, 2026
48f5e98
fix(gui): clear Input Test highlights when it is turned off
Patola Jul 1, 2026
60852cb
fix(gui): Deck back-paddle order in side panel (L4/R4 above L5/R5)
Patola Jul 2, 2026
a08fc87
build(images): add an svgo config and wire the asset generators to mi…
Patola Jul 3, 2026
b731a6b
perf(images): svgo-optimize the SC1/SC2/Deck SVGs
Patola Jul 3, 2026
c7b689f
style(types): annotate the Steam Controller v2 / Deck changeset
C0rn3j Aug 2, 2026
8674174
fix(osd): Steam Deck OSD menu - helpers work in the AppImage, no Turn…
C0rn3j Jul 12, 2026
7bd09b6
binding-display: auto-generate the template from controller art
Patola Jul 4, 2026
311305e
binding-display: add Steam Deck support
Patola Jul 4, 2026
665f496
sccdaemon: show/lock the invoking controller for Display Bindings
Patola Jul 4, 2026
bbd4cf6
osd/binding-display: fit the window to the screen (Steam Deck)
Patola Jul 4, 2026
e4300b3
osd/binding-display: shrink v1 labels to fit their boxes
Patola Jul 4, 2026
1773f0b
binding-display: honor group transforms when placing markers (Deck)
Patola Jul 4, 2026
b24fbc8
binding-display: add ds4/ds5/x360 templates
Patola Jul 4, 2026
34160f1
mapper: guard rstick/dpad state access for gamepads on the HID decoder
Patola Jul 4, 2026
91c0fe9
modifiers: neutralize a released absolute-gyro action in ModeModifier
Patola Jul 5, 2026
aace846
gui: fix gyro Per-Axis mouse-axis labels + add a Clear button
Patola Jul 5, 2026
6113f00
fix(gyro,gui): make gyro->mouse fully work (routing, labels, directio…
Patola Jul 6, 2026
dda64b3
fix(actions): decode euler gyros in TiltAction (rest false-fires, axi…
Patola Jul 9, 2026
77290e2
gyro: intuitive mouse semantics -- Absolute = laser pointer, relative…
Patola Jul 10, 2026
8bf9fbd
tests,docs: cover the 'inverted' modifier (3 long-failing meta-tests)
Patola Jul 11, 2026
98278de
fix(gyro): align "Mouse (Desktop)" signs with the calibrated rate table
Patola Jul 12, 2026
66eb02b
gui: per-controller grip/paddle button lists (gyro enablers, chords, …
Patola Jul 12, 2026
8a6c049
fix(gyro): make the Recenter Gyro special action actually recenter
Patola Jul 12, 2026
7d13545
docs: add a "Using multiple controllers" section to the README
Patola Jun 19, 2026
920a70d
docs(README): document the controller selector and add a multi-contro…
Patola Jun 21, 2026
3ddcced
docs(appimage): document AppImage udev steps
C0rn3j Jul 12, 2026
94a4f9e
docs(TODO.md): Add changes
Patola Jun 15, 2026
797eeff
gui: name the Bluetooth hidraw DualShock 4 in the controller list
Patola Jul 26, 2026
43309cc
sc1: convert the hardware quaternion to EUREL euler angles (one gyro …
Patola Jul 26, 2026
3e76c79
fix(gyro): re-center absolute gyro at every activation, not at release
Patola Jul 26, 2026
dbcc44b
fix(gyro): scale gyro output to the target axis' own range
Patola Aug 2, 2026
91e7281
fix(modeshift): give analog range conditions hysteresis
Patola Aug 2, 2026
7cc3ca6
fix(gyro): apply per-axis sensitivity once, before clamping
Patola Aug 2, 2026
2bee8d4
fix(sc2): enable the IMU quaternion stream, not just rates and accel
Patola Aug 8, 2026
cff4fed
fix(gui): make "Mouse (Emulate Stick)" actually emulate a stick
Patola Aug 8, 2026
1ecc6c1
fix(sc2): send the haptic gain as signed dB, not as an amplitude
Patola Aug 10, 2026
b5180d0
feat(sc2): real continuous rumble via output report 0x80
Patola Aug 10, 2026
795247a
docs(todo): scope SC2 actuator audio streaming (haptic reports 0x86-0…
Patola Aug 10, 2026
08881c5
feat(sc2): use both click presets, and add SCC_HAPTIC_DEBUG
Patola Aug 10, 2026
c0b3373
fix(sc2): spread haptic gain over the whole slider, split rumble motors
Patola Aug 10, 2026
21d289a
fix(rumble): never swallow an effect that carries no magnitudes
Patola Aug 10, 2026
13ca1f2
debug(rumble): dump the raw FF effect under SCC_HAPTIC_DEBUG
Patola Aug 10, 2026
e17d715
docs(sc2): record report 0x80 as hardware-verified
Patola Aug 10, 2026
35ffdfa
feat(sc2): tone, sweep and firmware-script haptic effects
Patola Aug 10, 2026
37824c8
feat(gui): choose the haptic effect in the action editor
Patola Aug 10, 2026
6fd108a
fix(gui): stop the action editor crashing on the effect table
Patola Aug 10, 2026
9cdcf1d
fix(gui): keep the haptic effect in the editor's tracked state
Patola Aug 10, 2026
a804d57
feat(gui): name the firmware haptic presets instead of a 0-255 slider
Patola Aug 10, 2026
647d17d
fix(gui): load the haptic effect widgets after parsing, not during
Patola Aug 11, 2026
86ec342
feat(gui): pair each haptic parameter slider with a spin button
Patola Aug 11, 2026
e517502
docs(sc2): record what the haptic effects and presets do on hardware
Patola Aug 11, 2026
5c135b1
fix(modifiers): do not lose sensitivity when a ball steps aside
C0rn3j Aug 17, 2026
9b3a562
fix(gui): let the haptic sliders reach their stated maximum
Patola Aug 11, 2026
ef889df
docs: Steam co-drives PlayStation pads over Bluetooth; DS4 haptics TODO
Patola Aug 11, 2026
84fe4e3
daemon: set restrictive umask to fix socket and file permissions
sergio-correia Aug 12, 2026
04fa55b
sc_by_bt: add bounds check to prevent heap overflow in BT driver
sergio-correia Aug 12, 2026
0e21bee
hiddrv: fix no-op CLAMP macro and add bounds checking
sergio-correia Aug 12, 2026
1a28701
IPC: restrict Replace: actions and validate Selected:/Profile: paths
sergio-correia Aug 12, 2026
e97e978
daemon: fix os.system() injection and scheduler task ordering
sergio-correia Aug 12, 2026
576a828
fix(gui): keep the haptic Effect chooser when no controller is attached
Patola Aug 14, 2026
1a23fe7
daemon: fix ReplacedAction forwarding and operator precedence bug
sergio-correia Aug 14, 2026
58b7b17
controller: fix HapticData.__mul__ double-scaling frequency
sergio-correia Aug 14, 2026
75d8b9c
drivers: fix STICK/RSTICK modeshift axes
C0rn3j Aug 17, 2026
32ce45f
hiddrv: fix button_map shift UB at position 32
sergio-correia Aug 14, 2026
60fb914
daemon: fix Subprocess race between _threaded and kill()
sergio-correia Aug 14, 2026
10b5f70
hiddrv: stop unmapped buttons pressing the right stick
C0rn3j Aug 17, 2026
944d65a
fix(config): stop a bad save or parse from wiping every setting
Patola Aug 14, 2026
1cb339d
fix(osd): stop an idle input cancelling navigation another is driving
C0rn3j Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 117 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ User-mode driver, mapper and GTK3 based GUI for Steam Controller, DS4 and many o

## Features
- Allows to setup, configure and use the Steam Controller without ever launching Steam
- Connect multiple controllers at the same time
- Connect multiple controllers at the same time, each with its own remembered profile
- Supports profiles switchable in GUI or with controller button
- Stick, Pads and Gyroscope input
- Steam Controller 2 (2026) support, including its capacitive stick-touch and grip sensors — bind actions to them directly, or use them as conditions in mode-shift combinations
- Haptic Feedback and in-game Rumble support
- OSD, Menus, On-Screen Keyboard for desktop *and* in games.
- Automatic profile switching based on active window.
Expand All @@ -23,6 +24,75 @@ User-mode driver, mapper and GTK3 based GUI for Steam Controller, DS4 and many o

Based on [Standalone Steam Controller Driver](https://github.com/ynsta/steamcontroller) by [Ynsta](https://github.com/ynsta).

## Using multiple controllers

SC Controller can drive several controllers at once — Steam Controllers (v1 and
v2), a DualShock 4 and others can all be connected together.

- **One window, two bars: pick the controller, then its profile.** Just connect
them: a controller-selector bar lists every connected controller (by type,
numbered when you have more than one of the same model) together with its
current profile; choosing one shows it on the big controller image, and a
second bar sets that controller's profile. There is no separate window per
device. The controller that connected *first* is the primary one — it is the
one drawn by default and the target when a command (a menu, the OSD) does not
name a specific controller.
- **Each controller keeps its own profile.** Selecting a controller and setting
a profile applies only to that controller. The choice is remembered and
restored automatically the next time that controller connects, so you do not
have to re-pick it every session.
- **Disconnecting is safe.** Turning one controller off (or letting it go idle)
leaves the window and the other controllers untouched; when it comes back it
returns to its remembered profile.

![SC Controller with three controllers connected](docs/multiple-controllers.jpg?raw=true)

*Two Steam Controller v1s and a Steam Controller v2 connected at once: the
selector at the top lists each controller — numbered when there are duplicates —
alongside its current profile.*

### Telling controllers apart

How a controller is identified — and therefore which remembered profile and
per-controller settings it gets — is governed by **Use Serial Numbers to
Identify Controllers** in *Settings*:

- **Off (default):** controllers are identified by connection order (first
connected, second connected, …). This is simplest for a fixed setup, but if
you change which controller powers on first they will swap profiles.
- **On:** each controller is identified by its own hardware serial number, so
its profile and settings follow the physical device no matter what order
things connect in.

Turn this **on** when you regularly use more than one controller — especially
two of the same model, such as two Steam Controllers — and want each to reliably
keep its own profile.

### PlayStation controllers: turn off Steam's controller support

A DualShock 4 or DualSense **cannot be claimed exclusively over Bluetooth**, and
this is worth knowing before you conclude something is broken.

Steam Controllers are taken exclusively: SC Controller claims the USB interface,
which detaches the kernel driver, and nothing else can reach the device. Over
Bluetooth a DS4/DS5 is reached through `/dev/hidrawN` instead — and hidraw
allows **several readers at once**. If Steam is running with PlayStation
controller support enabled, Steam and SC Controller both receive every report
and both act on it. There is no way for us to lock Steam out.

What that looks like in practice, and it does not look like a conflict:

- the touchpad moves the pointer with an acceleration and glide you never
configured, whatever the pad is actually bound to
- clicking the touchpad produces a mouse button instead of your binding, and
rebinding it changes nothing
- your own bindings *do* work — so the controller seems half-configured rather
than contested

Fix it in **Steam → Settings → Controller** by turning off *PlayStation
Controller Support*. Connecting the pad **by USB** also works, for a different
reason: claiming the USB interface takes the device away from Steam too.

## Like what I'm doing?

You can check out the ways to donate on [my website](https://rys.rs/donate), or just go straight to my [Ko-Fi](https://ko-fi.com/martinrys).
Expand All @@ -40,6 +110,23 @@ Linux:
- **Void Linux:** Packaged as [sc-controller](https://github.com/void-linux/void-packages/blob/master/srcpkgs/sc-controller/template) - Run `xbps-install -S sc-controller` in a terminal, points to archived Ryochan7's fork at the time of writing
- **Others:** You can attempt to use one of the AppImages (try all, AppImages built on older distributions tend to work better), or a package meant for your parent distribution if applicable. Flatpak is planned.

### AppImage: install the udev rules

The AppImage is self-contained but **cannot install the udev rules** it needs (those live in a system directory). Without them your user can't access the controller and SC Controller can't create the virtual gamepad (`/dev/uinput`), so a detected controller appears to "do nothing". Distro packages install these rules for you; **AppImage users must do it once, by hand:**

1. Download `69-sc-controller.rules` from the [latest release](https://github.com/Patola/sc-controller-cc/releases/latest).
2. Copy it into place — this needs `sudo`:
```sh
sudo cp 69-sc-controller.rules /etc/udev/rules.d/69-sc-controller.rules
```
3. Reload and re-apply the rules:
```sh
sudo udevadm control --reload-rules && sudo udevadm trigger
```
4. Unplug and replug the controller (or its wireless dongle) — or reboot.

Only the AppImage needs this; the Arch and other distro packages already ship these rules. **The Steam Deck doesn't need it either** — SteamOS already ships udev rules for Steam devices, so the AppImage works out of the box there.

Windows/macOS:
- Not planned, the half-finished C rewrite has Windows support but it has been abandoned, see https://github.com/C0rn3j/sc-controller/issues/44 for more info

Expand Down Expand Up @@ -80,3 +167,32 @@ docker build -o build-output --build-arg BASE_CODENAME=noble .
- Optionally checkout a branch or a tag, like `main`(default) or `v0.6.2`
- Execute `./run.sh`, this automatically builds the project into a venv called `.venv`, activates it and runs sc-controller, which in turn runs scc-daemon if one does not run already
- If you are debugging an issue, running `./run.sh daemon` first will launch the daemon in debug mode, allowing you to launch sc-controller in another terminal with `./run.sh` - note that sc-controller launched via `run.sh` always runs in debug mode too.

### Regenerating controller artwork (for contributors)

Some SVG assets under `images/` are **generated** from source drawings by scripts
in `tools/`, so edit the source and rerun the script rather than hand-editing the
committed output. All scripts run from the repository root and optimise their
output with [`svgo`](https://github.com/svg/svgo) when it is on `PATH` (optional;
without it the SVGs are just left un-minified). The `svgo` config
(`tools/svgo.config.js`) deliberately preserves the element ids, `<rect>`
geometry, `viewBox` and `display:none` layers that the GUI relies on.

- **`tools/gen_sc2_image.py`** — builds the Steam Controller v2 GUI artwork
(`images/controller-images/sc2.svg`, the face-button glyphs and side-panel
icons) from the traced sources in `tools/` (`sc2-source.svg`, `sc2-assets/`).

- **`tools/gen_binding_display.py`** — builds the per-controller *Display Current
Bindings* templates in `images/binding-display/<gui-background>.svg`. Instead of
a hand-drawn asset per controller, it derives each template straight from that
controller's GUI drawing (`images/controller-images/<name>.svg`): it scales the
drawing into the OSD canvas, recolours it into the binding-display palette
(green outlines over two greys on a dark backdrop) and drops a marker ring at
each control's `AREA_*` anchor so the binding boxes can draw connector lines to
them. The OSD then picks the file up automatically via the controller's gui
`background` name (see `scc/osd/binding_display.py`, `_resolve_image`).

To add a controller: give it an entry in the script's `CONTROLLERS` table (its
source drawing + which `AREA_*` anchors each binding box points at) and a
matching box layout in `LAYOUTS` in `scc/osd/binding_display.py`, then rerun the
script. Controllers that share a physical control set can share a layout.
Loading