fix(input): a stick axis steers once it has been seen at rest (camera spinning on its own) #1677

Merged
NotRexed merged 1 commit from fix/stick-seen-at-rest into main 2026-11-10 13:19:09 +00:00
NotRexed commented 2026-11-10 13:08:49 +00:00 (Migrated from github.com)

Fixes #1673 and #1661: the camera pans or spins by itself, and Link runs in circles, as soon as he can move. Reported with an Xbox 360 pad on CachyOS, and a wired GameSir 2 Lite.

Cause

host/pad_sdl.c takes each stick as the strongest value across all the open pads. Some devices read an axis as held all the time: a mapping that puts a trigger or an unused axis on a stick, or a second, virtual pad. One of those drives the camera or Link even with the player's own pad at rest.

Fix

Each pad lets an axis steer once that axis has been seen at rest since the pad was opened (hos_stick_axis returns 0, inside the dead zone). A real stick rests when connected, so it works right away; an axis stuck at full deflection never does.

A worn stick that rests just past a small dead zone also counts once it's pushed the other way, since it went past its rest. The bits are kept per pad and per axis and reset when a pad is opened.

Tests

New tests/test_stick_rest.py compiles the block from pad_sdl.c and checks:

  • a held phantom axis never steers;
  • the other axes stay free;
  • a normal stick steers either way;
  • a drifting stick steers after crossing over.

test_stick_dead_zone passes. Not tested on a real affected controller; the reporters' hid: lines (#1661) would confirm the phantom device.

🤖 Generated with Claude Code

Fixes #1673 and #1661: the camera pans or spins by itself, and Link runs in circles, as soon as he can move. Reported with an Xbox 360 pad on CachyOS, and a wired GameSir 2 Lite. ## Cause `host/pad_sdl.c` takes each stick as the strongest value across all the open pads. Some devices read an axis as held all the time: a mapping that puts a trigger or an unused axis on a stick, or a second, virtual pad. One of those drives the camera or Link even with the player's own pad at rest. ## Fix Each pad lets an axis steer once that axis has been seen at rest since the pad was opened (`hos_stick_axis` returns 0, inside the dead zone). A real stick rests when connected, so it works right away; an axis stuck at full deflection never does. A worn stick that rests just past a small dead zone also counts once it's pushed the other way, since it went past its rest. The bits are kept per pad and per axis and reset when a pad is opened. ## Tests New `tests/test_stick_rest.py` compiles the block from `pad_sdl.c` and checks: - a held phantom axis never steers; - the other axes stay free; - a normal stick steers either way; - a drifting stick steers after crossing over. `test_stick_dead_zone` passes. Not tested on a real affected controller; the reporters' `hid:` lines (#1661) would confirm the phantom device. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
icedragn43 commented 2026-11-10 20:08:40 +00:00 (Migrated from github.com)

Tried version 2.0.14, so if this is merged into that build then it's still happening to me (issue #1673)

Tried version 2.0.14, so if this is merged into that build then it's still happening to me (issue #1673)
Commenting is not possible because the repository is archived.
No description provided.