WIP: feat(input): add a held or toggled Walk key with adjustable speed #66

Draft
mooki wants to merge 7 commits from mooki/Longshot:walk-key into main
First-time contributor

Why

Keyboard players should be able to walk instead of always running. A rebindable Walk key gives the movement keys a partial stick tilt, either while held or from one press to the next.

This remains work in progress: the feature works in the Longshot runs below, but the shared PC varied too much to establish its cost while unused. The default-key preference is also still a maintainer decision; this move keeps Caps Lock.

What changed

  • Input: walk_held(), walk_percent() and move_keys_stick() in host/nn_hid.c scale only the movement keys. Hold is the default; Toggle changes state on a fresh press, not a held key returning from a menu/focus change. Running, controllers, camera keys and mouse input keep their own tilt.
  • Bindings: append HOS_KEY_WALK to the key enum/name tables; display Walk after Camera right and before the ocarina notes. binds_load() preserves older mappings: if another control already owns Caps Lock, Walk starts unbound and logs why. No saved-options version change.
  • Menu: Walk mode and Walk speed in gpu/vk/vk_menu.cpp/.h, with the existing binding/rebinding UI and live renderer callbacks in vk_replay.cpp. The default remains 45%, range 15–90% in steps of five.
  • IDs: retain the later published allocation 49/50, not the approval's historical 52/53. Current main reserves 49/50 for Walk, uses 51 for FOV, 52 for Skip opening and 53 for the live frame cap. The host and renderer agree; the compiled guard finds 45 unique IDs and rejects all five collision variants. There is no host/hos_options.c here: host/rx_backend.c forwards option reads, and host/nn_vi.c reads the cap. No host/renderer table entry changes, so API version 21 stays.
  • Tests/docs: retain every restored background-input assertion and the complete Walk behavior/wiring fixture. The only new fixture adaptation for this move is reading main's renamed README.md instead of readme.md. Preserve all historical result rows and add the five new Longshot attempt/run rows.

Flags and settings

No new environment variable, build flag or command-line flag is added. Internal identifiers below are callback/key IDs, not environment switches.

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Walk mode (HOS_OPT_WALK_MODE, 49) New menu option: Hold walks while the key is down; Toggle alternates walking/running Hold On by default: predictable held input; walking itself is inactive until requested Keyboard movement Controller, mouse and camera-key tilt Physical keyboard, Windows gameplay (should help on: Other supported PCs)
walk_mode New ini key: Persists 0 Hold or 1 Toggle, independently of the callback ID 0 On by default: keep the chosen mode Players saving settings Does not change other input sources Windows file persistence in the game (should help on: Other supported PCs)
Walk speed (HOS_OPT_WALK_SPEED, 50) New menu option: Movement-key stick share while walking; 15–90%, steps of five 45% On by default: preserved measured walking default; no scaling while inactive Keyboard walking, diagonals included Running, controllers, mouse and camera keys Physical input, slopes, water, first-person aiming (should help on: Other supported PCs)
walk_speed New ini key: Persists the walking stick percentage 45 On by default: keep the player's chosen share Saved keyboard settings Does not make every percentage a walking pose; higher shares jog/run Windows gameplay persistence (should help on: Other supported PCs)
Walk (HOS_KEY_WALK) New keyboard/mouse-only control: Existing Controls-page rebinding, second-key and clear/reset behavior Caps Lock, no second key Maintainer choice pending: retained from the original PR; rebindable Keyboard players Gamepad bindings; OS Caps Lock still changes capitals Real keyboard/mouse, layout/remapping tools (should help on: Other supported keyboard layouts)
key_walk New ini key: Saves the two virtual-key bindings by name, not option number 20,0; unbound if an old mapping already uses Caps Lock On by default: preserve old mappings rather than steal their key Existing and new keyboard profiles Does not remap an old conflicting binding automatically Physical input and Windows gameplay (should help on: Other supported PCs)

Measurements

Branch state: on main d725b3631982ed0035ea3ac9cbe1677e9fad260c; head 629766eb206386d0777aa262b212d7e07f530d23; whole game-free suite on this head: 511 passed, 1 failed, 20 skipped (main d725b3631982ed0035ea3ac9cbe1677e9fad260c: 510 passed, 1 failed, 20 skipped); the commits are unchanged by rebases apart from the results table.

The only failure on both heads is tests/test_updater_asset_digest.py: local .NET NU1100, unable to resolve the missing Microsoft.AspNetCore.App.Ref (= 10.0.13) reference pack for net10.0.

main: d4a69456 (2026-11-12), with the same local test probe as this PR
this PR: walk-key @ 3fc3c891, with that local test probe
Hardware: RTX 4090 24 GB, NVIDIA 615.78.08; Core i9-13900K, 96 GB; Arch Linux, kernel 7.2.15-1-omarchy
Scene: same copied Kokiri Forest save, daytime; 1920×1080, Custom preset, game's own upscaler at 100%, frame generation off, cap 60, shader precompile off; windowless
Method: main → this PR → main → this PR, four completed runs of 151.0 / 206.4 / 116.0 / 134.4 seconds. Wait for ten fresh controllable scene samples, warm up another 20 seconds, observe 40 seconds with Walk unused, then exercise the keys. Each movement median is nine game-set-speed readings after the first reading of the hold. FPS medians use complete 120-present log blocks inside the unused window. Ordinary shared runs, not a controlled performance measurement.
How to reproduce: on a Kokiri Forest save, set the settings above; hold W or S with Caps Lock, then without it. Switch Walk mode to Toggle, tap Caps Lock, move, tap it again, and move again. Inspect Walk mode/speed and the Walk binding on Controls. Run python -I -B tests/test_walk_key.py and python -I -B tests/test_option_ids.py for the game-free checks. The automated runs used a local test probe because the current bridge has no keyboard input; a person pressing the key was not part of this check.

Main d725b363 differs from measured d4a69456 only by scripts, docs and tests, not game code; every carried patch is unchanged and the five product files are byte-identical to the measured head, so the game observations still hold.

The identical, uncommitted probe on both builds fills the Linux key table that the normal keyboard path reads and observes the game's controller-speed setter/position. It does not replace Walk with an analog controller command. The bridge supplies title input, settings and captures. A test-only menu-key hook and headless list-scroll step make the rows visible. Both probes were removed from the source worktrees after building; no probe or game-derived data is in the PR.

main @ d4a69456 this PR @ 3fc3c891
W + Caps Lock, forward speed per run 4.500 / 4.500 m/s 1.467 / 1.467 m/s
Median forward held-Walk speed 4.500 m/s 1.467 m/s
W without Caps Lock, both runs 4.500 m/s 4.500 m/s
Toggle walking, forward/back per run No Walk mode 1.472/1.469 and 1.469/1.469 m/s
Toggle off, both directions and runs No Walk mode 4.500 m/s
Left-stick magnitude with a held Walk key 32767 14745 (45%)
Walk-unused median logged FPS per run 27.45 / 60.00 29.00 / 56.25
Median of those two run medians 43.725 42.625
Same-build spread between run medians 32.55 FPS 27.25 FPS

Off-cost is inconclusive. Main alone changed from 27.45 to 60.00 FPS; the branch from 29.00 to 56.25. The 1.10-FPS gap between their arithmetic medians is much smaller than either build's repeat spread, but that large spread prevents a useful “no visible cost” conclusion. This is not evidence that Walk is faster, slower or free. A controlled comparison remains necessary before marking this feature ready.

Run order Build Unused-window blocks One-minute load during that window Held W + Caps Lock Game exit
1 main d4a69456 + probe 8 148.05 → 99.73 4.500 m/s 0
2 this PR 3fc3c891 + probe 9 120.96 → 78.16 1.467 m/s 0
3 main d4a69456 + probe 18 15.92 → 13.17 4.500 m/s 0
4 this PR 3fc3c891 + probe 18 30.12 → 21.50 1.467 m/s 0

