fix(input): a pad's gyro stops with its buttons when the game is behind another window #2542

Open
dylmart wants to merge 1 commit from dylmart/fix/motion-in-background into main
dylmart commented 2026-11-11 22:44:15 +00:00 (Migrated from github.com)

The buttons only count while the game's window is in front (or with the Insert menu's "Controller in background" on, or HOS_INPUT_BACKGROUND=1), but GetSixAxisSensorStates read the pad's motion either way. So with the game behind another window, a gyro kept turning the camera while the buttons did nothing.

  • host/nn_hid.c: motion_counts() applies the buttons' rule to motion: the game's window in front, or pads_in_background(). When it's false, GetSixAxisSensorStates hands out the pad at rest, the same way it does with no motion pad. The switch between live and at rest uses the existing sample-number handling, so no reading repeats a number.
  • tests/test_motion_background.py (new, game-free): cuts pads_in_background and motion_counts out of nn_hid.c and checks six cases (in front; behind with the row off or on; HOS_INPUT_BACKGROUND 0 or 1 overriding the row). It also checks that GetSixAxisSensorStates asks motion_counts before it reads the pad. That check fails without this change.

Testing

Found while testing #2495 on Linux (CachyOS, Hyprland) with a 2026 Steam Controller: with the game behind Firefox, the buttons stopped and the gyro kept moving the camera. The game's log showed hid: game window not in front for that whole stretch. It's the same without #2495 for any pad SDL reads a gyro from; #2495 only makes it reachable for a Steam Controller under Steam.

In the game (nightly v2.1.0-rc.3-112 plus #2495 and this change, Linux, 2026 Steam Controller started from Steam): with the game behind Firefox, moving the controller doesn't move the camera, and the gyro works again as soon as the game's window is back in front, without a click into it. The log shows the two switches (hid: game window not in front / in front). The "Controller in background" row wasn't tried in the game; the test covers it.

tests/test_motion_background.py, test_input_background.py, test_motion.py and test_gyro_rearm.py pass. host/nn_hid.c has no new compiler warnings.

The buttons only count while the game's window is in front (or with the Insert menu's "Controller in background" on, or `HOS_INPUT_BACKGROUND=1`), but `GetSixAxisSensorStates` read the pad's motion either way. So with the game behind another window, a gyro kept turning the camera while the buttons did nothing. - `host/nn_hid.c`: `motion_counts()` applies the buttons' rule to motion: the game's window in front, or `pads_in_background()`. When it's false, `GetSixAxisSensorStates` hands out the pad at rest, the same way it does with no motion pad. The switch between live and at rest uses the existing sample-number handling, so no reading repeats a number. - `tests/test_motion_background.py` (new, game-free): cuts `pads_in_background` and `motion_counts` out of `nn_hid.c` and checks six cases (in front; behind with the row off or on; `HOS_INPUT_BACKGROUND` 0 or 1 overriding the row). It also checks that `GetSixAxisSensorStates` asks `motion_counts` before it reads the pad. That check fails without this change. ## Testing Found while testing #2495 on Linux (CachyOS, Hyprland) with a 2026 Steam Controller: with the game behind Firefox, the buttons stopped and the gyro kept moving the camera. The game's log showed `hid: game window not in front` for that whole stretch. It's the same without #2495 for any pad SDL reads a gyro from; #2495 only makes it reachable for a Steam Controller under Steam. In the game (nightly v2.1.0-rc.3-112 plus #2495 and this change, Linux, 2026 Steam Controller started from Steam): with the game behind Firefox, moving the controller doesn't move the camera, and the gyro works again as soon as the game's window is back in front, without a click into it. The log shows the two switches (`hid: game window not in front` / `in front`). The "Controller in background" row wasn't tried in the game; the test covers it. `tests/test_motion_background.py`, `test_input_background.py`, `test_motion.py` and `test_gyro_rearm.py` pass. `host/nn_hid.c` has no new compiler warnings.
Owner

@Joey-Magnus approved on GitHub · 2026-11-12 14:33 UTC · original

I merged this into current main and ran tests/test_motion_background.py, test_input_background.py, test_motion.py and test_gyro_rearm.py: all pass. The change is the right size. motion_counts() reuses pads_in_background(), so the gyro follows the same rule as the buttons (window in front, the "Controller in background" row, HOS_INPUT_BACKGROUND=0/1 overriding the row). Going to rest reuses the existing sample-number jump, so the game never sees a repeated number.

The two red Windows shards fail in tests/test_pcache_header_read.py and tests/test_psychov35.py. Neither touches host/nn_hid.c, and both pass on main's latest runs, so a re-run should clear them.

One small point, not blocking: host/nn_hid.c:1174 reads HOS_INPUT_BACKGROUND a second time into its own statics, the same way the button path does at :987. One shared helper would keep the two from drifting, but this matches what's already there.

> [@Joey-Magnus](https://github.com/Joey-Magnus) approved on GitHub · 2026-11-12 14:33 UTC · [original](https://github.com/NotRexed/Hookshot/pull/2542#pullrequestreview-5876214855) I merged this into current main and ran tests/test_motion_background.py, test_input_background.py, test_motion.py and test_gyro_rearm.py: all pass. The change is the right size. `motion_counts()` reuses `pads_in_background()`, so the gyro follows the same rule as the buttons (window in front, the "Controller in background" row, HOS_INPUT_BACKGROUND=0/1 overriding the row). Going to rest reuses the existing sample-number jump, so the game never sees a repeated number. The two red Windows shards fail in tests/test_pcache_header_read.py and tests/test_psychov35.py. Neither touches host/nn_hid.c, and both pass on main's latest runs, so a re-run should clear them. One small point, not blocking: host/nn_hid.c:1174 reads HOS_INPUT_BACKGROUND a second time into its own statics, the same way the button path does at :987. One shared helper would keep the two from drifting, but this matches what's already there. <!-- github-sync:r:5876214855 -->
Commenting is not possible because the repository is archived.
No description provided.