WIP: feat(menu): type and save a custom output size in the Insert menu #51

Draft
mooki wants to merge 5 commits from mooki/Longshot:menu-text-fields into main
First-time contributor

Why

Players should be able to type a monitor size that the Insert menu does not list, without editing the options file. This also gives later text settings a shared editor rather than another keyboard handler.

Draft for one remaining runtime check: the frame-time comparison awaits a quiet machine. The new Longshot menu and saved-size proof is complete; the shared-load comparison below is too variable to establish no cost while the menu is closed.

The closed-menu timing limitation remains open. All earlier evidence below keeps its actually tested identity.

What changed

  • Graphics gains Custom output size, with typing, caret movement, Backspace/Delete, Enter to commit, Esc to cancel, and first-line clipboard paste. Printable ASCII only: unsupported characters are left out because the menu's baked font does not cover them.
  • Text input is enabled only while a field has focus. A bounded, locked host queue connects Windows/SDL text events to the renderer. Controller confirm/back/paste and the menu's existing focus rules use the same editor.
  • A typed listed size reuses its choice; an unlisted size joins the appropriate shape's list. The screen-mode choices, monitor/native marks, restart tracking, preset exemption and saved output_res=<width>x<height> representation remain intact.
  • Renderer API 21 → 22: take_text follows screen_size in both MkwVkHost and its positional initializer. Main's nvn_program_created, live frame-rate-cap option 53, in-play Debug callbacks and Dev FPS level are retained. No numeric option ID is added or renumbered. The executable and renderer must come from the same build.
  • Existing source-reading fixtures are updated without removing their checks. The README, scripted-menu reference and tested configurations are updated.

This answers Joey-Magnus's review of the original change: the display-mode work is already in the base, and custom_output/output_extras are retained. The later program-created callback consumed API 21, so this addition correctly uses 22 rather than the review's then-next 21.

Implementation map: gpu/vk/vk_menu.cpp owns text_edit, output_field_apply, restart_value and the focused menu_tick path; host/rx_backend.c owns host_take_text and the queue. host/display.c, host/posix/display_sdl.c and host/hos_sdl.c feed it. gpu/vk/vk_api.h, gpu/vk/vk_menu_keys.h, gpu/vk/vk_ui.h and gpu/vk/menu_i18n.h carry the interface, paste prompts and revised hint. tests/test_menu_text_field.py, tests/test_menu_keys.py, tests/test_menu_restart_slots.py and tests/screensaver_test.c carry the source-fixture coverage.

Flags and settings

The table covers changed behavior as well as newly introduced names. Runtime evidence remains the carried Linux/RTX 4090 evidence at 7677d2f12; source contracts and untested interactions are not new runtime results. There is no new global enable switch, no new numeric option ID, and no new production command-line or build flag.

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
RX_VK_MENU_SCRIPT Changed existing environment switch: Adds TYPE:text up to the next comma and focused HOME, END, BACK, DEL, LEFT, RIGHT, ENTER, ESC; existing pad confirm/back events reach the field Unset: no scripted menu input Off by default: explicit test input only Repeatable scripted typing/caret/commit on the Linux runs below Physical-input validation or a quiet-machine guarantee Native Windows input, SDL2, physical devices
Custom output size New Graphics menu row: Edits an unlisted size, selects an already listed size, or clears the custom choice; commits through output_field_apply and takes effect after restart None; an existing unlisted saved size is shown instead. No field has text focus until editing begins On after more testing: offer the editor, not a forced custom size; the closed-menu timing check is still open Typed-size and saved-start Linux/RTX 4090 cases below Unicode/IME entry or changing the running picture immediately Windows, SDL2, physical keyboard/clipboard/controller, AMD/Intel, Steam Deck, real windows and monitor changes
Output resolution Changed menu integration and restart tracking: Reuses a listed typed size or offers the custom size; compares dimensions, not only the choice index, for restart tracking; preserves the startup size in the dynamic list Base/fallback 2048x1152; existing saved choices, environment overrides and first-start Auto selection still apply On by default: retain existing selection policy, not a new size default Custom/listed transitions and saved 1920x800 start below Removing the restart requirement or proving live monitor enumeration Native Windows, physical displays, AMD/Intel, Steam Deck
Aspect ratio Changed interaction with typed output sizes: Follows the committed size's shape and remaps startup/Later state when the dynamic shape list changes Monitor's shape (ultrawide=1); a non-16:9 output size retains its own shape On by default: keep the existing default; only an explicit size edit changes the selection The typed 1920x800/21:9-menu case and game-free dynamic-list cases Proving physical monitor changes or HDR Native Windows, real monitor changes, AMD/Intel, Steam Deck
output_res Existing ini key, now written by the text field: Keeps widthxheight, not a list index; accepted custom dimensions are rounded down to multiples of 8, at least 640x360, at most 5120x2880's pixels, from 5:4 to 48:9 Missing/invalid value: the game's 2048x1152; saved values and existing Auto/environment selection remain applicable Off by default: forced custom value: retain the saved/default choice Persistent custom-size edits without hand-editing the ini Live resizing; invalid sizes are refused in the editor and fall back when read from the file Windows persistence, long sessions and other GPU vendors
ultrawide Existing ini key, changed through the new field's shape selection: Keeps the existing encoding: 1 follows the monitor, otherwise 0; another shape is represented by output_res 1, monitor's shape On by default: preserve the existing default and encoding Keeping saved size and shape aligned after a typed edit Unicode input or a new display-enumeration policy Native Windows and physical monitor changes
HOS_OUTPUT_RES Existing environment override, new editor interaction: A committed text edit releases the menu's temporary override for saving, like the existing Output resolution row; it does not resize this process. Unset the launch override to test the saved value on the next start Unset: no environment override Off by default: explicit one-run override only Preserving an explicit player edit; the new fixture covers the release call Applying a saved size while the next launch still forces an environment value End-to-end override/edit interaction in the new game captures; native Windows
tests/test_menu_text_field.py --cxx New test-driver CLI option: Selects the compiler driver for the extracted C++20 menu and C11 queue fixtures (-x selects the language) g++ for direct invocation; the whole-suite runner supplies its selected C++ compiler Off by default: automatic run: an explicit game-free test command Repeating the source fixtures with the selected compiler Windows runtime or physical-input proof from a syntax-only capture Native Windows execution of the changed fixtures

The README option table and custom-size explanation, plus docs/development.md's scripted-input and options-file references, are updated. The test driver's --cxx usage is documented in its own module. HOS_DISPLAY_MODES, capture/timing switches, the Quality preset, Profile, frame-rate cap and screen-mode policy are unchanged; their values below are reproduction settings, not new defaults.

Measurements

Branch state: on main d725b3631982ed0035ea3ac9cbe1677e9fad260c; head d5b2ff117905fa9ad4a5def759efa52f7a5c1078; 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 sole failure in both suites in the branch-state block is tests/test_updater_asset_digest.py: local .NET cannot resolve Microsoft.AspNetCore.App.Ref (= 10.0.13) (NU1100). The historical suites below also include this failure.

main: d4a69456c9 (measured baseline, 2026-11-12)
this PR: menu-text-fields @ 7677d2f12e (code built and tested, 2026-11-12)

Previously submitted branch head: 70373b9a1c9cf106b49e82b7010360762c877c60; code built and tested @ 7677d2f12e123fa79df8b3f6604b6fec7933bce2. The final commit adds the measured configuration rows only.

Between measured main d4a69456 and main d725b3631982ed0035ea3ac9cbe1677e9fad260c, changes are confined to forge scripts/workflow, documentation/rules and tests, not the host or renderer. The functional observations therefore remain relevant to the same runtime change, but all rows and outputs below retain their original measured commits. They are not reruns on the current head, and the noisy closed-menu observations do not become conclusive through a rebase.