Observed movement output, extracted from the retained samples (not a percentage multiplied into an assumed game speed):

run=1 arm=base held-walk-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s
run=2 arm=branch held-walk-forward stick=[0, 14745] samples=9 median_speed=1.467 m/s
run=2 arm=branch held-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s
run=2 arm=branch toggle-walk-forward stick=[0, 14745] samples=9 median_speed=1.472 m/s
run=2 arm=branch toggle-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s
run=3 arm=base held-walk-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s
run=4 arm=branch held-walk-forward stick=[0, 14745] samples=9 median_speed=1.467 m/s
run=4 arm=branch held-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s
run=4 arm=branch toggle-walk-forward stick=[0, 14745] samples=9 median_speed=1.469 m/s
run=4 arm=branch toggle-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s
[hos BaseProcExecutor4] hid: walking: the movement keys tilt the left stick to 45% (0, 14745)
[hos BaseProcExecutor4] hid: walking on (Walk mode Toggle)
[hos BaseProcExecutor0] hid: walking off (Walk mode Toggle)

The central log lines from each sorted unused-window population produce its median; all blocks are retained, not just these central lines:

run 1, main: central 27.3 and 27.6 of 8 blocks
[hos Presentation Thread] vk: 3840 presents, 27.3 fps; a frame: 4003 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 840 pipelines (155504 ms), 460 programs (0 failed), 1350 textures (3733 MB)
[hos Presentation Thread] vk: 3480 presents, 27.6 fps; a frame: 4000 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 840 pipelines (155504 ms), 460 programs (0 failed), 1367 textures (3828 MB)
run 2, this PR: central 29.0 of 9 blocks
[hos Presentation Thread] vk: 3840 presents, 29.0 fps; a frame: 4005 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 843 pipelines (201666 ms), 604 programs (0 failed), 1443 textures (3855 MB)
run 3, main: central 60.0 and 60.0 of 18 blocks
[hos Presentation Thread] vk: 3720 presents, 60.0 fps; a frame: 4085 draws (0 skipped), 124 dispatches, 181 passes, 138 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (216 ms), 0 programs (0 failed), 1526 textures (3893 MB)
[hos Presentation Thread] vk: 4080 presents, 60.0 fps; a frame: 4084 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (216 ms), 0 programs (0 failed), 1525 textures (3898 MB)
run 4, this PR: central 56.0 and 56.5 of 18 blocks
[hos Presentation Thread] vk: 5160 presents, 56.0 fps; a frame: 4081 draws (0 skipped), 125 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (277 ms), 0 programs (0 failed), 1542 textures (4062 MB)
[hos Presentation Thread] vk: 4680 presents, 56.5 fps; a frame: 4084 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (277 ms), 0 programs (0 failed), 1507 textures (3846 MB)

All four completed runs had zero fatal/crash/device-loss/core-escape/kernel-fault counts and complete journal coverage. A separate 59.8-second cold attempt is rejected, not counted as a fifth measurement: the driver sent a blocking A during loading, timed out waiting for a controller read and requested quit. Game exit was 0 with no fault lines; it reached no stable movement or unused window. The corrected driver required an advancing menu before title input. No binary changed to fix that test-driver mistake.

The whole suite used a fresh HOME and repository-default compiler selection after the last documentation commit. Separate check output:

PASS: 45 option IDs are unique; explicit, implicit and legacy collisions rejected
PASS: 5 captured translation units, 0 failures, 0 unjudged drivers/files; Windows execution NOT TESTED

The preliminary suite on 3fc3c891 was 509/1/20. The earlier shared main suite at measured d4a69456 was 507/2/20: the same .NET failure plus a timing-dependent AppImage retry fixture failure under heavy load, whose isolated follow-up passed all nine cases. No package was installed and no failure is called a pass. The whole suite includes the new description/forge tests from d725b3631.

The shared main suite was run once for all moved pull requests of this day.

The unchanged Walk test against measured main rejects the absent helper and option allocation (one error and one failure before behavioral compilation); that is an absence/wiring negative, not a baseline game-speed fixture. The actual game comparison above supplies the behavioral before result. Five changed input fixture units passed Windows-target syntax; the option-ID driver separately used the real Windows-target compiler exits for every expected collision. Two unused-variable warnings in the ocarina binding fixture remain visible. No Windows execution is implied.

Historical GitHub checks were green on Windows and Ubuntu at 45f3e06c2ed59ee56cca05ee13bc6b24d131d990; the published head 2202ab57d77cadc220a2bb3c26b0413f0c21f3e7 carried the same five patches. Relative to that published topic, the forge's product changes are rename-only; the new adaptation is the fixture's README filename, plus new measured-run documentation. This is historical CI, not a new Forgejo Windows run.

Testing

Tested: On this PC: Arch Linux, RTX 4090, NVIDIA 615.78.08, Core i9-13900K. Game-free checks covered the Walk behavior/wiring, option-ID collisions, changed input fixtures and the whole suite reported above; five input units also passed Windows-target syntax, not native Windows execution. The measured Longshot builds d4a69456 / 3fc3c891 used the same copied daytime Kokiri Forest save and identical local key probes: hold W/S with and without Caps Lock, switch to Toggle, tap to walk, tap again to run, and inspect Walk mode/speed and the Controls binding. Those game observations are carried to the current head, not a new game run or physical-keyboard test.

Tested but not measured: the menu's appearance and binding-page navigation were inspected without a menu-specific overhead measurement. The shared unused-key FPS observations are inconclusive, not a performance verdict. The 15–90% range and 45% default keep their earlier Hookshot threshold evidence; the full range was not remeasured in Longshot.

Not tested: A physical keyboard or mouse on this PC, AMD/Intel gameplay, Caps Lock's OS state, first-person aiming while walking, slopes/water or places beyond Kokiri Forest; a controlled on/off overhead comparison. The runs used a key probe on the RTX 4090 in one area, not physical input or those other devices/scenes, and shared load prevents an overhead conclusion. No new test request has been opened for those platforms.

Needs other testers:

  • Windows with a physical keyboard: build the host and run the changed input fixtures; try Hold/Toggle and save/reload a rebound Walk key, expecting passing fixtures and the chosen binding/mode to work (request to open)
  • Non-US keyboard layout or remapped Caps Lock: try Walk and menu/focus changes, expecting the rebound key to work and Toggle to change only on a fresh press (request to open)

Screenshots

main @ d4a69456: S + Caps Lock still runs; this PR @ 3fc3c891: the same key combination walks. Same copied scene, with the identical local key probe; not physical-keyboard input.

main @ d4a69456 has no Walk rows; this PR @ 3fc3c891 has Walk mode and speed. Toggle is selected for the picture; Hold remains the default.

main @ d4a69456 proceeds from Camera right to the ocarina rows; this PR @ 3fc3c891 adds Walk bound to Caps Lock, with no gamepad binding.

Historical pictures, inspected and kept separately rather than relabelled as Longshot:

Earlier Hookshot evidence, 2026-11-11, first-version key probe: walking at about 1.47 m/s versus running at 4.50 m/s. Not a new Longshot measurement.

Hookshot @ 7e536c338 plus its local probe, 2026-11-12: Toggle selected and its help text.

Same historical Hookshot build: the 45% row and its unchanged input-source scope.

Same historical Hookshot build: the actual Walk/Caps Lock row, cropped without attributing another row's help to it.

Risk and rollback

