Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
619f033
gui: offer all 4 grips + right-stick press in modeshift combo chooser
Patola Jun 15, 2026
41e455d
gui: add 2nd grips + right-stick press to remaining button choosers
Patola Jun 15, 2026
f1f9408
sc2/gui: bind capacitive stick touch; label left stick
Patola Jun 15, 2026
16d4913
sc2/gui: bind capacitive handle grip sensing (Steam Controller only)
Patola Jun 15, 2026
f5ee4e0
gui: dedicated v2 (Steam Controller 2025) image + stick-touch/grip-se…
C0rn3j Aug 2, 2026
d10150a
fix: Ignore X11 errors
C0rn3j Jul 19, 2026
7657092
osd: per-controller binding display with a v2 (Steam Controller 2025)…
Patola Jun 18, 2026
53ac25b
gui: "Edit Bindings" opens the OSD-keyboard bindings editor (sc-contr…
Patola Jun 18, 2026
4aa33ba
gui: remove the abandoned controller-driven OSD edit mode (osd_mode)
C0rn3j Aug 30, 2026
6074935
gui: add "Act on release" (inverted button) for always-on sensors
Patola Jun 19, 2026
285a2d2
daemon: remember each controller's profile across (re)connects
Patola Jun 19, 2026
be69ce4
gui: replace the per-controller profile bars with a controller selector
Patola Jun 20, 2026
ad457b8
fix(gui): make "Restart emulation" wait for the old daemon to exit
Patola Jun 20, 2026
e8cb147
fix(usb/sc_dongle): keep the v1 dongle alive when GET_SERIAL stalls
C0rn3j Jul 12, 2026
3e99b2b
fix(osd): Add input locking to prevent stuck keys
C0rn3j Jul 15, 2026
cb81f8d
fix(daemon): release a held action when locking so its key-up isn't lost
Patola Jul 3, 2026
6cc466e
fix(osd): keep generic face-button icons for the v2 quick menu
Patola Jul 3, 2026
fbff489
fix(osd): cancel the quick-menu auto-timeout on quit
Patola Jul 3, 2026
06399cf
fix(gui): Input Test mode — selected controller, viewBox cursor, re-a…
C0rn3j Sep 13, 2026
366a7a2
fix(config): default "disable emulation on close" ON for Steam Deck
Patola Jun 28, 2026
a731dec
feat(gui,images): per-controller button-image override + Deck back-bu…
Patola Jun 28, 2026
9bbaeba
fix(packaging,images): package per-controller icon dirs; Deck icons t…
Patola Jun 28, 2026
753f82f
feat(images): consistent around-controller icons for Deck & SC2 (from…
Patola Jun 28, 2026
ed69ee0
fix(images): lighten the Deck Steam/QAM button infill
Patola Jul 3, 2026
b7d5409
fix(gui): SC v1 mislayout
Patola Jun 28, 2026
060b408
fix(gui): Deck button layout — D-Pad to top, Steam to the left column
Patola Jun 28, 2026
19659fb
fix(gui,osd): invisible OSD submenus
C0rn3j Aug 17, 2026
3adc948
feat(gui): show the Steam logo on the Steam Controller v1 C button
Patola Jun 29, 2026
4fd6fb6
fix(gui): size the SC v1 Steam logo to the generic C button
Patola Jun 29, 2026
a49eab0
fix(gui): clear Input Test highlights when it is turned off
Patola Jul 1, 2026
44e64fa
fix(gui): Deck back-paddle order in side panel (L4/R4 above L5/R5)
Patola Jul 2, 2026
d2f0960
build(images): add an svgo config and wire the asset generators to mi…
Patola Jul 3, 2026
ff83cf3
perf(images): svgo-optimize the SC1/SC2/Deck SVGs
C0rn3j Sep 13, 2026
13b1b33
style(types): annotate the Steam Controller v2 / Deck changeset
C0rn3j Aug 2, 2026
c823e50
fix(osd): Steam Deck OSD menu - helpers work in the AppImage, no Turn…
C0rn3j Jul 12, 2026
144a793
binding-display: auto-generate the template from controller art
Patola Jul 4, 2026
c9b5576
binding-display: add Steam Deck support
Patola Jul 4, 2026
0c67ce7
sccdaemon: show/lock the invoking controller for Display Bindings
Patola Jul 4, 2026
b37cdfb
osd/binding-display: fit the window to the screen (Steam Deck)
Patola Jul 4, 2026
40e49eb
osd/binding-display: shrink v1 labels to fit their boxes
Patola Jul 4, 2026
60f4400
binding-display: honor group transforms when placing markers (Deck)
Patola Jul 4, 2026
f823663
binding-display: add ds4/ds5/x360 templates
Patola Jul 4, 2026
363d7dc
mapper: guard rstick/dpad state access for gamepads on the HID decoder
Patola Jul 4, 2026
e55e993
modifiers: neutralize a released absolute-gyro action in ModeModifier
Patola Jul 5, 2026
7385594
gui: fix gyro Per-Axis mouse-axis labels + add a Clear button
Patola Jul 5, 2026
931efbd
fix(gyro,gui): make gyro->mouse fully work (routing, labels, directio…
Patola Jul 6, 2026
cafbdb2
fix(actions): decode euler gyros in TiltAction (rest false-fires, axi…
Patola Jul 9, 2026
6fb0c99
gyro: intuitive mouse semantics -- Absolute = laser pointer, relative…
Patola Jul 10, 2026
096b144
tests,docs: cover the 'inverted' modifier (3 long-failing meta-tests)
Patola Jul 11, 2026
1c5af82
fix(gyro): align "Mouse (Desktop)" signs with the calibrated rate table
Patola Jul 12, 2026
94e317d
gui: per-controller grip/paddle button lists (gyro enablers, chords, …
Patola Jul 12, 2026
df1e40d
fix(gyro): make the Recenter Gyro special action actually recenter
Patola Jul 12, 2026
9f83574
docs: add a "Using multiple controllers" section to the README
Patola Jun 19, 2026
7d0e872
docs(README): document the controller selector and add a multi-contro…
Patola Jun 21, 2026
c0f1e01
docs(appimage): document AppImage udev steps
C0rn3j Jul 12, 2026
ecbe92a
docs(TODO.md): Add changes
Patola Jun 15, 2026
183c956
gui: name the Bluetooth hidraw DualShock 4 in the controller list
Patola Jul 26, 2026
16bfd9e
sc1: convert the hardware quaternion to EUREL euler angles (one gyro …
Patola Jul 26, 2026
5c4b9df
fix(gyro): re-center absolute gyro at every activation, not at release
Patola Jul 26, 2026
7ad8159
fix(gyro): scale gyro output to the target axis' own range
Patola Aug 2, 2026
a9ae009
fix(modeshift): give analog range conditions hysteresis
Patola Aug 2, 2026
a568429
fix(gyro): apply per-axis sensitivity once, before clamping
Patola Aug 2, 2026
8982352
fix(sc2): enable the IMU quaternion stream, not just rates and accel
Patola Aug 8, 2026
0b1cee5
fix(gui): make "Mouse (Emulate Stick)" actually emulate a stick
Patola Aug 8, 2026
8fdad5f
fix(sc2): send the haptic gain as signed dB, not as an amplitude
Patola Aug 10, 2026
dd3fc22
feat(sc2): real continuous rumble via output report 0x80
Patola Aug 10, 2026
9c27131
docs(todo): scope SC2 actuator audio streaming (haptic reports 0x86-0…
Patola Aug 10, 2026
f141fd0
feat(sc2): use both click presets, and add SCC_HAPTIC_DEBUG
Patola Aug 10, 2026
c3936dc
fix(sc2): spread haptic gain over the whole slider, split rumble motors
Patola Aug 10, 2026
80ea449
fix(rumble): never swallow an effect that carries no magnitudes
Patola Aug 10, 2026
02e5f44
debug(rumble): dump the raw FF effect under SCC_HAPTIC_DEBUG
Patola Aug 10, 2026
37b2648
docs(sc2): record report 0x80 as hardware-verified
Patola Aug 10, 2026
49ec898
feat(sc2): tone, sweep and firmware-script haptic effects
Patola Aug 10, 2026
ae4d53c
feat(gui): choose the haptic effect in the action editor
Patola Aug 10, 2026
8476cbd
fix(gui): stop the action editor crashing on the effect table
Patola Aug 10, 2026
54a4759
fix(gui): keep the haptic effect in the editor's tracked state
Patola Aug 10, 2026
f6cbd4b
feat(gui): name the firmware haptic presets instead of a 0-255 slider
Patola Aug 10, 2026
f377910
fix(gui): load the haptic effect widgets after parsing, not during
Patola Aug 11, 2026
eebf94f
feat(gui): pair each haptic parameter slider with a spin button
Patola Aug 11, 2026
841a687
docs(sc2): record what the haptic effects and presets do on hardware
Patola Aug 11, 2026
5fffc4f
fix(modifiers): do not lose sensitivity when a ball steps aside
C0rn3j Aug 17, 2026
47adc67
fix(gui): let the haptic sliders reach their stated maximum
Patola Aug 11, 2026
56cf4af
docs: Steam co-drives PlayStation pads over Bluetooth; DS4 haptics TODO
Patola Aug 11, 2026
f1f8a83
daemon: set restrictive umask to fix socket and file permissions
sergio-correia Aug 12, 2026
2d73307
hiddrv: fix no-op CLAMP macro and add bounds checking
sergio-correia Aug 12, 2026
9cc759d
IPC: restrict Replace: actions and validate Selected:/Profile: paths
sergio-correia Aug 12, 2026
6594902
daemon: fix os.system() injection and scheduler task ordering
sergio-correia Aug 12, 2026
5d4bf29
fix(gui): keep the haptic Effect chooser when no controller is attached
Patola Aug 14, 2026
dc07f94
daemon: fix ReplacedAction forwarding and operator precedence bug
sergio-correia Aug 14, 2026
fd39951
controller: fix HapticData.__mul__ double-scaling frequency
sergio-correia Aug 14, 2026
81ed4ce
drivers: fix STICK/RSTICK modeshift axes
C0rn3j Aug 17, 2026
f1da72e
hiddrv: fix button_map shift UB at position 32
sergio-correia Aug 14, 2026
e5c95df
daemon: fix Subprocess race between _threaded and kill()
sergio-correia Aug 14, 2026
4c018e4
hiddrv: stop unmapped buttons pressing the right stick
C0rn3j Aug 17, 2026
4839977
fix(config): stop a bad save or parse from wiping every setting
Patola Aug 14, 2026
8665ca1
fix(osd): stop an idle input cancelling navigation another is driving
C0rn3j Sep 13, 2026
5d62a02
WIP osd removal commit fix
C0rn3j Sep 13, 2026
b32c5d5
WIP fix for failing test_haptic_strength_slider_reaches_the_amplitude…
C0rn3j Sep 14, 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
117 changes: 116 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ User-mode driver, mapper, and GTK 4 based GUI for game controllers, including bu

- Allows to setup, configure and use the Steam Controller (2015 & 2026) without ever launching Steam
- Emulates the Xbox 360 controller, mouse, trackball and keyboard
- Connect multiple controllers at the same time
- Connect multiple controllers at the same time, each with its own remembered profile
- Supports profiles, switchable in the GUI, or with a controller button
- Joystick, Touchpad and Gyroscope input
- Haptic Feedback and in-game Rumble support
Expand Down Expand Up @@ -73,6 +73,75 @@ Beware that even when you do use automapper instead of manual assignment, you st
*Note that there is no automatic discovery of evdev nodes for gyroscope/touchpad, so if your controller has one of those, it currently needs SCC to implement a custom driver for it.*</br>
*That does mean that devices like Nintendo controllers do not have a working gyroscope, as I do not own any.*

## 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 Down Expand Up @@ -150,6 +219,23 @@ We also have a [Discord](https://discord.gg/d3G7dDJ2G7) available.
</tr>
</table>

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

## Building the package by yourself

### Dependencies
Expand Down Expand Up @@ -187,6 +273,35 @@ docker build -o build-output --build-arg BASE_CODENAME=noble .
- 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.

## AI notice

If you contribute AI-assisted work, please disclose it, make certain you have reviewed it, and ensure that you have tested the changes.
Expand Down
Loading