fix(input): an input still held after the Insert menu no longer blocks the pads' other buttons #340

Open
jarynclouatre wants to merge 1 commit from jarynclouatre/Longshot:fix/pad-after-menu-each into main
Contributor

Type: fix · Risk: low · Tested on: Linux x86-64 (game-free checks only) · Needs: none

Why

After the Insert menu was open once, the pads reach the game again only when no input of any controller is down. One input that stays down (a worn or mis-mapped trigger past its rest, a Guide button, something resting on a second controller) keeps every button and both sticks of every pad from the game for the rest of the session, while the Insert menu, which reads the raw word, still answers.

read_input in host/nn_hid.c keeps one flag: if (rx_option(1, 0)) pad_after_menu = 1; else if (pad_after_menu && !pad_raw_now) pad_after_menu = 0;, and gives the game the pads only while it is clear.

How to reproduce

Seen on: found reading the code; not seen in the game. Game-free checks on Linux x86-64.
Settings and switches: defaults.
Steps: Keep one controller input down, open the Insert menu and close it, then try another button and the sticks.
Expected: Each input held through the menu waits until released; the other buttons and sticks count after it closes.
Actual: Every button and both sticks of every pad stay out of the game until all controller inputs are up; the Insert menu still answers.

What changed

After the Insert menu closes, each pad input it used waits for its own release. Other buttons, the sticks and the ocarina notes can reach the game while one input stays down.

  • input (host/nn_hid.c, read_input): pad_after_menu is now the set of pad inputs (1 << HOS_PAD_*) that were down while the menu was open, or at the first read after it closed, so the press that closed it waits even when no read saw it while the menu was open. After the close each input leaves the set when it is let go, and the game gets bound_pad_buttons of the others (pads_read keeps the last read's inputs without the Back+Start chord in pad_raw_game for that). While the set is empty the game gets pads_read's word as before. The sticks are withheld while the menu is open and count again as soon as it is closed.
  • ocarina (oc_notes, oc_pad_word): the note layer leaves out the waiting pad inputs instead of playing no notes until all are up.
  • tests: tests/test_pads_after_menu.py (new) compiles production's pads_read, bound_pad_buttons and read_input's pad block with fakes for SDL, XInput and the clock. A trigger held through the menu and the close: the press that closed it and the trigger wait, the sticks count at once, South gives B with the trigger still down, the closing button counts when pressed again, the trigger counts once it was let go; a close press no read saw while the menu was open waits too; a button resting on a second pad waits while the first pad's buttons count. tests/test_ocarina_notes.py case (j) now holds the (L) note's pad input after the menu: no note from it, the keys' notes still play, and the note comes back once it was let go. tests/input_background_test.c declares the new state.

Measurements

Verdict: the new pad test fails on main and passes here; the suite gains one passing check with no new failures.

Hardware: none used (game-free checks on a Linux x86-64 PC, gcc 15.2, Python 3.14.4; no clang++ there)
Scene: none, the game was not run
Method: 2026-11-14; branch fix/pad-after-menu-each. python3 -I -B tests/run_all.py, two runs each, interleaved (main, PR, main, PR, with the other two branches' runs between); both runs of a side gave the same counts. The PR's new or changed checks also run against main's source.
How to reproduce: the commands above in a checkout of each commit

Before: main @ 5ad0f503 After: this PR @ 74998cc5
tests/run_all.py (run 1, run 2) 465 passed, 3 failed, 80 skipped (both) 466 passed, 3 failed, 80 skipped (both)
failing checks test_bake_portability.py, test_pad_layout.py, test_menu_keys.py the same three
tests/test_pads_after_menu.py fails: the stick is withheld while the trigger is down; with that line left out, South gives nothing with the trigger down passes

test_bake_portability.py fails here for a missing Python module (zstandard), on main as well. test_pad_layout.py fails on main since #137 (its fixture lacks host/hold_toggle.h; #331 and #338 fix it). test_menu_keys.py doesn't build with g++ on main since #137 (#338 fixes it).

Flags and settings

None.

Testing

Tested: the game-free suite on a Linux PC, as in Measurements. host/nn_hid.c compiles (-fsyntax-only) with llvm-mingw 20261104's x86_64-w64-mingw32-clang and with Linux gcc 15.2, with the same warnings as main's; no file paths are touched.

Not tested: a controller in the game. The new test runs production's pad read and the pad block of read_input with the pads faked at SDL's boundary.

Must be tested: None.

Risks

What could break: Pad input handling after the Insert menu, including the ocarina's note layer.

Turning it off: Reverting the commit puts the single flag back.

Compatibility: The sticks now count right after the menu closes instead of after every input was let go; host/pad_sdl.c's stick rest guard is unchanged.

Reviewer notes

  • Issue 296 (a 360 pad moves the Insert menu but gives the game nothing) has the same look, but this was not shown to be its cause.
  • #286 moves the same lines of read_input (pads behind another window); one of the two will need a small rebase.

Issues

For #296

Checklist

Everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description) of the status line's type.
  • Why gives the reason plainly and links the issues that fit (the tracker searched).
  • Measurements has a verdict, or one line saying why there is nothing to measure.
  • Testing names what was tested, what wasn't, and what must still be tested, where and how.
  • Rebased on current main.
  • python -I -B tests/run_all.py passes (any failure that also fails on main is named).
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

When it applies

  • Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths.
**Type:** fix · **Risk:** low · **Tested on:** Linux x86-64 (game-free checks only) · **Needs:** none ## Why After the Insert menu was open once, the pads reach the game again only when no input of any controller is down. One input that stays down (a worn or mis-mapped trigger past its rest, a Guide button, something resting on a second controller) keeps every button and both sticks of every pad from the game for the rest of the session, while the Insert menu, which reads the raw word, still answers. `read_input` in `host/nn_hid.c` keeps one flag: `if (rx_option(1, 0)) pad_after_menu = 1; else if (pad_after_menu && !pad_raw_now) pad_after_menu = 0;`, and gives the game the pads only while it is clear. ## How to reproduce **Seen on:** found reading the code; not seen in the game. Game-free checks on Linux x86-64. **Settings and switches:** defaults. **Steps:** Keep one controller input down, open the Insert menu and close it, then try another button and the sticks. **Expected:** Each input held through the menu waits until released; the other buttons and sticks count after it closes. **Actual:** Every button and both sticks of every pad stay out of the game until all controller inputs are up; the Insert menu still answers. ## What changed After the Insert menu closes, each pad input it used waits for its own release. Other buttons, the sticks and the ocarina notes can reach the game while one input stays down. - input (`host/nn_hid.c`, `read_input`): `pad_after_menu` is now the set of pad inputs (`1 << HOS_PAD_*`) that were down while the menu was open, or at the first read after it closed, so the press that closed it waits even when no read saw it while the menu was open. After the close each input leaves the set when it is let go, and the game gets `bound_pad_buttons` of the others (`pads_read` keeps the last read's inputs without the Back+Start chord in `pad_raw_game` for that). While the set is empty the game gets `pads_read`'s word as before. The sticks are withheld while the menu is open and count again as soon as it is closed. - ocarina (`oc_notes`, `oc_pad_word`): the note layer leaves out the waiting pad inputs instead of playing no notes until all are up. - tests: `tests/test_pads_after_menu.py` (new) compiles production's `pads_read`, `bound_pad_buttons` and `read_input`'s pad block with fakes for SDL, XInput and the clock. A trigger held through the menu and the close: the press that closed it and the trigger wait, the sticks count at once, South gives B with the trigger still down, the closing button counts when pressed again, the trigger counts once it was let go; a close press no read saw while the menu was open waits too; a button resting on a second pad waits while the first pad's buttons count. `tests/test_ocarina_notes.py` case (j) now holds the (L) note's pad input after the menu: no note from it, the keys' notes still play, and the note comes back once it was let go. `tests/input_background_test.c` declares the new state. ## Measurements **Verdict:** the new pad test fails on main and passes here; the suite gains one passing check with no new failures. Hardware: none used (game-free checks on a Linux x86-64 PC, gcc 15.2, Python 3.14.4; no clang++ there) Scene: none, the game was not run Method: 2026-11-14; branch `fix/pad-after-menu-each`. `python3 -I -B tests/run_all.py`, two runs each, interleaved (main, PR, main, PR, with the other two branches' runs between); both runs of a side gave the same counts. The PR's new or changed checks also run against main's source. How to reproduce: the commands above in a checkout of each commit | | Before: main @ 5ad0f503 | After: this PR @ 74998cc5 | |---|---|---| | `tests/run_all.py` (run 1, run 2) | 465 passed, 3 failed, 80 skipped (both) | 466 passed, 3 failed, 80 skipped (both) | | failing checks | `test_bake_portability.py`, `test_pad_layout.py`, `test_menu_keys.py` | the same three | | `tests/test_pads_after_menu.py` | fails: the stick is withheld while the trigger is down; with that line left out, South gives nothing with the trigger down | passes | `test_bake_portability.py` fails here for a missing Python module (zstandard), on main as well. `test_pad_layout.py` fails on main since #137 (its fixture lacks `host/hold_toggle.h`; #331 and #338 fix it). `test_menu_keys.py` doesn't build with g++ on main since #137 (#338 fixes it). ### Flags and settings None. ## Testing **Tested:** the game-free suite on a Linux PC, as in Measurements. `host/nn_hid.c` compiles (`-fsyntax-only`) with llvm-mingw 20261104's x86_64-w64-mingw32-clang and with Linux gcc 15.2, with the same warnings as main's; no file paths are touched. **Not tested:** a controller in the game. The new test runs production's pad read and the pad block of `read_input` with the pads faked at SDL's boundary. **Must be tested:** None. ## Risks **What could break:** Pad input handling after the Insert menu, including the ocarina's note layer. **Turning it off:** Reverting the commit puts the single flag back. **Compatibility:** The sticks now count right after the menu closes instead of after every input was let go; `host/pad_sdl.c`'s stick rest guard is unchanged. ## Reviewer notes - Issue 296 (a 360 pad moves the Insert menu but gives the game nothing) has the same look, but this was not shown to be its cause. - #286 moves the same lines of `read_input` (pads behind another window); one of the two will need a small rebase. ## Issues For #296 ## Checklist ### Everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`) of the status line's type. - [x] Why gives the reason plainly and links the issues that fit (the tracker searched). - [x] Measurements has a verdict, or one line saying why there is nothing to measure. - [x] Testing names what was tested, what wasn't, and what must still be tested, where and how. - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` passes (any failure that also fails on `main` is named). - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### When it applies - [x] Numbers from the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths.
fix(input): an input still held after the Insert menu no longer blocks the pads' other buttons
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 6s
beanstalk/approval Test farm not requested
74998cc555
After the Insert menu closed, read_input gave the game no pad input until
every input of every pad was up (one pad_after_menu flag). One input that
stayed down, a worn trigger past its rest, a Guide button, something resting
on a second controller, kept all buttons and both sticks of all pads from the
game for the rest of the session, while the menu, which reads the raw word,
still answered.

pad_after_menu is now the set of inputs that were down while the menu was
open or at the first read after it closed; each leaves the set when it is let
go, and the game gets the bound buttons of the rest (pads_read keeps the
chordless raw word for that). The press that closed the menu still waits
until released. The sticks count again as soon as the menu is closed. The
ocarina's note layer leaves out the waiting inputs instead of waiting for all.
jarynclouatre changed title from WIP: fix(input): an input still held after the Insert menu no longer blocks the pads' other buttons to fix(input): an input still held after the Insert menu no longer blocks the pads' other buttons 2026-11-14 02:15:21 +00:00
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
Website / Website on Cloudflare (pull_request_target) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 6s
beanstalk/approval Test farm not requested
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
Some workflows are waiting to be reviewed.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'fix/pad-after-menu-each:jarynclouatre-fix/pad-after-menu-each'
git switch 'jarynclouatre-fix/pad-after-menu-each'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!340
No description provided.