Caps Lock still changes the OS's capitals state; bind another key if unwanted. First-person actions that read the movement stick could also become slower while Walk is active; camera-key and mouse tilt are not scaled, but first-person aiming was not tried. Old conflicting bindings must remain owned by their original controls, and future option additions must preserve the unique-ID guard.

Release Walk in Hold mode, toggle it off, or clear its binding to stop walking. Reverting the feature removes the new input path entirely; there is no new global off switch or saved-options migration to undo. The lack of a controlled unused-cost result is why this PR stays WIP.

Reviewer notes

Start with walk_held()/move_keys_stick(), the old-binding conflict rule, and the host/renderer's 49/50 callbacks. tests/test_input_background.py only adds to main's checks; the four assertions Joey-Magnus requested remain intact. tests/test_option_ids.py retains all five negative cases.

Joey-Magnus approved c3c7d19e after the earlier review fixes, including then-free 52/53, named key_walk persistence, no API-table bump and the safe conflicting-key upgrade. The later published rebase moved to main's reserved 49/50; the current cap owns 53, so the historical numbers must not be restored. That approval predates this forge head. Caps Lock versus another default key remains the maintainers' choice; no default was changed during this move.

Issues

Original request: https://github.com/NotRexed/Hookshot/issues/2344 (closed). Original pull request: https://github.com/NotRexed/Hookshot/issues/2345.

No matching issue exists in the forge's all-issues list checked for this move. No old GitHub number is used as a forge closing reference.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. — Correctness is shown; the feature's unused-cost criterion remains inconclusive under shared load.
  • 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.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • Screenshots for a change that shows on screen.
  • A row in docs/tested-configurations.md for each measured run.
  • A game-free test added for the fix, failing on main and passing here. — Feature test: main lacks the helper/allocation; runtime comparison supplies the behavioral before result.
  • 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. — Linux Longshot built; current Windows fixture syntax only, historical Windows/Ubuntu checks labelled above.
  • Docs updated.

Moved from NotRexed/Hookshot#2345.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 [email protected]

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]