No new game build, Windows execution or game run is claimed for this rebase.

Hardware: RTX 4090 24 GB, NVIDIA 615.78.08; Core i9-13900K, 96 GB RAM; Arch Linux 7.2.15-1-omarchy.
Scene: title / Insert menu, 2048x1152 before editing; saved-size start at 1920x800. Closed-menu observations: child Link standing in Kokiri Forest from the same copied save, 1280x720, default 60 cap, game's upscaler, FG off, no overlays, windowless. Authored display modes 1920x1080 and 2560x1080, not physical monitor enumeration.
Method: same release-profile build on both sides, rebuilt host and renderer; one baseline menu run, a 100 s scripted edit, then a separate 45 s start using its saved options. For the closed-menu comparison: one 80 s warm-up per build, then main/branch/main/branch, 80 s each; common 35–65 s renderer-frame windows, with the first boundary interval excluded. These headless CPU intervals follow offscreen submission; they are not GPU time or display latency. Whole game-free suite with the default compiler on the branch; the main suite is the day's shared pinned-base run.

How to reproduce:

  1. Use matched release/profile builds, with each executable and renderer from the same source; the retained comparison is main d4a69456 against code 7677d2f1. Keep separate disposable options/save storage, the game's upscaler, frame generation off and no overlays. The menu captures used precompile off (RX_VK_PRECOMPILE=0), windowless output, and authored HOS_DISPLAY_MODES=1920x1080,2560x1080, not physical display enumeration.
  2. On main, open Insert → Graphics at 2048x1152 and observe that Output resolution is followed by Profile, with no Custom output size row. On this PR, use the sequence below; observe partial text and a moved caret before committing, then select listed 2560x1080 and 3440x1440, return through 2560x1080 to 1920x800, and compare each observed row with saved output_res. The retained edit is a 100 s scripted run; RX_VK_MENU_SCRIPT supplies the timed menu keys and TYPE:text actions documented above.
  3. Start a separate 45 s process with those saved options and without HOS_OUTPUT_RES. Check the startup picture 1920x800 / camera ratio 2.4000 lines, both size rows, and the absence of a restart marker.
  4. For the closed-menu comparison, use the same locally copied save with child Link standing in Kokiri Forest, 1280x720, Custom preset, 100% render resolution, default 60 cap, the game's upscaler and FG off. Record RX_VK_FRAME_LOG renderer CSVs; warm each build for 80 s, then run main/PR/main/PR for 80 s each. Read the same 35–65 s interval after excluding the first boundary interval. Keep every run and its load/journal receipt; the retained shared-load runs below fail the predeclared 5% same-build consistency rule. A quiet repeat is still needed, not a speed conclusion from these rows.
  5. The new game-free driver is invoked as python -I -B tests/test_menu_text_field.py --cxx g++; the complete source suite is python -I -B tests/run_all.py. These are reproduction commands, not new receipts. The text-field driver has no --source option: a baseline comparison needs the corresponding pinned-source fixture setup, not an invented flag.

Try it: Insert → Graphics → Custom output size → Enter → type 1920x800 → Enter. Closing the menu offers the existing restart question. This changes the saved size, not the running game's picture until its next start.

main @ d4a69456 this PR @ 7677d2f1
Typed-size row Absent Typing, caret and commit visible
Saved/listed size sequence No typed entry 1920x800 → 2560x1080 → 3440x1440 → 2560x1080 → 1920x800; every observed row agrees with saved dimensions
Next start Ordinary 2048x1152 baseline Picture 1920x800; camera ratio 2.4000; both size rows 1920x800, no restart marker
Whole game-free suite 507 passed, 2 failed, 20 skipped 509 passed, 1 failed, 20 skipped
New field test on main's source Fails: text API absent Included and passing in the whole suite
FAIL: vk_api.h: no HOS_TEXT_KEY and HOS_TEXT_OFF/ON/PASTE
507 passed, 2 failed, 20 skipped in 504 s (linux, 6 at once)
509 passed, 1 failed, 20 skipped in 315 s (linux, 6 at once)
PASS: 3 captured translation units, 0 failures, 0 unjudged drivers/files; Windows execution NOT TESTED
[hos host] longshot v2.2.0-rc.1-23-g7677d2f12 (source 3e2f2cc9)
[hos host] oe: output resolution 1920x800
[hos host] boot: widescreen: picture 1920x800, scene 1440x600, camera ratio 2.4000, HUD and movies in the middle 74.1%
output_res=1920x800

The base suite was run once for all moved pull requests of this day, on that commit. The shared base also fails two bounded-time cases in tests/test_appimage_package_retry.py; that test passes on this branch. A duplicate base run completed before the shared-base policy: 507/2/20, with the same .NET failure and a shaderbatch-build error in test_bake_skeleton.py; both non-.NET checks pass here. No failed result was erased or relabelled green. These checks have not yet been run on a forge runner.

All three new functional game runs ended at their requested bounds (game exit 124), with zero fatal, crash, device-loss, virtual-core-escape, kernel-fault and NVRM counts and complete journal coverage. The menu edit's load was 226.31 → 122.12; the saved start's 87.82 → 64.20. Neither duration nor frame rate from those captures is a performance measurement.

Closed-menu observations, under shared load — inconclusive. The same-build spread is too large to say anything: median-frame repeat spread is 7.39% on main and 23.40% on the branch; mean-frame repeat spread is 15.00% and 29.36%. Both exceed the 5% same-build consistency rule set before reading the data. The branch's observed medians are higher, but these noisy runs do not establish causation or “no cost when off”. The frame-time comparison awaits a quiet machine. No run is discarded.

main @ d4a69456 this PR @ 7677d2f1
Median frame time, run 1 / run 2 20.4535 / 18.9960 ms 26.6860 / 33.7570 ms
Median of those two medians 19.72475 ms 30.22150 ms
Mean frame time, run 1 / run 2 22.5643 / 19.4150 ms 25.8817 / 34.7887 ms
Median of the two means 20.98964 ms 30.33518 ms
One-minute load, run 1 before → after 69.87 → 37.25 35.07 → 55.34
One-minute load, run 2 before → after 35.57 → 17.46 13.15 → 41.44

Actual reader output from the retained renderer CSVs, in run order:

base-closed-1: window=35..65s frames=1328 mean_ms=22.564300 median_ms=20.453500 p99_ms=37.158000
branch-closed-1: window=35..65s frames=1158 mean_ms=25.881656 median_ms=26.686000 p99_ms=44.379000
base-closed-2: window=35..65s frames=1545 mean_ms=19.414979 median_ms=18.996000 p99_ms=27.932000
branch-closed-2: window=35..65s frames=862 mean_ms=34.788704 median_ms=33.757000 p99_ms=48.366000
Same-build consistency within 5%: False

The game state and inspected pictures put all four runs in the same saved forest scene, with the menu closed. All four ended at their bounds with game exit 124, zero fatal/crash/device-loss/escape/kernel/NVRM counts and complete journal coverage. These observations meet the requested interleaving, not the evidence needed for a no-cost conclusion.

Current-main source suite, separate from the historical runtime comparison

Main ran the whole game-free suite once for all PRs using the branch-state block's base: python -I -B tests/run_all.py --jobs 6 --strict, default compiler, fresh HOME. It finished at 2026-11-12T19:12:28-06:00 under heavy shared load; the one-minute load after the run was 62.6. This is a source-suite receipt, not another game or frame-time measurement.

The earlier d4a69456/7677d2f1 tables and failures remain historical evidence at those exact identities. The refreshed branch's full suite ran 2026-11-12 19:10:40–19:16:36 local, using the repository default compiler and fresh HOME/XDG. Execution took 234 s on main and 247 s on the branch, not a performance comparison. No base suite was duplicated.

Testing