## Why Keyboard players should be able to walk instead of always running. A rebindable Walk key gives the movement keys a partial stick tilt, either while held or from one press to the next. This remains **work in progress**: the feature works in the Longshot runs below, but the shared PC varied too much to establish its cost while unused. The default-key preference is also still a maintainer decision; this move keeps Caps Lock. ## What changed - Input: `walk_held()`, `walk_percent()` and `move_keys_stick()` in `host/nn_hid.c` scale only the movement keys. Hold is the default; Toggle changes state on a fresh press, not a held key returning from a menu/focus change. Running, controllers, camera keys and mouse input keep their own tilt. - Bindings: append `HOS_KEY_WALK` to the key enum/name tables; display Walk after Camera right and before the ocarina notes. `binds_load()` preserves older mappings: if another control already owns Caps Lock, Walk starts unbound and logs why. No saved-options version change. - Menu: Walk mode and Walk speed in `gpu/vk/vk_menu.cpp`/`.h`, with the existing binding/rebinding UI and live renderer callbacks in `vk_replay.cpp`. The default remains 45%, range 15–90% in steps of five. - IDs: retain the later published allocation **49/50**, not the approval's historical 52/53. Current main reserves 49/50 for Walk, uses 51 for FOV, 52 for Skip opening and **53 for the live frame cap**. The host and renderer agree; the compiled guard finds 45 unique IDs and rejects all five collision variants. There is no `host/hos_options.c` here: `host/rx_backend.c` forwards option reads, and `host/nn_vi.c` reads the cap. No host/renderer table entry changes, so API version 21 stays. - Tests/docs: retain every restored background-input assertion and the complete Walk behavior/wiring fixture. The only new fixture adaptation for this move is reading main's renamed `README.md` instead of `readme.md`. Preserve all historical result rows and add the five new Longshot attempt/run rows. ## Flags and settings No new environment variable, build flag or command-line flag is added. Internal identifiers below are callback/key IDs, not environment switches. | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Walk mode (`HOS_OPT_WALK_MODE`, 49) | New menu option: Hold walks while the key is down; Toggle alternates walking/running | Hold | On by default: predictable held input; walking itself is inactive until requested | Keyboard movement | Controller, mouse and camera-key tilt | Physical keyboard, Windows gameplay (should help on: Other supported PCs) | | `walk_mode` | New ini key: Persists 0 Hold or 1 Toggle, independently of the callback ID | 0 | On by default: keep the chosen mode | Players saving settings | Does not change other input sources | Windows file persistence in the game (should help on: Other supported PCs) | | Walk speed (`HOS_OPT_WALK_SPEED`, 50) | New menu option: Movement-key stick share while walking; 15–90%, steps of five | 45% | On by default: preserved measured walking default; no scaling while inactive | Keyboard walking, diagonals included | Running, controllers, mouse and camera keys | Physical input, slopes, water, first-person aiming (should help on: Other supported PCs) | | `walk_speed` | New ini key: Persists the walking stick percentage | 45 | On by default: keep the player's chosen share | Saved keyboard settings | Does not make every percentage a walking pose; higher shares jog/run | Windows gameplay persistence (should help on: Other supported PCs) | | Walk (`HOS_KEY_WALK`) | New keyboard/mouse-only control: Existing Controls-page rebinding, second-key and clear/reset behavior | Caps Lock, no second key | Maintainer choice pending: retained from the original PR; rebindable | Keyboard players | Gamepad bindings; OS Caps Lock still changes capitals | Real keyboard/mouse, layout/remapping tools (should help on: Other supported keyboard layouts) | | `key_walk` | New ini key: Saves the two virtual-key bindings by name, not option number | `20,0`; unbound if an old mapping already uses Caps Lock | On by default: preserve old mappings rather than steal their key | Existing and new keyboard profiles | Does not remap an old conflicting binding automatically | Physical input and Windows gameplay (should help on: Other supported PCs) | ## Measurements <!-- branch-state --> Branch state: on main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`; head `629766eb206386d0777aa262b212d7e07f530d23`; whole game-free suite on this head: `511 passed, 1 failed, 20 skipped` (main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`: `510 passed, 1 failed, 20 skipped`); the commits are unchanged by rebases apart from the results table. <!-- /branch-state --> The only failure on both heads is `tests/test_updater_asset_digest.py`: local .NET `NU1100`, unable to resolve the missing `Microsoft.AspNetCore.App.Ref (= 10.0.13)` reference pack for net10.0. main: d4a69456 (2026-11-12), with the same local test probe as this PR this PR: walk-key @ 3fc3c891, with that local test probe Hardware: RTX 4090 24 GB, NVIDIA 615.78.08; Core i9-13900K, 96 GB; Arch Linux, kernel 7.2.15-1-omarchy Scene: same copied Kokiri Forest save, daytime; 1920×1080, Custom preset, game's own upscaler at 100%, frame generation off, cap 60, shader precompile off; windowless Method: main → this PR → main → this PR, four completed runs of 151.0 / 206.4 / 116.0 / 134.4 seconds. Wait for ten fresh controllable scene samples, warm up another 20 seconds, observe 40 seconds with Walk unused, then exercise the keys. Each movement median is nine game-set-speed readings after the first reading of the hold. FPS medians use complete 120-present log blocks inside the unused window. Ordinary shared runs, not a controlled performance measurement. How to reproduce: on a Kokiri Forest save, set the settings above; hold W or S with Caps Lock, then without it. Switch Walk mode to Toggle, tap Caps Lock, move, tap it again, and move again. Inspect Walk mode/speed and the Walk binding on Controls. Run `python -I -B tests/test_walk_key.py` and `python -I -B tests/test_option_ids.py` for the game-free checks. The automated runs used a local test probe because the current bridge has no keyboard input; **a person pressing the key was not part of this check**. Main `d725b363` differs from measured `d4a69456` only by scripts, docs and tests, not game code; every carried patch is unchanged and the five product files are byte-identical to the measured head, so the game observations still hold. The identical, uncommitted probe on both builds fills the Linux key table that the normal keyboard path reads and observes the game's controller-speed setter/position. It does not replace Walk with an analog controller command. The bridge supplies title input, settings and captures. A test-only menu-key hook and headless list-scroll step make the rows visible. Both probes were removed from the source worktrees after building; no probe or game-derived data is in the PR. | | main @ d4a69456 | this PR @ 3fc3c891 | |---|---|---| | W + Caps Lock, forward speed per run | 4.500 / 4.500 m/s | 1.467 / 1.467 m/s | | Median forward held-Walk speed | 4.500 m/s | 1.467 m/s | | W without Caps Lock, both runs | 4.500 m/s | 4.500 m/s | | Toggle walking, forward/back per run | No Walk mode | 1.472/1.469 and 1.469/1.469 m/s | | Toggle off, both directions and runs | No Walk mode | 4.500 m/s | | Left-stick magnitude with a held Walk key | 32767 | 14745 (45%) | | Walk-unused median logged FPS per run | 27.45 / 60.00 | 29.00 / 56.25 | | Median of those two run medians | 43.725 | 42.625 | | Same-build spread between run medians | 32.55 FPS | 27.25 FPS | **Off-cost is inconclusive.** Main alone changed from 27.45 to 60.00 FPS; the branch from 29.00 to 56.25. The 1.10-FPS gap between their arithmetic medians is much smaller than either build's repeat spread, but that large spread prevents a useful “no visible cost” conclusion. This is not evidence that Walk is faster, slower or free. A controlled comparison remains necessary before marking this feature ready. | Run order | Build | Unused-window blocks | One-minute load during that window | Held W + Caps Lock | Game exit | |---|---|---:|---|---:|---:| | 1 | main `d4a69456` + probe | 8 | 148.05 → 99.73 | 4.500 m/s | 0 | | 2 | this PR `3fc3c891` + probe | 9 | 120.96 → 78.16 | 1.467 m/s | 0 | | 3 | main `d4a69456` + probe | 18 | 15.92 → 13.17 | 4.500 m/s | 0 | | 4 | this PR `3fc3c891` + probe | 18 | 30.12 → 21.50 | 1.467 m/s | 0 | Observed movement output, extracted from the retained samples (not a percentage multiplied into an assumed game speed): ```text run=1 arm=base held-walk-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s run=2 arm=branch held-walk-forward stick=[0, 14745] samples=9 median_speed=1.467 m/s run=2 arm=branch held-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s run=2 arm=branch toggle-walk-forward stick=[0, 14745] samples=9 median_speed=1.472 m/s run=2 arm=branch toggle-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s run=3 arm=base held-walk-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s run=4 arm=branch held-walk-forward stick=[0, 14745] samples=9 median_speed=1.467 m/s run=4 arm=branch held-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s run=4 arm=branch toggle-walk-forward stick=[0, 14745] samples=9 median_speed=1.469 m/s run=4 arm=branch toggle-run-forward stick=[0, 32767] samples=9 median_speed=4.500 m/s [hos BaseProcExecutor4] hid: walking: the movement keys tilt the left stick to 45% (0, 14745) [hos BaseProcExecutor4] hid: walking on (Walk mode Toggle) [hos BaseProcExecutor0] hid: walking off (Walk mode Toggle) ``` The central log lines from each sorted unused-window population produce its median; all blocks are retained, not just these central lines: ```text run 1, main: central 27.3 and 27.6 of 8 blocks [hos Presentation Thread] vk: 3840 presents, 27.3 fps; a frame: 4003 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 840 pipelines (155504 ms), 460 programs (0 failed), 1350 textures (3733 MB) [hos Presentation Thread] vk: 3480 presents, 27.6 fps; a frame: 4000 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 840 pipelines (155504 ms), 460 programs (0 failed), 1367 textures (3828 MB) run 2, this PR: central 29.0 of 9 blocks [hos Presentation Thread] vk: 3840 presents, 29.0 fps; a frame: 4005 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 843 pipelines (201666 ms), 604 programs (0 failed), 1443 textures (3855 MB) run 3, main: central 60.0 and 60.0 of 18 blocks [hos Presentation Thread] vk: 3720 presents, 60.0 fps; a frame: 4085 draws (0 skipped), 124 dispatches, 181 passes, 138 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (216 ms), 0 programs (0 failed), 1526 textures (3893 MB) [hos Presentation Thread] vk: 4080 presents, 60.0 fps; a frame: 4084 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (216 ms), 0 programs (0 failed), 1525 textures (3898 MB) run 4, this PR: central 56.0 and 56.5 of 18 blocks [hos Presentation Thread] vk: 5160 presents, 56.0 fps; a frame: 4081 draws (0 skipped), 125 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (277 ms), 0 programs (0 failed), 1542 textures (4062 MB) [hos Presentation Thread] vk: 4680 presents, 56.5 fps; a frame: 4084 draws (0 skipped), 123 dispatches, 181 passes, 137 barriers, 6 submits, 0.0 uploads (0.0 MB), 80 ub updates (56 overlays), GPU-bound wait 0.0 ms; 841 pipelines (277 ms), 0 programs (0 failed), 1507 textures (3846 MB) ``` All four completed runs had zero fatal/crash/device-loss/core-escape/kernel-fault counts and complete journal coverage. A separate **59.8-second cold attempt is rejected**, not counted as a fifth measurement: the driver sent a blocking A during loading, timed out waiting for a controller read and requested quit. Game exit was 0 with no fault lines; it reached no stable movement or unused window. The corrected driver required an advancing menu before title input. No binary changed to fix that test-driver mistake. The whole suite used a fresh HOME and repository-default compiler selection after the last documentation commit. Separate check output: ```text PASS: 45 option IDs are unique; explicit, implicit and legacy collisions rejected PASS: 5 captured translation units, 0 failures, 0 unjudged drivers/files; Windows execution NOT TESTED ``` The preliminary suite on `3fc3c891` was 509/1/20. The earlier shared main suite at measured `d4a69456` was 507/2/20: the same .NET failure plus a timing-dependent AppImage retry fixture failure under heavy load, whose isolated follow-up passed all nine cases. No package was installed and no failure is called a pass. The whole suite includes the new description/forge tests from `d725b3631`. The shared main suite was run once for all moved pull requests of this day. The unchanged Walk test against measured main rejects the absent helper and option allocation (one error and one failure before behavioral compilation); that is an absence/wiring negative, not a baseline game-speed fixture. The actual game comparison above supplies the behavioral before result. Five changed input fixture units passed Windows-target syntax; the option-ID driver separately used the real Windows-target compiler exits for every expected collision. Two unused-variable warnings in the ocarina binding fixture remain visible. No Windows execution is implied. Historical GitHub checks were green on Windows and Ubuntu at `45f3e06c2ed59ee56cca05ee13bc6b24d131d990`; the published head `2202ab57d77cadc220a2bb3c26b0413f0c21f3e7` carried the same five patches. Relative to that published topic, the forge's product changes are rename-only; the new adaptation is the fixture's README filename, plus new measured-run documentation. This is historical CI, not a new Forgejo Windows run. ## Testing **Tested:** On this PC: Arch Linux, RTX 4090, NVIDIA 615.78.08, Core i9-13900K. Game-free checks covered the Walk behavior/wiring, option-ID collisions, changed input fixtures and the whole suite reported above; five input units also passed Windows-target syntax, not native Windows execution. The measured Longshot builds `d4a69456` / `3fc3c891` used the same copied daytime Kokiri Forest save and identical local key probes: hold W/S with and without Caps Lock, switch to Toggle, tap to walk, tap again to run, and inspect Walk mode/speed and the Controls binding. Those game observations are carried to the current head, not a new game run or physical-keyboard test. Tested but not measured: the menu's appearance and binding-page navigation were inspected without a menu-specific overhead measurement. The shared unused-key FPS observations are inconclusive, not a performance verdict. The 15–90% range and 45% default keep their earlier Hookshot threshold evidence; the full range was not remeasured in Longshot. **Not tested:** A physical keyboard or mouse on this PC, AMD/Intel gameplay, Caps Lock's OS state, first-person aiming while walking, slopes/water or places beyond Kokiri Forest; a controlled on/off overhead comparison. The runs used a key probe on the RTX 4090 in one area, not physical input or those other devices/scenes, and shared load prevents an overhead conclusion. No new test request has been opened for those platforms. **Needs other testers:** - Windows with a physical keyboard: build the host and run the changed input fixtures; try Hold/Toggle and save/reload a rebound Walk key, expecting passing fixtures and the chosen binding/mode to work (request to open) - Non-US keyboard layout or remapped Caps Lock: try Walk and menu/focus changes, expecting the rebound key to work and Toggle to change only on a fresh press (request to open) ## Screenshots ![main @ d4a69456: S + Caps Lock still runs; this PR @ 3fc3c891: the same key combination walks. Same copied scene, with the identical local key probe; not physical-keyboard input.](https://git.magicbean.dev/attachments/3f0728e5-abab-4e4e-86b3-372aed92bd40) ![main @ d4a69456 has no Walk rows; this PR @ 3fc3c891 has Walk mode and speed. Toggle is selected for the picture; Hold remains the default.](https://git.magicbean.dev/attachments/721c9264-567f-412d-9d66-334269e75f3b) ![main @ d4a69456 proceeds from Camera right to the ocarina rows; this PR @ 3fc3c891 adds Walk bound to Caps Lock, with no gamepad binding.](https://git.magicbean.dev/attachments/a3396c81-ffcc-401e-a13f-2a942a9982f8) Historical pictures, inspected and kept separately rather than relabelled as Longshot: ![Earlier Hookshot evidence, 2026-11-11, first-version key probe: walking at about 1.47 m/s versus running at 4.50 m/s. Not a new Longshot measurement.](https://git.magicbean.dev/attachments/8ff38d68-8f2a-4126-ac51-66cc73a20298) ![Hookshot @ 7e536c338 plus its local probe, 2026-11-12: Toggle selected and its help text.](https://git.magicbean.dev/attachments/fc69235a-e3ec-4438-9d40-0fdd2083561d) ![Same historical Hookshot build: the 45% row and its unchanged input-source scope.](https://git.magicbean.dev/attachments/8110ff5a-67e7-4dff-8eb2-ef5bc84d6fe4) ![Same historical Hookshot build: the actual Walk/Caps Lock row, cropped without attributing another row's help to it.](https://git.magicbean.dev/attachments/9388704b-6a70-4e2a-a81a-978726beb5f0) ## Risk and rollback Caps Lock still changes the OS's capitals state; bind another key if unwanted. First-person actions that read the movement stick could also become slower while Walk is active; camera-key and mouse tilt are not scaled, but first-person aiming was not tried. Old conflicting bindings must remain owned by their original controls, and future option additions must preserve the unique-ID guard. Release Walk in Hold mode, toggle it off, or clear its binding to stop walking. Reverting the feature removes the new input path entirely; there is no new global off switch or saved-options migration to undo. The lack of a controlled unused-cost result is why this PR stays WIP. ## Reviewer notes Start with `walk_held()`/`move_keys_stick()`, the old-binding conflict rule, and the host/renderer's 49/50 callbacks. `tests/test_input_background.py` only adds to main's checks; the four assertions Joey-Magnus requested remain intact. `tests/test_option_ids.py` retains all five negative cases. Joey-Magnus approved `c3c7d19e` after the earlier review fixes, including then-free 52/53, named `key_walk` persistence, no API-table bump and the safe conflicting-key upgrade. The later published rebase moved to main's reserved 49/50; the current cap owns 53, so the historical numbers must not be restored. That approval predates this forge head. Caps Lock versus another default key remains the maintainers' choice; no default was changed during this move. ## Issues Original request: https://github.com/NotRexed/Hookshot/issues/2344 (closed). Original pull request: https://github.com/NotRexed/Hookshot/issues/2345. No matching issue exists in the forge's all-issues list checked for this move. No old GitHub number is used as a forge closing reference. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [ ] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. — Correctness is shown; the feature's unused-cost criterion remains inconclusive under shared load. - [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. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] Screenshots for a change that shows on screen. - [x] A row in `docs/tested-configurations.md` for each measured run. - [x] A game-free test added for the fix, failing on `main` and passing here. — Feature test: main lacks the helper/allocation; runtime comparison supplies the behavioral before result. - [x] 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. — Linux Longshot built; current Windows fixture syntax only, historical Windows/Ubuntu checks labelled above. - [x] Docs updated. --- Moved from NotRexed/Hookshot#2345. Assisted-by: Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 <[email protected]> Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <[email protected]>
The movement keys push the left stick to its edge, so on the keyboard Link always ran. A Walk control on the
Controls page (Caps Lock by default) makes them tilt it to the Controls tab's Walk speed instead, while it is held or,
with Walk mode on Toggle, from one press to the next. The camera keys, the mouse, controllers and scripted input keep
their tilt. An options file that already gives Caps Lock to another control leaves Walk without a key.

Walk speed runs from 15% to 90%, default 45%: measured in Kokiri Forest, Link walks his slowest (1.03 m/s) at 15% of
the stick and below, his walk's top speed (1.47 m/s) at 45% and 50%, and from 55% he speeds up into a jog and a run
(4.5 m/s at full tilt).

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Restore all four background-input wiring guards verbatim from main, and the
Walk wiring and documentation checks removed during the earlier renumbering.
Keep the background fixture change strictly additive. Adapt the Walk fixture
to main's two-slot pad binding locks without dropping any assertions.

Use option IDs 52 and 53 after surveying every open PR that changes vk_api.h.
The fetched heads include FOV at 51, Keyboard at 49 and Item wheel at 60;
neither Walk ID is claimed. Compile the real header constants with the host
input path, pin their allocation with static assertions, and retain the
renderer/menu/source checks. Saved walk_mode and walk_speed keys are unchanged.

After FOV merged, keep its formatter and all option-uniqueness checks. Update
the two Walk collision cases and fallback reservations to 52/53 rather than
removing them; its implicit-enum, Item wheel and legacy numeric cases remain.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Use 49 and 50 for Walk mode and speed; 52 now belongs to Skip opening. Keep every collision case and assertion, the named saved keys, and the existing defaults.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Keep the standard C file APIs in the extracted input fixtures under Windows secure-CRT diagnostics. Walk force-includes longshot_env.h, so declare the CRT policy in its compiler arguments before that header. No assertion or warning policy is removed.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Keep the first run's incomplete Hold evidence alongside its valid Toggle
speeds and three menu pictures. Record the separately authorized ordinary
completion run with the same binary, and distinguish test-only key holds
from physical input.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Forge main renamed readme.md to README.md. Keep every Walk documentation assertion and read the current tracked path on case-sensitive systems.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
docs(input): record interleaved Longshot Walk evidence
Some checks are pending
PR description / Description follows the template (pull_request_target) Waiting to run
629766eb20
Retain the failed cold boot, four completed key-probe runs and their inspected menus. Walking works; shared-machine frame-rate spread leaves off-cost unresolved.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Author
First-time contributor

Discussion carried over from NotRexed/Hookshot#2345