Tested: on this PC (Arch Linux, RTX 4090 with NVIDIA 615.78.08, i9-13900K), the current-head whole game-free suite; earlier text-field, menu-key, restart-slot and screensaver checks and the text-field negative control against main retain their measured commits above. Three translation units compiled for the Windows target; not run on Windows. In the game, compared main's title/Insert → Graphics page with scripted typing and caret movement on code 7677d2f1, committed 1920x800, switched through listed sizes and back, then started a separate process to check the saved picture size, both menu rows and absence of a restart marker. The retained closed-menu runs stood in Kokiri Forest with the same save and settings.

Tested but not measured: the title/Insert-menu typing, caret, listed-choice and saved-size functional captures on main d4a69456 and code 7677d2f1, and the historical Hookshot 4914fdec captures. Their durations and frame rates are not performance measurements. The closed-menu captures did produce the retained renderer-interval numbers, but the shared-load spread makes them inconclusive rather than evidence of no cost.

Not tested: the closed-menu frame-time comparison still awaits a quiet machine. Physical keyboard/clipboard on Linux, mouse/controller, IME, SDL2, Steam Deck, AMD/Intel, a real window on Linux, monitor changes, HDR, long sessions, or other gameplay areas. These checks used scripted input, authored display modes and bounded windowless scenes on this PC. Refusal/cancellation and empty-field behavior are covered game-free, not by these new game captures. No test request was posted during this move.

The current head has not been rebuilt or run in the game. Earlier build/game/syntax evidence retains its named sources. The three cross-target syntax captures stop before execution and do not reach the text test's later C-queue compile. No new hosted Windows check is claimed.

Needs other testers:

  • Windows x64: run the changed menu-key, text-field and screensaver fixtures, then type and paste 1920x800 in Custom output size, cancel once and commit once, expecting passing fixtures, input focus restored after cancellation and the saved size on the next start (request to open)

Screenshots

main @ d4a69456 / this PR @ 7677d2f1: baseline Graphics page, then partial text, caret, commit, listed choice and saved-size start.

New Longshot proof: main without the field; partial text; moved caret; committed custom size; a listed choice still available; the saved size after a new start.

this PR @ 7677d2f1: saved 1920x800 next start; the baseline is main @ d4a69456 in the first panel.

New Longshot 1920x800 start, both size rows agree and no restart-required marker remains.

main @ d4a69456 / this PR @ 7677d2f1: both interleaved pairs at the same saved scene; visual agreement does not settle the timing gap.

All four Longshot closed-menu runs reach the same saved forest scene; the differing timing results remain inconclusive.

Historical Hookshot @ 4914fdec: earlier edit/list-choice sequence, not a new Longshot or rebased-head run.

Historical Hookshot 4914fdec, 2026-11-12: six edit/list-choice steps before the rename. Not a new Longshot run.

Historical Hookshot @ 4914fdec: earlier saved-size start, not a new Longshot or rebased-head run.

Historical Hookshot 4914fdec, 2026-11-12: the saved-size start. The new Longshot proof above repeats this behavior.

Every listed picture was inspected. The earlier Hookshot evidence is retained with its original build identity, not used as a substitute for the new runs.

Risk and rollback

A stuck focus could withhold game/menu input; a mixed executable/renderer pair is rejected. ASCII-only entry is a deliberate limitation, not Unicode/IME support.

Stop editing with Esc/controller Back, then leave the menu to return input to the game; closing the menu also cancels the edit. Unset RX_VK_MENU_SCRIPT to stop scripted input. A committed size is restored by selecting the prior size and restarting; the running picture is not changed by an edit. There is no feature-disable switch: a full rollback reverts the paired host and renderer changes together and deploys a matching executable/renderer pair, rather than mixing API 21 and 22.

Dynamic output/shape lists and restart tracking are the other risk: a custom edit must not lose the startup size, reuse a stale shape index, or misreport a pending restart. The quiet closed-menu cost check remains open; the shared-load numbers are not a no-regression guarantee.

Reviewer notes

  • Start with API 22 in gpu/vk/vk_api.h and the positional vk_host initializer in host/rx_backend.c: take_text follows screen_size, while main's nvn_program_created, option 53 and existing callbacks remain intact.
  • In gpu/vk/vk_menu.cpp, read output_field_apply, output_choice_of, restart_value and the focused branch of menu_tick. Check dynamic custom_output/output_extras membership, the retained startup size, remapped shape/Later state, cancellation and persistence, rather than treating the old fixed list as current.
  • Read tests/test_menu_text_field.py alongside tests/test_menu_keys.py, tests/test_menu_restart_slots.py and tests/screensaver_test.c. Their source extraction boundaries changed with the implementation; existing checks are retained. The syntax-only receipt does not cover native Windows execution or the later C-queue compile.
  • This remains WIP, not a request to mark it ready. Functional evidence is complete for the stated scripted Linux scope and the current-head source suite is recorded above; closed-menu timing and untested platforms remain explicit.

Issues