Every comment that was readable on the original thread when it was copied on 2026-11-12, in order, unchanged except that issue and pull request numbers are written as links to the old repository and names carry no @. Comments by an account that has since been closed there could no longer be read and are missing; where a reply quotes them, the quote remains.


mooki000, 2026-11-11 16:54 UTC (comment, original):

Rebased onto main b744b1ec. It merged without a conflict, but its test would not have built there: the read_input that tests/test_walk_key.py cuts out of host/nn_hid.c now calls hos_control_input() (NotRexed/Hookshot#926) and reads HOS_INPUT_EXCLUSIVE with env_on() (NotRexed/Hookshot#2042). The test now gets gpu/vk/compat/hookshot_env.h with -include and stubs the control bridge as off, as tests/test_input_background.py does on main. The source lines of this pull request are unchanged.

With the control socket: its input keeps its own stick tilt, like scripted input, and an exclusive socket input keeps the keyboard out while it lasts, Walk included.

Rerun on the new head (8a14b300): the branch's three tests pass with gcc 16 and clang 23, and test_walk_key.py still fails against main's source. tests/run_all.py: 374 passed, 4 failed, 10 skipped. All four fail on main too on this machine; two of them are main's test_vcore_fs_open.py and test_vcore_video_acquire.py, which NotRexed/Hookshot#2380 fixes, so expect those two red here until it is merged. The game runs in the description are from the old base (49f75dc8) and were not repeated.


mooki000, 2026-11-11 17:56 UTC (comment, original):

Moved Walk mode/speed to 49/50 and updated both vk_menu.h comments in 37687e2f. The host and renderer use the same constants; a compiled header check reports walk_mode=49 walk_speed=50 camera_speed=48. Saved named keys are unchanged. NotRexed/Hookshot#2366 can keep 46; its remaining overlaps are text conflicts, not shared IDs.

Also rebased onto 7759a6f3, including NotRexed/Hookshot#2380. The three input checks pass with GCC and Clang. The full suite is 386 passed, 1 failed, 10 skipped; only the missing .NET 8 reference packs fail here. I removed the source-text wiring assertions rather than repinning the IDs; the compiled behavior check still rejects a variant with Walk tilt suppressed, with both compilers.

No new game run after this rebase/renumber; first-person aiming remains explicitly untested.


mooki000, 2026-11-11 18:03 UTC (comment, original):

tests/test_walk_key.py passes on Windows on 37687e2f. Windows part 1/2 fails only on tests/test_native_astc_texture_count.py (the known scanf CRT deprecation); NotRexed/Hookshot#2397 contains that fix. The description now records this Windows game-free coverage. Physical keyboard input and Windows gameplay remain untested.


pmwork-personal, 2026-11-11 19:26 UTC (comment, original):

I think i prefer Alt as walk. its consistent with many other default control schemes in other implementations with walk keys.


mooki000, 2026-11-11 20:08 UTC (comment, original):

pmwork-personal thanks. Walk is rebindable on the Controls page. This CI refresh keeps Caps Lock; the default choice can be settled separately. The readme already calls out its effect on capitals.

Rebased onto 47ed9f14, now 796b1bdf, including the merged NotRexed/Hookshot#2397 repair and NotRexed/Hookshot#2366 live prompts. The latter exposed a fixture bug: the test selected an earlier hos_bind declaration instead of its definition. The range search is fixed, and all three input checks pass with GCC and Clang. Walk still uses 49/50. No new gameplay, physical-input or first-person-aiming proof is claimed.

Update 2026-11-11: the refreshed source-regression workflow is green on 796b1bdf: both Windows and both Ubuntu shards pass. This is game-free CI evidence, not a new game run.


Joey-Magnus, 2026-11-11 21:23 UTC (review: changes requested, original):

The code is sound (Caps Lock is scancode 57, a conflicting old ini leaves Walk unbound with a log line, and no API bump is needed). Two things before merge:

  1. tests/test_input_background.py drops four checks unrelated to this feature: the background block reads pads but not keyboard or mouse, t.option maps 4 to pad_background, and the "Controller in background" row exists. All four still pass on this branch, so they can simply go back in. AGENTS.md asks for checks to be updated, not removed.
  2. Option ID collision: HOS_OPT_WALK_MODE = 49 matches NotRexed/Hookshot#2357's HOS_OPT_FOV = 49. The two PRs touch different hunks, so git won't flag it. Your if (id == HOS_OPT_WALK_MODE) comes first, so the game would read Walk mode (0/1) as the FOV percentage, which oot_fov.c then rejects. Whichever lands second has to renumber; please coordinate with polaco1782.

There's also an open question from a commenter about Alt instead of Caps Lock as the default.


mooki000, 2026-11-11 23:45 UTC (comment, original):

I fixed both points in 5ab213a6:

  1. I restored all four background checks verbatim and every original Walk wiring/doc check. The background test only adds to main. After NotRexed/Hookshot#2357 merged, I updated its two Walk collision cases and reservations to 52/53, keeping all five cases and every assertion.
  2. I moved Walk mode/speed to 52/53 after scripting a survey of all 134 open PRs and fetching the 13 heads that changed vk_api.h. Neither ID was claimed; the refreshed table now puts FOV 51 on main and still finds 52/53 free. NotRexed/Hookshot#2530 claims 49 for Keyboard. The real header is compiled with the host's reads, and the renderer, menu comments and wiring checks agree.

The three input checks and the 43-ID guard pass with GCC and Clang; suppressed Walk tilt fails at runtime, and all 13 socket-fixture states pass. The updated description keeps both unequal raw suite results with their loads; the three differing depth/recorder/appimage checks all pass when run serially.

I kept Caps Lock for now: Walk is rebindable on the Controls page, and I can change the default if the maintainers prefer another key.

I rebased onto 8fcc8c22 after the FOV merge, keeping both formatters, main's two-slot pad bindings and its documentation additions. No new game run, physical-input or first-person-aiming proof is claimed.


mooki000, 2026-11-12 06:07 UTC (comment, original):

Rebased the pushed 5ab213a6 onto current main 87991bc8 as c3c7d19e, keeping both commits and their complete authors/messages/trailers. The resolutions retain all five ocarina-note controls, keyboard prompts, camera handover, upscaler reset and current translated hints beside Walk's unchanged Hold/Caps Lock/45% defaults, 15–90% range and IDs 52/53. Fixtures retain all assertions; the new note-layer integration also asserts that an inactive note layer consumes no controller input. GCC passed all 122 selected checks; Clang passed 121 with main's inherited background-input warning. The suite was 469 passed / 2 inherited failures / 20 skipped: that warning and the known release-script race. The last rebase adds only NotRexed/Hookshot#2671 and changes no PR file blob; Walk/ocarina/wiring checks, final-main negatives, NotRexed/Hookshot#2671's offline check and Windows-target syntax ran again. The final PR gate passes. No second full suite, game run or native Windows execution is claimed. Sources: the NotRexed/Hookshot#2345 evidence and final-handoff ledger above.


Joey-Magnus, 2026-11-12 14:32 UTC (review: approved, original):

Both of my points are fixed at c3c7d19e. tests/test_input_background.py now only adds to main's checks, with the four I asked about back unchanged, and Walk uses option ids 52 and 53 (gpu/vk/vk_api.h:34), which nothing on main uses (main has 45 to 48, and NotRexed/Hookshot#2357's FOV took 51). The bind table grows by one entry at its end, saved by name as key_walk, options_version is untouched and no API bump is needed.

I merged it into current main and ran test_walk_key.py, test_bound_keys.py, test_input_background.py, test_ocarina_note_bindings.py, test_ocarina_notes.py, test_option_ids.py, test_menu_i18n.py and test_env_on.py: all pass, and CI is green on this head. Leaving Walk unbound with a log line when an older ini already gives Caps Lock to another control (binds_load) is the right upgrade path.

Caps Lock versus Alt as the default is the maintainers' call, and it's rebindable either way. First-person aiming while walking is still untested, as you say.


mooki000, 2026-11-12 17:04 UTC (comment, original):

Both are taken in the default layout: Shift is B and Ctrl is the left-stick click (key_default in host/nn_hid.c), so Walk on either means moving one of those to another key. Caps Lock was the free key beside them, which is the only reason it was picked. The row is rebound on the Controls page like any other, so a player who wants Walk on Shift or Ctrl can swap them today.

Caps Lock has a cost, to be fair: every press also flips the system's Caps Lock state, and I have not tried it on a physical keyboard (the runs were headless, as the description says).

If you would rather have Walk on Ctrl by default, with the stick click moved to another key or left without one, say which and I will change the default table, the README row and the test. One thing to decide with it: a player whose saved bindings already name Ctrl for the stick click would start with Walk unbound (the existing rule for a default key that is taken), not with the two swapped.


mooki000, 2026-11-12 18:48 UTC (comment, original):

Rebased onto main 3c2d80cf3; new head 2202ab57d.
Walk mode and speed now use 49 and 50, the numbers main reserves for Walk, because 52 went to Skip opening. Saved option names are unchanged.
No other gameplay change: Caps Lock, Hold, 45% and the 15–90% range remain. The default key still awaits the maintainer's preference.
Four input fixtures now declare CRT usage before headers; every assertion is retained. The fork's Windows run uses 45f3e06c2; all five patches are identical at this final head.
Focused checks: 24 passed with GCC 16 and 24 with Clang 23. A full run of the project's checks in my fork, Windows included, is green on 45f3e06c: the same five commits one main commit earlier (git range-diff marks each =), so it was not repeated for this head.
The earlier full suite was 497 passed, 3 failed, 20 skipped: two failures on main too, now fixed there; the compiler SIGKILL passed alone with fewer workers.
First windowless Kokiri run: three inspected menu pictures, Toggle walking/running 1.467 / 4.500 m/s, and Hold running 4.500 m/s.
Hold walking was not measured in that run: first-load shader compilation swallowed the short holds.
One ordinary completion run, same binary: Hold walking/running 1.469 / 4.500 m/s, nine readings each after the first.
Both walking results round to the description's 1.47 m/s, running to 4.50 m/s. Physical input and Windows gameplay remain untested.
Runs were built at 7e536c33, before the final refresh: the Walk code is identical, but the intervening main renderer changes were not rerun.
Joey-Magnus's earlier approval was for c3c7d19e and predates this refresh.