Original pull request: https://github.com/NotRexed/Hookshot/issues/2594
Original proposal: https://github.com/NotRexed/Hookshot/issues/2269
Dependent co-op draft: https://github.com/NotRexed/Hookshot/issues/2274
No matching issue was found in Longshot's complete public issue list on 2026-11-12. These old numbers are not Forgejo issue numbers.

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. Runs and medians are above, but same-build spread is too large; the frame-time comparison awaits a quiet machine.
  • 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.
  • MKWVK_API_VERSION bumped (gpu/vk/vk_api.h's MkwVkHost or MkwVkRenderer changed).
  • A game-free test added for the fix, failing on main and passing here. Historical negative control retained; the test also passes in the exact-head full suite.
  • 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 built; current Windows full build not repeated. The Linux build is the historical build named above, not the current head.
  • Docs updated.

Moved from NotRexed/Hookshot#2594.

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 Players should be able to type a monitor size that the Insert menu does not list, without editing the options file. This also gives later text settings a shared editor rather than another keyboard handler. **Draft for one remaining runtime check:** the frame-time comparison awaits a quiet machine. The new Longshot menu and saved-size proof is complete; the shared-load comparison below is too variable to establish no cost while the menu is closed. The closed-menu timing limitation remains open. All earlier evidence below keeps its actually tested identity. ## What changed - Graphics gains **Custom output size**, with typing, caret movement, Backspace/Delete, Enter to commit, Esc to cancel, and first-line clipboard paste. Printable ASCII only: unsupported characters are left out because the menu's baked font does not cover them. - Text input is enabled only while a field has focus. A bounded, locked host queue connects Windows/SDL text events to the renderer. Controller confirm/back/paste and the menu's existing focus rules use the same editor. - A typed listed size reuses its choice; an unlisted size joins the appropriate shape's list. The screen-mode choices, monitor/native marks, restart tracking, preset exemption and saved `output_res=<width>x<height>` representation remain intact. - Renderer API **21 → 22**: `take_text` follows `screen_size` in both `MkwVkHost` and its positional initializer. Main's `nvn_program_created`, live frame-rate-cap option **53**, in-play Debug callbacks and Dev FPS level are retained. No numeric option ID is added or renumbered. The executable and renderer must come from the same build. - Existing source-reading fixtures are updated without removing their checks. The README, scripted-menu reference and tested configurations are updated. This answers Joey-Magnus's review of [the original change](https://github.com/NotRexed/Hookshot/issues/2594): [the display-mode work](https://github.com/NotRexed/Hookshot/issues/2566) is already in the base, and `custom_output`/`output_extras` are retained. The later program-created callback consumed API 21, so this addition correctly uses 22 rather than the review's then-next 21. Implementation map: `gpu/vk/vk_menu.cpp` owns `text_edit`, `output_field_apply`, `restart_value` and the focused `menu_tick` path; `host/rx_backend.c` owns `host_take_text` and the queue. `host/display.c`, `host/posix/display_sdl.c` and `host/hos_sdl.c` feed it. `gpu/vk/vk_api.h`, `gpu/vk/vk_menu_keys.h`, `gpu/vk/vk_ui.h` and `gpu/vk/menu_i18n.h` carry the interface, paste prompts and revised hint. `tests/test_menu_text_field.py`, `tests/test_menu_keys.py`, `tests/test_menu_restart_slots.py` and `tests/screensaver_test.c` carry the source-fixture coverage. ## Flags and settings The table covers changed behavior as well as newly introduced names. Runtime evidence remains the carried Linux/RTX 4090 evidence at `7677d2f12`; source contracts and untested interactions are not new runtime results. There is no new global enable switch, no new numeric option ID, and no new production command-line or build flag. | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `RX_VK_MENU_SCRIPT` | Changed existing environment switch: Adds `TYPE:text` up to the next comma and focused `HOME`, `END`, `BACK`, `DEL`, `LEFT`, `RIGHT`, `ENTER`, `ESC`; existing pad confirm/back events reach the field | Unset: no scripted menu input | Off by default: explicit test input only | Repeatable scripted typing/caret/commit on the Linux runs below | Physical-input validation or a quiet-machine guarantee | Native Windows input, SDL2, physical devices | | Custom output size | New Graphics menu row: Edits an unlisted size, selects an already listed size, or clears the custom choice; commits through `output_field_apply` and takes effect after restart | None; an existing unlisted saved size is shown instead. No field has text focus until editing begins | On after more testing: offer the editor, not a forced custom size; the closed-menu timing check is still open | Typed-size and saved-start Linux/RTX 4090 cases below | Unicode/IME entry or changing the running picture immediately | Windows, SDL2, physical keyboard/clipboard/controller, AMD/Intel, Steam Deck, real windows and monitor changes | | Output resolution | Changed menu integration and restart tracking: Reuses a listed typed size or offers the custom size; compares dimensions, not only the choice index, for restart tracking; preserves the startup size in the dynamic list | Base/fallback 2048x1152; existing saved choices, environment overrides and first-start Auto selection still apply | On by default: retain existing selection policy, not a new size default | Custom/listed transitions and saved 1920x800 start below | Removing the restart requirement or proving live monitor enumeration | Native Windows, physical displays, AMD/Intel, Steam Deck | | Aspect ratio | Changed interaction with typed output sizes: Follows the committed size's shape and remaps startup/Later state when the dynamic shape list changes | Monitor's shape (`ultrawide=1`); a non-16:9 output size retains its own shape | On by default: keep the existing default; only an explicit size edit changes the selection | The typed 1920x800/21:9-menu case and game-free dynamic-list cases | Proving physical monitor changes or HDR | Native Windows, real monitor changes, AMD/Intel, Steam Deck | | `output_res` | Existing ini key, now written by the text field: Keeps `widthxheight`, not a list index; accepted custom dimensions are rounded down to multiples of 8, at least 640x360, at most 5120x2880's pixels, from 5:4 to 48:9 | Missing/invalid value: the game's 2048x1152; saved values and existing Auto/environment selection remain applicable | Off by default: forced custom value: retain the saved/default choice | Persistent custom-size edits without hand-editing the ini | Live resizing; invalid sizes are refused in the editor and fall back when read from the file | Windows persistence, long sessions and other GPU vendors | | `ultrawide` | Existing ini key, changed through the new field's shape selection: Keeps the existing encoding: 1 follows the monitor, otherwise 0; another shape is represented by `output_res` | 1, monitor's shape | On by default: preserve the existing default and encoding | Keeping saved size and shape aligned after a typed edit | Unicode input or a new display-enumeration policy | Native Windows and physical monitor changes | | `HOS_OUTPUT_RES` | Existing environment override, new editor interaction: A committed text edit releases the menu's temporary override for saving, like the existing Output resolution row; it does not resize this process. Unset the launch override to test the saved value on the next start | Unset: no environment override | Off by default: explicit one-run override only | Preserving an explicit player edit; the new fixture covers the release call | Applying a saved size while the next launch still forces an environment value | End-to-end override/edit interaction in the new game captures; native Windows | | `tests/test_menu_text_field.py --cxx` | New test-driver CLI option: Selects the compiler driver for the extracted C++20 menu and C11 queue fixtures (`-x` selects the language) | `g++` for direct invocation; the whole-suite runner supplies its selected C++ compiler | Off by default: automatic run: an explicit game-free test command | Repeating the source fixtures with the selected compiler | Windows runtime or physical-input proof from a syntax-only capture | Native Windows execution of the changed fixtures | The README option table and custom-size explanation, plus `docs/development.md`'s scripted-input and options-file references, are updated. The test driver's `--cxx` usage is documented in its own module. `HOS_DISPLAY_MODES`, capture/timing switches, the Quality preset, Profile, frame-rate cap and screen-mode policy are unchanged; their values below are reproduction settings, not new defaults. ## Measurements <!-- branch-state --> Branch state: on main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`; head `d5b2ff117905fa9ad4a5def759efa52f7a5c1078`; 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 sole failure in both suites in the branch-state block is `tests/test_updater_asset_digest.py`: local .NET cannot resolve `Microsoft.AspNetCore.App.Ref (= 10.0.13)` (`NU1100`). The historical suites below also include this failure. main: d4a69456c9de5131589af1fcf9a09adba4c403d1 (measured baseline, 2026-11-12) this PR: menu-text-fields @ 7677d2f12e123fa79df8b3f6604b6fec7933bce2 (code built and tested, 2026-11-12) Previously submitted branch head: `70373b9a1c9cf106b49e82b7010360762c877c60`; code built and tested @ `7677d2f12e123fa79df8b3f6604b6fec7933bce2`. The final commit adds the measured configuration rows only. Between measured main `d4a69456` and main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`, changes are confined to forge scripts/workflow, documentation/rules and tests, not the host or renderer. The functional observations therefore remain relevant to the same runtime change, but all rows and outputs below retain their original measured commits. They are not reruns on the current head, and the noisy closed-menu observations do not become conclusive through a rebase. No new game build, Windows execution or game run is claimed for this rebase. Hardware: RTX 4090 24 GB, NVIDIA 615.78.08; Core i9-13900K, 96 GB RAM; Arch Linux 7.2.15-1-omarchy. Scene: title / Insert menu, 2048x1152 before editing; saved-size start at 1920x800. Closed-menu observations: child Link standing in Kokiri Forest from the same copied save, 1280x720, default 60 cap, game's upscaler, FG off, no overlays, windowless. Authored display modes 1920x1080 and 2560x1080, not physical monitor enumeration. Method: same release-profile build on both sides, rebuilt host and renderer; one baseline menu run, a 100 s scripted edit, then a separate 45 s start using its saved options. For the closed-menu comparison: one 80 s warm-up per build, then main/branch/main/branch, 80 s each; common 35–65 s renderer-frame windows, with the first boundary interval excluded. These headless CPU intervals follow offscreen submission; they are not GPU time or display latency. Whole game-free suite with the default compiler on the branch; the main suite is the day's shared pinned-base run. How to reproduce: 1. Use matched release/profile builds, with each executable and renderer from the same source; the retained comparison is main `d4a69456` against code `7677d2f1`. Keep separate disposable options/save storage, the game's upscaler, frame generation off and no overlays. The menu captures used precompile off (`RX_VK_PRECOMPILE=0`), windowless output, and authored `HOS_DISPLAY_MODES=1920x1080,2560x1080`, not physical display enumeration. 2. On main, open Insert → Graphics at 2048x1152 and observe that Output resolution is followed by Profile, with no Custom output size row. On this PR, use the sequence below; observe partial text and a moved caret before committing, then select listed 2560x1080 and 3440x1440, return through 2560x1080 to 1920x800, and compare each observed row with saved `output_res`. The retained edit is a 100 s scripted run; `RX_VK_MENU_SCRIPT` supplies the timed menu keys and `TYPE:text` actions documented above. 3. Start a separate 45 s process with those saved options and without `HOS_OUTPUT_RES`. Check the startup `picture 1920x800` / `camera ratio 2.4000` lines, both size rows, and the absence of a restart marker. 4. For the closed-menu comparison, use the same locally copied save with child Link standing in Kokiri Forest, 1280x720, Custom preset, 100% render resolution, default 60 cap, the game's upscaler and FG off. Record `RX_VK_FRAME_LOG` renderer CSVs; warm each build for 80 s, then run main/PR/main/PR for 80 s each. Read the same 35–65 s interval after excluding the first boundary interval. Keep every run and its load/journal receipt; the retained shared-load runs below fail the predeclared 5% same-build consistency rule. A quiet repeat is still needed, not a speed conclusion from these rows. 5. The new game-free driver is invoked as `python -I -B tests/test_menu_text_field.py --cxx g++`; the complete source suite is `python -I -B tests/run_all.py`. These are reproduction commands, not new receipts. The text-field driver has no `--source` option: a baseline comparison needs the corresponding pinned-source fixture setup, not an invented flag. **Try it:** Insert → Graphics → Custom output size → Enter → type `1920x800` → Enter. Closing the menu offers the existing restart question. This changes the saved size, not the running game's picture until its next start. | | main @ d4a69456 | this PR @ 7677d2f1 | |---|---|---| | Typed-size row | Absent | Typing, caret and commit visible | | Saved/listed size sequence | No typed entry | 1920x800 → 2560x1080 → 3440x1440 → 2560x1080 → 1920x800; every observed row agrees with saved dimensions | | Next start | Ordinary 2048x1152 baseline | Picture 1920x800; camera ratio 2.4000; both size rows 1920x800, no restart marker | | Whole game-free suite | 507 passed, 2 failed, 20 skipped | 509 passed, 1 failed, 20 skipped | | New field test on main's source | Fails: text API absent | Included and passing in the whole suite | ```text FAIL: vk_api.h: no HOS_TEXT_KEY and HOS_TEXT_OFF/ON/PASTE 507 passed, 2 failed, 20 skipped in 504 s (linux, 6 at once) 509 passed, 1 failed, 20 skipped in 315 s (linux, 6 at once) PASS: 3 captured translation units, 0 failures, 0 unjudged drivers/files; Windows execution NOT TESTED [hos host] longshot v2.2.0-rc.1-23-g7677d2f12 (source 3e2f2cc9) [hos host] oe: output resolution 1920x800 [hos host] boot: widescreen: picture 1920x800, scene 1440x600, camera ratio 2.4000, HUD and movies in the middle 74.1% output_res=1920x800 ``` The base suite was run once for all moved pull requests of this day, on that commit. The shared base also fails two bounded-time cases in `tests/test_appimage_package_retry.py`; that test passes on this branch. A duplicate base run completed before the shared-base policy: 507/2/20, with the same .NET failure and a shaderbatch-build error in `test_bake_skeleton.py`; both non-.NET checks pass here. No failed result was erased or relabelled green. These checks have not yet been run on a forge runner. All three new functional game runs ended at their requested bounds (game exit 124), with zero fatal, crash, device-loss, virtual-core-escape, kernel-fault and NVRM counts and complete journal coverage. The menu edit's load was 226.31 → 122.12; the saved start's 87.82 → 64.20. Neither duration nor frame rate from those captures is a performance measurement. **Closed-menu observations, under shared load — inconclusive.** The same-build spread is too large to say anything: median-frame repeat spread is 7.39% on main and 23.40% on the branch; mean-frame repeat spread is 15.00% and 29.36%. Both exceed the 5% same-build consistency rule set before reading the data. The branch's observed medians are higher, but these noisy runs do not establish causation or “no cost when off”. **The frame-time comparison awaits a quiet machine.** No run is discarded. | | main @ d4a69456 | this PR @ 7677d2f1 | |---|---|---| | Median frame time, run 1 / run 2 | 20.4535 / 18.9960 ms | 26.6860 / 33.7570 ms | | Median of those two medians | 19.72475 ms | 30.22150 ms | | Mean frame time, run 1 / run 2 | 22.5643 / 19.4150 ms | 25.8817 / 34.7887 ms | | Median of the two means | 20.98964 ms | 30.33518 ms | | One-minute load, run 1 before → after | 69.87 → 37.25 | 35.07 → 55.34 | | One-minute load, run 2 before → after | 35.57 → 17.46 | 13.15 → 41.44 | Actual reader output from the retained renderer CSVs, in run order: ```text base-closed-1: window=35..65s frames=1328 mean_ms=22.564300 median_ms=20.453500 p99_ms=37.158000 branch-closed-1: window=35..65s frames=1158 mean_ms=25.881656 median_ms=26.686000 p99_ms=44.379000 base-closed-2: window=35..65s frames=1545 mean_ms=19.414979 median_ms=18.996000 p99_ms=27.932000 branch-closed-2: window=35..65s frames=862 mean_ms=34.788704 median_ms=33.757000 p99_ms=48.366000 Same-build consistency within 5%: False ``` The game state and inspected pictures put all four runs in the same saved forest scene, with the menu closed. All four ended at their bounds with game exit 124, zero fatal/crash/device-loss/escape/kernel/NVRM counts and complete journal coverage. These observations meet the requested interleaving, not the evidence needed for a no-cost conclusion. ### Current-main source suite, separate from the historical runtime comparison Main ran the whole game-free suite once for all PRs using the branch-state block's base: `python -I -B tests/run_all.py --jobs 6 --strict`, default compiler, fresh HOME. It finished at 2026-11-12T19:12:28-06:00 under heavy shared load; the one-minute load after the run was 62.6. This is a source-suite receipt, not another game or frame-time measurement. The earlier `d4a69456`/`7677d2f1` tables and failures remain historical evidence at those exact identities. The refreshed branch's full suite ran 2026-11-12 19:10:40–19:16:36 local, using the repository default compiler and fresh HOME/XDG. Execution took 234 s on main and 247 s on the branch, not a performance comparison. No base suite was duplicated. ## Testing **Tested:** on this PC (Arch Linux, RTX 4090 with NVIDIA 615.78.08, i9-13900K), the current-head whole game-free suite; earlier text-field, menu-key, restart-slot and screensaver checks and the text-field negative control against main retain their measured commits above. Three translation units compiled for the Windows target; not run on Windows. In the game, compared main's title/Insert → Graphics page with scripted typing and caret movement on code `7677d2f1`, committed `1920x800`, switched through listed sizes and back, then started a separate process to check the saved picture size, both menu rows and absence of a restart marker. The retained closed-menu runs stood in Kokiri Forest with the same save and settings. Tested but not measured: the title/Insert-menu typing, caret, listed-choice and saved-size functional captures on main `d4a69456` and code `7677d2f1`, and the historical Hookshot `4914fdec` captures. Their durations and frame rates are not performance measurements. The closed-menu captures did produce the retained renderer-interval numbers, but the shared-load spread makes them inconclusive rather than evidence of no cost. **Not tested:** the closed-menu frame-time comparison still awaits a quiet machine. Physical keyboard/clipboard on Linux, mouse/controller, IME, SDL2, Steam Deck, AMD/Intel, a real window on Linux, monitor changes, HDR, long sessions, or other gameplay areas. These checks used scripted input, authored display modes and bounded windowless scenes on this PC. Refusal/cancellation and empty-field behavior are covered game-free, not by these new game captures. No test request was posted during this move. The current head has not been rebuilt or run in the game. Earlier build/game/syntax evidence retains its named sources. The three cross-target syntax captures stop before execution and do not reach the text test's later C-queue compile. No new hosted Windows check is claimed. **Needs other testers:** - Windows x64: run the changed menu-key, text-field and screensaver fixtures, then type and paste `1920x800` in Custom output size, cancel once and commit once, expecting passing fixtures, input focus restored after cancellation and the saved size on the next start (request to open) ## Screenshots **main @ d4a69456 / this PR @ 7677d2f1:** baseline Graphics page, then partial text, caret, commit, listed choice and saved-size start. ![New Longshot proof: main without the field; partial text; moved caret; committed custom size; a listed choice still available; the saved size after a new start.](https://git.magicbean.dev/attachments/e8484ef6-c70a-4d47-9f6e-605d7b219b17) **this PR @ 7677d2f1:** saved 1920x800 next start; the baseline is main @ d4a69456 in the first panel. ![New Longshot 1920x800 start, both size rows agree and no restart-required marker remains.](https://git.magicbean.dev/attachments/a120b38e-7e92-4051-84ab-38a0c94af1c5) **main @ d4a69456 / this PR @ 7677d2f1:** both interleaved pairs at the same saved scene; visual agreement does not settle the timing gap. ![All four Longshot closed-menu runs reach the same saved forest scene; the differing timing results remain inconclusive.](https://git.magicbean.dev/attachments/5c30c114-c538-454c-a7ea-de0420513299) **Historical Hookshot @ 4914fdec:** earlier edit/list-choice sequence, not a new Longshot or rebased-head run. ![Historical Hookshot `4914fdec`, 2026-11-12: six edit/list-choice steps before the rename. Not a new Longshot run.](https://git.magicbean.dev/attachments/f19b1508-b65e-4e5f-91c9-c4b35c3dac3f) **Historical Hookshot @ 4914fdec:** earlier saved-size start, not a new Longshot or rebased-head run. ![Historical Hookshot `4914fdec`, 2026-11-12: the saved-size start. The new Longshot proof above repeats this behavior.](https://git.magicbean.dev/attachments/a41fa04b-f4df-4ee1-af15-3affb96df43d) Every listed picture was inspected. The earlier Hookshot evidence is retained with its original build identity, not used as a substitute for the new runs. ## Risk and rollback A stuck focus could withhold game/menu input; a mixed executable/renderer pair is rejected. ASCII-only entry is a deliberate limitation, not Unicode/IME support. Stop editing with Esc/controller Back, then leave the menu to return input to the game; closing the menu also cancels the edit. Unset `RX_VK_MENU_SCRIPT` to stop scripted input. A committed size is restored by selecting the prior size and restarting; the running picture is not changed by an edit. There is no feature-disable switch: a full rollback reverts the paired host and renderer changes together and deploys a matching executable/renderer pair, rather than mixing API 21 and 22. Dynamic output/shape lists and restart tracking are the other risk: a custom edit must not lose the startup size, reuse a stale shape index, or misreport a pending restart. The quiet closed-menu cost check remains open; the shared-load numbers are not a no-regression guarantee. ## Reviewer notes - Start with API **22** in `gpu/vk/vk_api.h` and the positional `vk_host` initializer in `host/rx_backend.c`: `take_text` follows `screen_size`, while main's `nvn_program_created`, option 53 and existing callbacks remain intact. - In `gpu/vk/vk_menu.cpp`, read `output_field_apply`, `output_choice_of`, `restart_value` and the focused branch of `menu_tick`. Check dynamic `custom_output`/`output_extras` membership, the retained startup size, remapped shape/Later state, cancellation and persistence, rather than treating the old fixed list as current. - Read `tests/test_menu_text_field.py` alongside `tests/test_menu_keys.py`, `tests/test_menu_restart_slots.py` and `tests/screensaver_test.c`. Their source extraction boundaries changed with the implementation; existing checks are retained. The syntax-only receipt does not cover native Windows execution or the later C-queue compile. - This remains WIP, not a request to mark it ready. Functional evidence is complete for the stated scripted Linux scope and the current-head source suite is recorded above; closed-menu timing and untested platforms remain explicit. ## Issues Original pull request: https://github.com/NotRexed/Hookshot/issues/2594 Original proposal: https://github.com/NotRexed/Hookshot/issues/2269 Dependent co-op draft: https://github.com/NotRexed/Hookshot/issues/2274 No matching issue was found in Longshot's complete public issue list on 2026-11-12. These old numbers are not Forgejo issue numbers. ## 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. Runs and medians are above, but same-build spread is too large; the frame-time comparison awaits a quiet machine. - [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] `MKWVK_API_VERSION` bumped (`gpu/vk/vk_api.h`'s `MkwVkHost` or `MkwVkRenderer` changed). - [x] A game-free test added for the fix, failing on `main` and passing here. Historical negative control retained; the test also passes in the exact-head full suite. - [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 built; current Windows full build not repeated. The Linux build is the historical build named above, not the current head. - [x] Docs updated. --- Moved from NotRexed/Hookshot#2594. 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 Insert menu could not take typed text: a setting held as text, such as an
output size of the player's own, could only be set by editing
longshot_options.ini.

A text field is a row whose value is typed. Characters come from the window
(WM_CHAR on Windows, SDL's text input on Linux, turned on only while a field
has the keyboard) through a new MkwVkHost member, take_text, appended last
(MKWVK_API_VERSION 20, from 18; 19 is claimed by an open pull request). Left,
Right, Home, End, Backspace and Delete edit,
Ctrl+V and Shift+Insert paste the clipboard's first line, Enter sets the
text, Esc puts it back; a controller's confirm and back are Enter and Esc,
its D-pad moves the caret, a free face button pastes. A field holds printable
ASCII, as the menu's glyphs are baked; other characters are left out. While a
field has the keyboard no key does anything else, and the game gets none, as
for the whole menu. RX_VK_MENU_SCRIPT gains TYPE:<text> and the editing keys.

The first field is Custom output size on the Graphics tab: the Output
resolution of the player's own (output_res=), typed and checked by the same
rules, with the reason shown when a size is refused. As the row itself, it
leaves the Quality preset alone, and a size typed is the player's own from
then on, also in a run whose HOS_OUTPUT_RES holds the row (env_release).

Main's prompts_live (version 17) stays before take_text in both the interface
and the host table. tests/test_menu_text_field.py compiles the editor and the
host's queue cut from the source, and checks the wiring in the source: the
interface's take_text in its place in the host's table, WM_CHAR and SDL's text
input, the menu telling the host whether a field has the keyboard, TYPE.

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]>
Windows clang with Microsoft headers rejected getenv from hos_wide_size.h and sscanf from the extracted output parser as deprecated under -Werror. Put _CRT_SECURE_NO_WARNINGS on the first line of both generated C and C++ sources, matching the existing capture fixture convention. The screensaver fixture also needs the guard: its injected window procedure calls getenv twice. Runtime code, warning flags and every behavioral check stay unchanged.

Linux g++ and clang++ execute all three text-field checks; GCC and Clang pass all 18 mocked-window-procedure cases. Native LLVM-MinGW 23.1.5 Windows-target syntax with -Wall -Wextra -Werror -Wdeprecated-declarations and Microsoft-style getenv/sscanf annotations fails before and passes after. The three generated co-op tab fixtures pass that audit unchanged; restart-slot checks generate no C or C++. This is not a Windows runtime test. Refs #2594.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Main took version 20 for screen_size and version 21 for nvn_program_created while this rebase was being prepared. Append take_text after screen_size at version 22 and keep its fixture version check in step. Preserve both merged callbacks and their history comments. Reuse the SDL2 SDL_free lookup now supplied by the merged controller diagnostics instead of loading the same callback twice.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Record the two windowless runs built at 4914fdec on main 8cf9a524. The native build reused a completed lift only after both actual source-tree lift keys matched the recorded donor key. Keep the tested commit named explicitly: the later clean rebase onto main 15d4ae8c is checked game-free, not represented as another game run.

Assisted-by: GPT-6 Astra

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

Discussion carried over from NotRexed/Hookshot#2594

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-12 01:49 UTC (comment, original):

Rebased onto main (85e3df35 on 6f7ab2a7) and the Windows check repaired; the description's first block says what changed and what ran on the new head.