## Discussion carried over from NotRexed/Hookshot#2345 Every comment that was readable on [the original thread](https://github.com/NotRexed/Hookshot/pull/2345) when it was copied on 2026-11-12, in order, unchanged except that issue and pull request numbers are written as links to the old repository and names carry no @. Comments by an account that has since been closed there could no longer be read and are missing; where a reply quotes them, the quote remains. --- **mooki000**, 2026-11-11 16:54 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6801896456)): Rebased onto main `b744b1ec`. It merged without a conflict, but its test would not have built there: the `read_input` that `tests/test_walk_key.py` cuts out of `host/nn_hid.c` now calls `hos_control_input()` ([NotRexed/Hookshot#926](https://github.com/NotRexed/Hookshot/issues/926)) and reads `HOS_INPUT_EXCLUSIVE` with `env_on()` ([NotRexed/Hookshot#2042](https://github.com/NotRexed/Hookshot/issues/2042)). The test now gets `gpu/vk/compat/hookshot_env.h` with `-include` and stubs the control bridge as off, as `tests/test_input_background.py` does on main. The source lines of this pull request are unchanged. With the control socket: its input keeps its own stick tilt, like scripted input, and an exclusive socket input keeps the keyboard out while it lasts, Walk included. Rerun on the new head (`8a14b300`): the branch's three tests pass with gcc 16 and clang 23, and `test_walk_key.py` still fails against main's source. `tests/run_all.py`: 374 passed, 4 failed, 10 skipped. All four fail on main too on this machine; two of them are main's `test_vcore_fs_open.py` and `test_vcore_video_acquire.py`, which [NotRexed/Hookshot#2380](https://github.com/NotRexed/Hookshot/issues/2380) fixes, so expect those two red here until it is merged. The game runs in the description are from the old base (`49f75dc8`) and were not repeated. --- **mooki000**, 2026-11-11 17:56 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6803289601)): Moved Walk mode/speed to **49/50** and updated both `vk_menu.h` comments in `37687e2f`. The host and renderer use the same constants; a compiled header check reports `walk_mode=49 walk_speed=50 camera_speed=48`. Saved named keys are unchanged. [NotRexed/Hookshot#2366](https://github.com/NotRexed/Hookshot/issues/2366) can keep 46; its remaining overlaps are text conflicts, not shared IDs. Also rebased onto `7759a6f3`, including [NotRexed/Hookshot#2380](https://github.com/NotRexed/Hookshot/issues/2380). The three input checks pass with GCC and Clang. The full suite is `386 passed, 1 failed, 10 skipped`; only the missing .NET 8 reference packs fail here. I removed the source-text wiring assertions rather than repinning the IDs; the compiled behavior check still rejects a variant with Walk tilt suppressed, with both compilers. No new game run after this rebase/renumber; first-person aiming remains explicitly untested. --- **mooki000**, 2026-11-11 18:03 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6803453045)): `tests/test_walk_key.py` passes on Windows on `37687e2f`. [Windows part 1/2](https://github.com/NotRexed/Hookshot/actions/runs/43072781059/job/130704747959) fails only on `tests/test_native_astc_texture_count.py` (the known `scanf` CRT deprecation); [NotRexed/Hookshot#2397](https://github.com/NotRexed/Hookshot/issues/2397) contains that fix. The description now records this Windows game-free coverage. Physical keyboard input and Windows gameplay remain untested. --- **pmwork-personal**, 2026-11-11 19:26 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6805237372)): I think i prefer Alt as walk. its consistent with many other default control schemes in other implementations with walk keys. --- **mooki000**, 2026-11-11 20:08 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6806115275)): pmwork-personal thanks. Walk is rebindable on the Controls page. This CI refresh keeps Caps Lock; the default choice can be settled separately. The readme already calls out its effect on capitals. Rebased onto `47ed9f14`, now `796b1bdf`, including the merged [NotRexed/Hookshot#2397](https://github.com/NotRexed/Hookshot/issues/2397) repair and [NotRexed/Hookshot#2366](https://github.com/NotRexed/Hookshot/issues/2366) live prompts. The latter exposed a fixture bug: the test selected an earlier `hos_bind` declaration instead of its definition. The range search is fixed, and all three input checks pass with GCC and Clang. Walk still uses 49/50. No new gameplay, physical-input or first-person-aiming proof is claimed. Update 2026-11-11: [the refreshed source-regression workflow](https://github.com/NotRexed/Hookshot/actions/runs/43093276382) is green on `796b1bdf`: both Windows and both Ubuntu shards pass. This is game-free CI evidence, not a new game run. --- **Joey-Magnus**, 2026-11-11 21:23 UTC (review: changes requested, [original](https://github.com/NotRexed/Hookshot/pull/2345#pullrequestreview-5865471662)): The code is sound (Caps Lock is scancode 57, a conflicting old ini leaves Walk unbound with a log line, and no API bump is needed). Two things before merge: 1. `tests/test_input_background.py` drops four checks unrelated to this feature: the background block reads pads but not keyboard or mouse, `t.option` maps 4 to `pad_background`, and the "Controller in background" row exists. All four still pass on this branch, so they can simply go back in. AGENTS.md asks for checks to be updated, not removed. 2. Option ID collision: `HOS_OPT_WALK_MODE = 49` matches [NotRexed/Hookshot#2357](https://github.com/NotRexed/Hookshot/issues/2357)'s `HOS_OPT_FOV = 49`. The two PRs touch different hunks, so git won't flag it. Your `if (id == HOS_OPT_WALK_MODE)` comes first, so the game would read Walk mode (0/1) as the FOV percentage, which `oot_fov.c` then rejects. Whichever lands second has to renumber; please coordinate with polaco1782. There's also an open question from a commenter about Alt instead of Caps Lock as the default. --- **mooki000**, 2026-11-11 23:45 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6809970212)): I fixed both points in `5ab213a6`: 1. I restored all four background checks verbatim and every original Walk wiring/doc check. The background test only adds to main. After [NotRexed/Hookshot#2357](https://github.com/NotRexed/Hookshot/issues/2357) merged, I updated its two Walk collision cases and reservations to 52/53, keeping all five cases and every assertion. 2. I moved Walk mode/speed to **52/53** after scripting a survey of all 134 open PRs and fetching the 13 heads that changed `vk_api.h`. Neither ID was claimed; the refreshed table now puts FOV 51 on main and still finds 52/53 free. [NotRexed/Hookshot#2530](https://github.com/NotRexed/Hookshot/issues/2530) claims 49 for Keyboard. The real header is compiled with the host's reads, and the renderer, menu comments and wiring checks agree. The three input checks and the 43-ID guard pass with GCC and Clang; suppressed Walk tilt fails at runtime, and all 13 socket-fixture states pass. The updated description keeps both unequal raw suite results with their loads; the three differing depth/recorder/appimage checks all pass when run serially. I kept Caps Lock for now: Walk is rebindable on the Controls page, and I can change the default if the maintainers prefer another key. I rebased onto `8fcc8c22` after the FOV merge, keeping both formatters, main's two-slot pad bindings and its documentation additions. No new game run, physical-input or first-person-aiming proof is claimed. --- **mooki000**, 2026-11-12 06:07 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6816119035)): Rebased the pushed `5ab213a6` onto current main `87991bc8` as `c3c7d19e`, keeping both commits and their complete authors/messages/trailers. The resolutions retain all five ocarina-note controls, keyboard prompts, camera handover, upscaler reset and current translated hints beside Walk's unchanged Hold/Caps Lock/45% defaults, 15–90% range and IDs 52/53. Fixtures retain all assertions; the new note-layer integration also asserts that an inactive note layer consumes no controller input. GCC passed all 122 selected checks; Clang passed 121 with main's inherited background-input warning. The suite was 469 passed / 2 inherited failures / 20 skipped: that warning and the known release-script race. The last rebase adds only [NotRexed/Hookshot#2671](https://github.com/NotRexed/Hookshot/issues/2671) and changes no PR file blob; Walk/ocarina/wiring checks, final-main negatives, [NotRexed/Hookshot#2671](https://github.com/NotRexed/Hookshot/issues/2671)'s offline check and Windows-target syntax ran again. The final PR gate passes. No second full suite, game run or native Windows execution is claimed. Sources: the [NotRexed/Hookshot#2345](https://github.com/NotRexed/Hookshot/issues/2345) evidence and final-handoff ledger above. --- **Joey-Magnus**, 2026-11-12 14:32 UTC (review: approved, [original](https://github.com/NotRexed/Hookshot/pull/2345#pullrequestreview-5876210432)): Both of my points are fixed at c3c7d19e. `tests/test_input_background.py` now only adds to main's checks, with the four I asked about back unchanged, and Walk uses option ids 52 and 53 (`gpu/vk/vk_api.h:34`), which nothing on main uses (main has 45 to 48, and [NotRexed/Hookshot#2357](https://github.com/NotRexed/Hookshot/issues/2357)'s FOV took 51). The bind table grows by one entry at its end, saved by name as `key_walk`, `options_version` is untouched and no API bump is needed. I merged it into current main and ran `test_walk_key.py`, `test_bound_keys.py`, `test_input_background.py`, `test_ocarina_note_bindings.py`, `test_ocarina_notes.py`, `test_option_ids.py`, `test_menu_i18n.py` and `test_env_on.py`: all pass, and CI is green on this head. Leaving Walk unbound with a log line when an older ini already gives Caps Lock to another control (`binds_load`) is the right upgrade path. Caps Lock versus Alt as the default is the maintainers' call, and it's rebindable either way. First-person aiming while walking is still untested, as you say. --- **mooki000**, 2026-11-12 17:04 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6830337464)): Both are taken in the default layout: Shift is B and Ctrl is the left-stick click (`key_default` in `host/nn_hid.c`), so Walk on either means moving one of those to another key. Caps Lock was the free key beside them, which is the only reason it was picked. The row is rebound on the Controls page like any other, so a player who wants Walk on Shift or Ctrl can swap them today. Caps Lock has a cost, to be fair: every press also flips the system's Caps Lock state, and I have not tried it on a physical keyboard (the runs were headless, as the description says). If you would rather have Walk on Ctrl by default, with the stick click moved to another key or left without one, say which and I will change the default table, the README row and the test. One thing to decide with it: a player whose saved bindings already name Ctrl for the stick click would start with Walk unbound (the existing rule for a default key that is taken), not with the two swapped. --- **mooki000**, 2026-11-12 18:48 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2345#issuecomment-6832814741)): Rebased onto main `3c2d80cf3`; new head `2202ab57d`. Walk mode and speed now use 49 and 50, the numbers main reserves for Walk, because 52 went to Skip opening. Saved option names are unchanged. No other gameplay change: Caps Lock, Hold, 45% and the 15–90% range remain. The default key still awaits the maintainer's preference. Four input fixtures now declare CRT usage before headers; every assertion is retained. The fork's Windows run uses `45f3e06c2`; all five patches are identical at this final head. Focused checks: 24 passed with GCC 16 and 24 with Clang 23. A full run of the project's checks in my fork, Windows included, is green on `45f3e06c`: the same five commits one main commit earlier (`git range-diff` marks each `=`), so it was not repeated for this head. The earlier full suite was 497 passed, 3 failed, 20 skipped: two failures on main too, now fixed there; the compiler SIGKILL passed alone with fewer workers. First windowless Kokiri run: three inspected menu pictures, Toggle walking/running 1.467 / 4.500 m/s, and Hold running 4.500 m/s. Hold walking was not measured in that run: first-load shader compilation swallowed the short holds. One ordinary completion run, same binary: Hold walking/running 1.469 / 4.500 m/s, nine readings each after the first. Both walking results round to the description's 1.47 m/s, running to 4.50 m/s. Physical input and Windows gameplay remain untested. Runs were built at `7e536c33`, before the final refresh: the Walk code is identical, but the intervening main renderer changes were not rerun. Joey-Magnus's earlier approval was for `c3c7d19e` and predates this refresh.
Author
First-time contributor

Added the three-part Testing section and updated the full checklist. Added one branch base/head/suite block under Measurements; apart from consolidating duplicate results and minor wording cleanup, nothing else changed.

Added the three-part Testing section and updated the full checklist. Added one branch base/head/suite block under Measurements; apart from consolidating duplicate results and minor wording cleanup, nothing else changed.
Some checks are pending
PR description / Description follows the template (pull_request_target) Waiting to run
This pull request has changes conflicting with the target branch.
  • docs/tested-configurations.md
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'walk-key:mooki-walk-key'
git switch 'mooki-walk-key'
Sign in to join this conversation.
No description provided.