The Windows failure of the first run was in the test, not in the feature: tests/test_menu_text_field.py builds a fixture from the menu's source, which calls getenv (through host/hos_wide_size.h) and sscanf. Microsoft's headers mark both deprecated, and with warnings as errors the fixture did not compile on the Windows runner. The generated sources now start with _CRT_SECURE_NO_WARNINGS, like main's other fixtures; the screensaver test's template had the same trap and got the same line. I could only check this with a Windows-target syntax compile here, so the Windows job on this head is the proof.

The rebase met the merged Bug report row (NotRexed/Hookshot#2347) in two places in gpu/vk/vk_menu.cpp; both sides are kept. The game run in the description (typing a size, the caret, committing) was made before the rebase, on cefdafbb, and is labelled so.


mooki000, 2026-11-12 05:27 UTC (comment, original):

Rebased onto current main (edaef2a9) as faf1c9b1; nothing in what it does has changed.

  • gpu/vk/vk_api.h: NotRexed/Hookshot#1930 took API version 19 for the ocarina note bindings, so this one is 20 (it adds take_text at the end of the host table; all of main's ids are kept).
  • gpu/vk/vk_menu.cpp: merged without conflict beside NotRexed/Hookshot#2574's reset hook, NotRexed/Hookshot#2435's keyboard prompts and NotRexed/Hookshot#2347's Bug report row.
  • gpu/vk/menu_i18n.h: this change rewords one hint of the Output resolution row ("Your own size, from Custom output size below."), and since NotRexed/Hookshot#1864 every catalogue has that hint. Its entry is replaced in all 13 catalogues, none removed. The reworded translations were written with a language model on top of the existing ones; corrections are welcome.

The text-field, menu-key, restart-slot, translation and switch checks pass on the new head with GCC 16.2.1 and Clang 23.1.3; the Windows-target syntax pass of the changed host files has no error. The whole suite: 470 passed, 1 failed, 20 skipped; the one is test_input_background.py under Clang, which fails the same way on untouched main (a variable set and not used in a fixture this pull request does not touch).


Joey-Magnus, 2026-11-12 14:33 UTC (review: comment, original):

I merged this into current main. tests/test_menu_text_field.py (all three parts), test_menu_keys.py, test_menu_restart_slots.py, test_menu_i18n.py, test_output_resolution.py, test_menu_setting_walk.py, test_utf8_paths.py and test_env_on.py pass.

I checked the SDL event offsets by hand against SDL2's and SDL3's structs:

  • key down: scancode 24/16, keycode 28/20, mod 32/24
  • text event: a pointer at 24 on SDL3, inline at 12 on SDL2

All match. The SDL3 text pointer is copied right away in event_text. The queue in host/rx_backend.c:216 is locked and drops input while no field is focused. Text input is only on while a field has focus, so no input method window opens over the game.

The one thing in the way is NotRexed/Hookshot#2566. Both claim MKWVK_API_VERSION 20 for a new MkwVkHost member (take_text here, screen_size there). Merging NotRexed/Hookshot#2566 on top of this conflicts in vk_api.h, vk_menu.cpp, menu_i18n.h, rx_backend.c and readme.md. You've already offered to rebase if NotRexed/Hookshot#2566 goes first. In that case take_text goes after screen_size at version 21, and the Custom output size has to fit NotRexed/Hookshot#2566's per-screen list (custom_output/output_extras).


mooki000, 2026-11-12 14:34 UTC (comment, original):

Thanks for checking the event offsets by hand. Agreed on the order: NotRexed/Hookshot#2566 first. I am testing NotRexed/Hookshot#2566 on Linux now (its head ea303801), and I am preparing this branch on top of it so it can follow straight after: take_text after screen_size at API version 21, and the custom output size fitted to NotRexed/Hookshot#2566's per-screen list (custom_output / output_extras). I will push that rebase when NotRexed/Hookshot#2566 lands, with the tests you ran repeated on it.


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

Rebased onto 15d4ae8c6 now that NotRexed/Hookshot#2566 is merged; final head c102f6f5.
API 22: NotRexed/Hookshot#2566 took 20 for screen_size, and NotRexed/Hookshot#2760 took 21 for nvn_program_created; take_text follows screen_size.
A typed listed size reuses its choice. An unlisted size joins its shape's choices; NotRexed/Hookshot#2566's modes and monitor/native marks stay unchanged.
All 22 final checks pass with GCC 16.2.1 and Clang 23.1.3: the 19 requested checks, both changed NotRexed/Hookshot#2788 drivers, and the README check. A full run of the project's checks in my fork, Windows included, is green on this exact head.
Earlier full suite: 496 passed, 4 failed, 20 skipped. Two compiler-invocation failures passed after repair; the two main failures were subsequently fixed by NotRexed/Hookshot#2861 and NotRexed/Hookshot#2883.
The two game runs were on 4914fdec (main 8cf9a524), Linux/RTX4090, windowless.
The menu run typed 1920x800, moved the caret, committed, selected listed 2560x1080 and 3440x1440, then returned to the custom size; rows and saved sizes agree.
The next start logs picture 1920x800 and camera ratio 2.4000: NotRexed/Hookshot#2566's rule gives this non-16:9 size its own picture/camera shape; the row shows 21:9.
Both games exited 124 with zero fatal/crash/device-loss/kernel/NVRM/vcore-escape counts. A closing-pipe error in the first observer was recovered from existing receipts, without repeating that game.

The Graphics tab in six steps: 1. typing 1920x8 before committing, 2. the complete text with the caret moved inside, 3. Enter commits 1920x800 and the Aspect ratio becomes 21:9, 4. the custom size in Output resolution, 5. the next listed choice 2560x1080, 6. then 3440x1440

After the restart at 1920x800: Output resolution and Custom output size both read 1920x800, Aspect ratio 21:9

The final head adds a clean rebase over five merges, one touching the menu file, and a docs-only commit. That combination was checked game-free only, not run in the game.
Not tested: Windows gameplay, a real window, HDR, physical keyboard/clipboard/controller input, IME or SDL2. No performance claim.
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]

## Discussion carried over from NotRexed/Hookshot#2594 Every comment that was readable on [the original thread](https://github.com/NotRexed/Hookshot/pull/2594) 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-12 01:49 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2594#issuecomment-6811995888)): Rebased onto `main` (`85e3df35` on `6f7ab2a7`) and the Windows check repaired; the description's first block says what changed and what ran on the new head. **The Windows failure** of the first run was in the test, not in the feature: `tests/test_menu_text_field.py` builds a fixture from the menu's source, which calls `getenv` (through `host/hos_wide_size.h`) and `sscanf`. Microsoft's headers mark both deprecated, and with warnings as errors the fixture did not compile on the Windows runner. The generated sources now start with `_CRT_SECURE_NO_WARNINGS`, like main's other fixtures; the screensaver test's template had the same trap and got the same line. I could only check this with a Windows-target syntax compile here, so the Windows job on this head is the proof. **The rebase** met the merged Bug report row ([NotRexed/Hookshot#2347](https://github.com/NotRexed/Hookshot/issues/2347)) in two places in `gpu/vk/vk_menu.cpp`; both sides are kept. The game run in the description (typing a size, the caret, committing) was made before the rebase, on `cefdafbb`, and is labelled so. --- **mooki000**, 2026-11-12 05:27 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2594#issuecomment-6815519920)): Rebased onto current main (`edaef2a9`) as `faf1c9b1`; nothing in what it does has changed. - `gpu/vk/vk_api.h`: [NotRexed/Hookshot#1930](https://github.com/NotRexed/Hookshot/issues/1930) took API version 19 for the ocarina note bindings, so this one is 20 (it adds `take_text` at the end of the host table; all of main's ids are kept). - `gpu/vk/vk_menu.cpp`: merged without conflict beside [NotRexed/Hookshot#2574](https://github.com/NotRexed/Hookshot/issues/2574)'s reset hook, [NotRexed/Hookshot#2435](https://github.com/NotRexed/Hookshot/issues/2435)'s keyboard prompts and [NotRexed/Hookshot#2347](https://github.com/NotRexed/Hookshot/issues/2347)'s Bug report row. - `gpu/vk/menu_i18n.h`: this change rewords one hint of the Output resolution row ("Your own size, from Custom output size below."), and since [NotRexed/Hookshot#1864](https://github.com/NotRexed/Hookshot/issues/1864) every catalogue has that hint. Its entry is replaced in all 13 catalogues, none removed. The reworded translations were written with a language model on top of the existing ones; corrections are welcome. The text-field, menu-key, restart-slot, translation and switch checks pass on the new head with GCC 16.2.1 and Clang 23.1.3; the Windows-target syntax pass of the changed host files has no error. The whole suite: 470 passed, 1 failed, 20 skipped; the one is `test_input_background.py` under Clang, which fails the same way on untouched main (a variable set and not used in a fixture this pull request does not touch). --- **Joey-Magnus**, 2026-11-12 14:33 UTC (review: comment, [original](https://github.com/NotRexed/Hookshot/pull/2594#pullrequestreview-5876219864)): I merged this into current main. tests/test_menu_text_field.py (all three parts), test_menu_keys.py, test_menu_restart_slots.py, test_menu_i18n.py, test_output_resolution.py, test_menu_setting_walk.py, test_utf8_paths.py and test_env_on.py pass. I checked the SDL event offsets by hand against SDL2's and SDL3's structs: - key down: scancode 24/16, keycode 28/20, mod 32/24 - text event: a pointer at 24 on SDL3, inline at 12 on SDL2 All match. The SDL3 text pointer is copied right away in `event_text`. The queue in host/rx_backend.c:216 is locked and drops input while no field is focused. Text input is only on while a field has focus, so no input method window opens over the game. The one thing in the way is [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566). Both claim MKWVK_API_VERSION 20 for a new MkwVkHost member (`take_text` here, `screen_size` there). Merging [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) on top of this conflicts in vk_api.h, vk_menu.cpp, menu_i18n.h, rx_backend.c and readme.md. You've already offered to rebase if [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) goes first. In that case `take_text` goes after `screen_size` at version 21, and the Custom output size has to fit [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566)'s per-screen list (`custom_output`/`output_extras`). --- **mooki000**, 2026-11-12 14:34 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2594#issuecomment-6826508631)): Thanks for checking the event offsets by hand. Agreed on the order: [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) first. I am testing [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) on Linux now (its head `ea303801`), and I am preparing this branch on top of it so it can follow straight after: `take_text` after `screen_size` at API version 21, and the custom output size fitted to [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566)'s per-screen list (`custom_output` / `output_extras`). I will push that rebase when [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) lands, with the tests you ran repeated on it. --- **mooki000**, 2026-11-12 18:54 UTC (comment, [original](https://github.com/NotRexed/Hookshot/pull/2594#issuecomment-6832944729)): Rebased onto `15d4ae8c6` now that [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) is merged; final head `c102f6f5`. API **22**: [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566) took 20 for `screen_size`, and [NotRexed/Hookshot#2760](https://github.com/NotRexed/Hookshot/issues/2760) took 21 for `nvn_program_created`; `take_text` follows `screen_size`. A typed listed size reuses its choice. An unlisted size joins its shape's choices; [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566)'s modes and monitor/native marks stay unchanged. All 22 final checks pass with GCC 16.2.1 and Clang 23.1.3: the 19 requested checks, both changed [NotRexed/Hookshot#2788](https://github.com/NotRexed/Hookshot/issues/2788) drivers, and the README check. A full run of the project's checks in my fork, Windows included, is green on this exact head. Earlier full suite: 496 passed, 4 failed, 20 skipped. Two compiler-invocation failures passed after repair; the two main failures were subsequently fixed by [NotRexed/Hookshot#2861](https://github.com/NotRexed/Hookshot/issues/2861) and [NotRexed/Hookshot#2883](https://github.com/NotRexed/Hookshot/issues/2883). The two game runs were on `4914fdec` (main `8cf9a524`), Linux/RTX4090, windowless. The menu run typed `1920x800`, moved the caret, committed, selected listed `2560x1080` and `3440x1440`, then returned to the custom size; rows and saved sizes agree. The next start logs `picture 1920x800` and `camera ratio 2.4000`: [NotRexed/Hookshot#2566](https://github.com/NotRexed/Hookshot/issues/2566)'s rule gives this non-16:9 size its own picture/camera shape; the row shows 21:9. Both games exited 124 with zero fatal/crash/device-loss/kernel/NVRM/vcore-escape counts. A closing-pipe error in the first observer was recovered from existing receipts, without repeating that game. ![The Graphics tab in six steps: 1. typing 1920x8 before committing, 2. the complete text with the caret moved inside, 3. Enter commits 1920x800 and the Aspect ratio becomes 21:9, 4. the custom size in Output resolution, 5. the next listed choice 2560x1080, 6. then 3440x1440](https://gist.githubusercontent.com/mooki000/b86bd3f35969803fb032f71f035844f8/raw/df9b0b32e43d66b1ca6febca32b9d610703b701a/131-text-fields-rebased.jpg) ![After the restart at 1920x800: Output resolution and Custom output size both read 1920x800, Aspect ratio 21:9](https://gist.githubusercontent.com/mooki000/b86bd3f35969803fb032f71f035844f8/raw/df9b0b32e43d66b1ca6febca32b9d610703b701a/132-text-fields-saved-start.jpg) The final head adds a clean rebase over five merges, one touching the menu file, and a docs-only commit. That combination was checked game-free only, not run in the game. Not tested: Windows gameplay, a real window, HDR, physical keyboard/clipboard/controller input, IME or SDL2. No performance claim. Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <[email protected]>
Author
First-time contributor

Rebased 70373b9a onto main d725b3631 as d5b2ff117 and updated the description to the new template. Functional evidence, uploaded pictures and inconclusive shared-load rows retain measured commits d4a69456 and 7677d2f1; intervening main changes are scripts, documentation, rules and tests only. The exact rebased head's whole suite is 511 passed, 1 failed and 20 skipped; the sole failure is the same local .NET reference-pack failure as current main. This remains WIP until the closed-menu comparison can be made on a quiet machine.

Rebased 70373b9a onto main d725b3631 as d5b2ff117 and updated the description to the new template. Functional evidence, uploaded pictures and inconclusive shared-load rows retain measured commits d4a69456 and 7677d2f1; intervening main changes are scripts, documentation, rules and tests only. The exact rebased head's whole suite is 511 passed, 1 failed and 20 skipped; the sole failure is the same local .NET reference-pack failure as current main. This remains WIP until the closed-menu comparison can be made on a quiet machine.
mooki force-pushed menu-text-fields from 70373b9a1c to d5b2ff1179
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 2s
2026-11-13 01:32:00 +00:00
Compare
Author
First-time contributor

Added the Testing section and updated its checklist. Added one branch base/suite block, consolidated duplicate results and simplified the supporting wording; everything else is unchanged.

Added the Testing section and updated its checklist. Added one branch base/suite block, consolidated duplicate results and simplified the supporting wording; everything else is unchanged.
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 2s
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 'menu-text-fields:mooki-menu-text-fields'
git switch 'mooki-menu-text-fields'
Sign in to join this conversation.
No description provided.