feat(prompts): a Keyboard face: the keys and mouse buttons bound, in texts, hints and menus #2435

Merged
Needicla merged 3 commits from feat/keyboard-prompts into main 2026-11-12 03:04:39 +00:00
Needicla commented 2026-11-11 19:15:39 +00:00 (Migrated from github.com)

Players on the keyboard and mouse see a controller's buttons in every prompt (the Switch's when no controller is connected), so they have to work out which key each one means. This adds a Keyboard face to the Button prompts system: the game's texts, hints and menus show the key or mouse button each action is bound to.

Part of #1007 (keyboard button prompts, from #2028).

What it does

  • Button prompts → Keyboard (a seventh value). Auto picks it when no controller is connected, through SDL or XInput; with one connected, Auto picks that controller's face as before.
  • Each Switch button shows the first key bound to it on the Controls page, or the second when the first slot is clear. Mouse buttons show as a mouse with that button lit, and keys named by words (Ctrl, Alt, Esc, Home, PgUp, Num1...) as wider keys set in the game's own bold font. Kenney's versions of those are too small to read at prompt size.
  • The sticks' icons (Move, Change View and their direction variants) show WASD (or W/A/S/D, AD, WS) and the mouse moving.
  • It follows the live system from #2366: changing a key, or switching to or from Keyboard, shows at once, like a pad rebind.
  • Kept as the Switch's: the textures (ocarina notes, the letters on black, the pause menu's controller picture) and the Talk ring's places. The ocarina hint is spaced by the keys' icon widths.

How

  • nx2/prompt_keys.py (new, data only, standard library): which icon each key and stick shows, and the code points.
  • nx2/prompt_draw.py: the keyboard face's glyphs. They are Kenney's Input Prompts Keyboard & Mouse font (CC0, the same 1.5 release as the controller faces), in its own folder third_party/kenney_input_keyboard with a PROVENANCE.md and the release's License.txt; the AppImage copies it. The word keys and the mice are drawn as non-crossing contours, so they fill the same under either winding rule.
  • nx2/prompt_assets.py: faces_font builds the keyboard face (the Switch's pad icons, plus each key's icon at KEY_BASE + key code, past every face's code points), and writes its hint.bin per key code.
  • host/prompts.c:
    • The bind arrays carry each button's first key after its pad input (BINDS), so key changes go through the same live path.
    • cmap4_bind points a button at its key's icon on the keyboard face.
    • text_code gives a text a code of its own for each (button, key) pair as it first appears (key_slot), and points it at the key's icon where the game keeps the font.
    • Code points: the per-pair codes come from 320 codes at U+EEC0–U+EFFF, and the sticks' codes are at U+F8C0–U+F8DF. I checked every font in the romfs: none uses either range. The CJK fonts use most of the private use area, including parts of U+F700–U+F7BF.
  • host/nn_hid.c: hos_xinput_pads(), so Auto doesn't pick Keyboard for an XInput-only controller.
  • gpu/vk/vk_menu.cpp: the Keyboard value and its hint; pad_name names pad inputs by place on the keyboard face.

Testing

In game, a build of this branch (81a5445f, the same code before the rebases onto #2448 and #1990) on Windows 11 (native, RTX 4060), keyboard and mouse, no controller. Driven with the control bridge (HOS_CONTROL, headless, --user on a copy of the saves), into Hyrule Field from a save, then the pause menu:

Case Result
Auto, no controller ✅ prompts: auto: controller "(none)": keyboard, keyboard icons, 16 buttons on these keys. The pause menu shows Q/R on the tabs, the mouse for Rotate, E for Select, Shift for Back; the HUD's item buttons show R and X.
Keyboard picked, a key rebound (A from E to F) ✅ Select reads F.
Xbox picked (a pad face, unchanged by this PR) ✅ LB/RB, Select on B and Back on A (the pad layout in use); the ocarina hint spread for Xbox's icons.
A change while the game runs (Keyboard ↔ Xbox) ✅ with #2583: on native Windows #2366's live path never found the font (it read it 8 bytes past its start), with or without the keyboard face. @polackangry found it and fixed it in #2583, and with that on top of this branch, Keyboard → Xbox → Keyboard while the game runs applies at once (now the xbox icons in texts / now the keyboard icons in texts), the pause menu reopened showing each face's icons. Without #2583 the row says "(restart)" on native Windows, as for every face.
A pad plugged in and out, a key rebound with a hint on screen ⚠️ Not tested: no controller here, and both go through the live path.

Also:

  • tests/test_prompt_font_bind.py is extended. On the keyboard face it checks: keys bound in the first or second slot, a key with no icon, the sticks, and text codes for each (button, key) pair. The other faces are unchanged. It passes, as do prompts_live, appimage_prompt_fonts and menu_hooks.
  • tests/run_all.py: the same results with and without the PR on this machine (its other failures are missing .NET and MSVC-target C++ headers).

Screenshots

From the build of this branch, 1280×720 (the bridge's shots: the game's own picture).

Auto with no controller, the pause menu: Q/R tabs, the mouse for Rotate, E for Select, Shift for Back.

Auto, no controller: the pause menu with keyboard prompts

Keyboard with A rebound to F: Select reads F.

Keyboard face, A on F: Select reads F

Xbox, for comparison (a pad face, as before this PR).

Xbox face: LB/RB, B and A

The field: the HUD's item buttons on R and X.

Hyrule Field: the item buttons on R and X

🤖 Generated with Claude Code

Players on the keyboard and mouse see a controller's buttons in every prompt (the Switch's when no controller is connected), so they have to work out which key each one means. This adds a **Keyboard** face to the Button prompts system: the game's texts, hints and menus show the key or mouse button each action is bound to. Part of #1007 (keyboard button prompts, from #2028). ## What it does - **Button prompts → Keyboard** (a seventh value). **Auto** picks it when no controller is connected, through SDL or XInput; with one connected, Auto picks that controller's face as before. - Each Switch button shows the first key bound to it on the Controls page, or the second when the first slot is clear. Mouse buttons show as a mouse with that button lit, and keys named by words (Ctrl, Alt, Esc, Home, PgUp, Num1...) as wider keys set in the game's own bold font. Kenney's versions of those are too small to read at prompt size. - The sticks' icons (Move, Change View and their direction variants) show **WASD** (or W/A/S/D, AD, WS) and the mouse moving. - It follows the live system from #2366: changing a key, or switching to or from Keyboard, shows at once, like a pad rebind. - Kept as the Switch's: the textures (ocarina notes, the letters on black, the pause menu's controller picture) and the Talk ring's places. The ocarina hint is spaced by the keys' icon widths. ## How - `nx2/prompt_keys.py` (new, data only, standard library): which icon each key and stick shows, and the code points. - `nx2/prompt_draw.py`: the keyboard face's glyphs. They are Kenney's Input Prompts **Keyboard & Mouse** font (CC0, the same 1.5 release as the controller faces), in its own folder `third_party/kenney_input_keyboard` with a `PROVENANCE.md` and the release's `License.txt`; the AppImage copies it. The word keys and the mice are drawn as non-crossing contours, so they fill the same under either winding rule. - `nx2/prompt_assets.py`: `faces_font` builds the keyboard face (the Switch's pad icons, plus each key's icon at `KEY_BASE + key code`, past every face's code points), and writes its `hint.bin` per key code. - `host/prompts.c`: - The bind arrays carry each button's first key after its pad input (`BINDS`), so key changes go through the same live path. - `cmap4_bind` points a button at its key's icon on the keyboard face. - `text_code` gives a text a code of its own for each (button, key) pair as it first appears (`key_slot`), and points it at the key's icon where the game keeps the font. - Code points: the per-pair codes come from 320 codes at U+EEC0–U+EFFF, and the sticks' codes are at U+F8C0–U+F8DF. I checked every font in the romfs: none uses either range. The CJK fonts use most of the private use area, including parts of U+F700–U+F7BF. - `host/nn_hid.c`: `hos_xinput_pads()`, so Auto doesn't pick Keyboard for an XInput-only controller. - `gpu/vk/vk_menu.cpp`: the Keyboard value and its hint; `pad_name` names pad inputs by place on the keyboard face. ## Testing **In game, a build of this branch (81a5445f, the same code before the rebases onto #2448 and #1990)** on Windows 11 (native, RTX 4060), keyboard and mouse, no controller. Driven with the control bridge (`HOS_CONTROL`, headless, `--user` on a copy of the saves), into Hyrule Field from a save, then the pause menu: | Case | Result | |---|---| | Auto, no controller | ✅ `prompts: auto: controller "(none)": keyboard`, `keyboard icons, 16 buttons on these keys`. The pause menu shows Q/R on the tabs, the mouse for Rotate, E for Select, Shift for Back; the HUD's item buttons show R and X. | | Keyboard picked, a key rebound (A from E to F) | ✅ Select reads F. | | Xbox picked (a pad face, unchanged by this PR) | ✅ LB/RB, Select on B and Back on A (the pad layout in use); the ocarina hint spread for Xbox's icons. | | A change while the game runs (Keyboard ↔ Xbox) | ✅ with #2583: on native Windows #2366's live path never found the font (it read it 8 bytes past its start), with or without the keyboard face. @polackangry found it and fixed it in #2583, and with that on top of this branch, Keyboard → Xbox → Keyboard while the game runs applies at once (`now the xbox icons in texts` / `now the keyboard icons in texts`), the pause menu reopened showing each face's icons. Without #2583 the row says "(restart)" on native Windows, as for every face. | | A pad plugged in and out, a key rebound with a hint on screen | ⚠️ Not tested: no controller here, and both go through the live path. | Also: - `tests/test_prompt_font_bind.py` is extended. On the keyboard face it checks: keys bound in the first or second slot, a key with no icon, the sticks, and text codes for each (button, key) pair. The other faces are unchanged. It passes, as do `prompts_live`, `appimage_prompt_fonts` and `menu_hooks`. - `tests/run_all.py`: the same results with and without the PR on this machine (its other failures are missing .NET and MSVC-target C++ headers). ## Screenshots From the build of this branch, 1280×720 (the bridge's shots: the game's own picture). Auto with no controller, the pause menu: Q/R tabs, the mouse for Rotate, E for Select, Shift for Back. ![Auto, no controller: the pause menu with keyboard prompts](https://raw.githubusercontent.com/Needicla/Hookshot/pr-2435-screenshots/screenshots/branch-auto-pause.png) Keyboard with A rebound to F: Select reads F. ![Keyboard face, A on F: Select reads F](https://raw.githubusercontent.com/Needicla/Hookshot/pr-2435-screenshots/screenshots/branch-keyboard-rebound-pause.png) Xbox, for comparison (a pad face, as before this PR). ![Xbox face: LB/RB, B and A](https://raw.githubusercontent.com/Needicla/Hookshot/pr-2435-screenshots/screenshots/branch-xbox-pause.png) The field: the HUD's item buttons on R and X. ![Hyrule Field: the item buttons on R and X](https://raw.githubusercontent.com/Needicla/Hookshot/pr-2435-screenshots/screenshots/branch-field-hud.png) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Joey-Magnus (Migrated from github.com) reviewed 2026-11-11 20:08:41 +00:00
Joey-Magnus (Migrated from github.com) left a comment

This is a well-built addition. The keyboard face sits on top of the live prompt system from #2366 without disturbing the controller faces. The code-point ranges are checked against each other in tests/test_prompt_font_bind.py: KEY_BASE past every face, slots and sticks clear of BIND_BASE. Auto only falls back to Keyboard when the build actually made prompts/keyboard/, and the textures and the Talk ring stay on the Switch's, which is the safe choice. At the PR's head I ran prompt, bound_keys and menu_hit locally (7 checks), and all pass. On GitHub only the title check has run so far; the other workflows need a maintainer to approve them.

should fix, nx2/prompt_keys.py:61,69-70,120-121,144,191-194: CONTRIBUTING (Code and data conventions) accepts the prompt packages (fontTools, Pillow, astc-encoder-py, texture2ddecoder) "for nx2/prompt_assets.py and nx2/prompt_draw.py alone", and asks reviewers to flag any other use. This new module imports fontTools.pens.* and fontTools.ttLib. The imports are inside functions, so the tests still import it on the standard library alone, which is good. Either move the drawing into nx2/prompt_draw.py, which is where drawing lives, or have the maintainer agree to add prompt_keys.py to that list and update the sentence in CONTRIBUTING in this PR.

should fix (testing): the in-game test installed the new icons into a v2.1.0 build as the Switch face's font. That shows the artwork, but not this PR's host code: auto_face (host/prompts.c:119), the keyboard branch of cmap4_bind, key_slot and the slots kept across live_font (host/prompts.c:967 on), and the stick rewrites in text_code. Those are the parts that write into the game's font in memory while it runs. Please run a build of this branch once: with Keyboard picked, with Auto and no controller, then plug a pad in and out, and rebind a key while a hint is on screen. Note the result in the description. Screenshots from that build would be better than the transplanted ones.

question, third_party/kenney_input/: CONTRIBUTING says not to modify third_party/, and to add a new folder with its own provenance note rather than edit one. This adds an unmodified font from the same Kenney release to the existing folder and adds a line to its PROVENANCE.md. That seems within the spirit of the rule, but it's the maintainer's call. If not, third_party/kenney_input_keyboard/ with its own PROVENANCE.md and License.txt is the literal reading.

minor, host/prompts.c:53,967: the 320 slots are given out once per (button, key) pair for the whole run. Someone who rebinds a lot can use them up, and then key_slot silently falls back to the Switch's icon. A single hos_log the first time it runs out would make that easy to diagnose.

One heads-up: #1990, also open, raises HOS_PAD_N, which is the stride of the BIND_BASE codes this PR builds on. Whichever of the two lands second needs to re-check text_code and the slot/BIND_BASE overlap test.

This is a well-built addition. The keyboard face sits on top of the live prompt system from #2366 without disturbing the controller faces. The code-point ranges are checked against each other in `tests/test_prompt_font_bind.py`: `KEY_BASE` past every face, slots and sticks clear of `BIND_BASE`. Auto only falls back to Keyboard when the build actually made `prompts/keyboard/`, and the textures and the Talk ring stay on the Switch's, which is the safe choice. At the PR's head I ran `prompt`, `bound_keys` and `menu_hit` locally (7 checks), and all pass. On GitHub only the title check has run so far; the other workflows need a maintainer to approve them. **should fix**, `nx2/prompt_keys.py:61,69-70,120-121,144,191-194`: CONTRIBUTING (*Code and data conventions*) accepts the prompt packages (fontTools, Pillow, astc-encoder-py, texture2ddecoder) "for `nx2/prompt_assets.py` and `nx2/prompt_draw.py` alone", and asks reviewers to flag any other use. This new module imports `fontTools.pens.*` and `fontTools.ttLib`. The imports are inside functions, so the tests still import it on the standard library alone, which is good. Either move the drawing into `nx2/prompt_draw.py`, which is where drawing lives, or have the maintainer agree to add `prompt_keys.py` to that list and update the sentence in CONTRIBUTING in this PR. **should fix (testing)**: the in-game test installed the new icons into a v2.1.0 build as the Switch face's font. That shows the artwork, but not this PR's host code: `auto_face` (`host/prompts.c:119`), the keyboard branch of `cmap4_bind`, `key_slot` and the slots kept across `live_font` (`host/prompts.c:967` on), and the stick rewrites in `text_code`. Those are the parts that write into the game's font in memory while it runs. Please run a build of this branch once: with Keyboard picked, with Auto and no controller, then plug a pad in and out, and rebind a key while a hint is on screen. Note the result in the description. Screenshots from that build would be better than the transplanted ones. **question**, `third_party/kenney_input/`: CONTRIBUTING says not to modify `third_party/`, and to add a new folder with its own provenance note rather than edit one. This adds an unmodified font from the same Kenney release to the existing folder and adds a line to its `PROVENANCE.md`. That seems within the spirit of the rule, but it's the maintainer's call. If not, `third_party/kenney_input_keyboard/` with its own `PROVENANCE.md` and `License.txt` is the literal reading. **minor**, `host/prompts.c:53,967`: the 320 slots are given out once per (button, key) pair for the whole run. Someone who rebinds a lot can use them up, and then `key_slot` silently falls back to the Switch's icon. A single `hos_log` the first time it runs out would make that easy to diagnose. One heads-up: #1990, also open, raises `HOS_PAD_N`, which is the stride of the `BIND_BASE` codes this PR builds on. Whichever of the two lands second needs to re-check `text_code` and the slot/`BIND_BASE` overlap test.
Needicla commented 2026-11-11 20:39:23 +00:00 (Migrated from github.com)

Thanks for the careful review, @Joey-Magnus. Addressed in 81a5445f:

Prompt packages outside their files: nx2/prompt_keys.py is now data only (key → icon, the stick table, the code points) and imports nothing but the standard library. All the drawing (word keys, mice, keyboard_glyphs) moved into nx2/prompt_draw.py, so CONTRIBUTING's list stays as it is. The font built is glyph-for-glyph the same as before the move (checked on a v2.1.0 romfs).

third_party/: I went with the literal reading. The Keyboard & Mouse font is in third_party/kenney_input_keyboard/ with its own PROVENANCE.md and the release's License.txt; it's byte-identical to the one in the same 1.5A release as the controller fonts. third_party/kenney_input/ is back as it was. scripts/linux/appimage.sh copies the new folder, and tests/test_appimage_prompt_fonts.py now checks both.

Slots running out: key_slot logs once the first time all 320 are given out, saying a key bound from then on shows the Switch's icon in texts until the next start.

#1990: noted. Whichever lands second re-checks text_code and the slot/BIND_BASE range checks in test_prompt_font_bind.py. I'll do that here if #1990 goes in first.

Testing: agreed, the in-game run so far covered the artwork, not this branch's host code. I'll run a build of this branch through the four cases you list (Keyboard picked, Auto with no controller, a pad plugged in and out, a key rebound with a hint on screen), then update the description with the results and screenshots from that build.

run_all.py shows the same results with and without the PR on this machine; the prompt checks (prompt_font_bind, prompts_live, appimage_prompt_fonts) pass.

Thanks for the careful review, @Joey-Magnus. Addressed in 81a5445f: **Prompt packages outside their files**: `nx2/prompt_keys.py` is now data only (key → icon, the stick table, the code points) and imports nothing but the standard library. All the drawing (word keys, mice, `keyboard_glyphs`) moved into `nx2/prompt_draw.py`, so CONTRIBUTING's list stays as it is. The font built is glyph-for-glyph the same as before the move (checked on a v2.1.0 romfs). **`third_party/`**: I went with the literal reading. The Keyboard & Mouse font is in `third_party/kenney_input_keyboard/` with its own `PROVENANCE.md` and the release's `License.txt`; it's byte-identical to the one in the same 1.5A release as the controller fonts. `third_party/kenney_input/` is back as it was. `scripts/linux/appimage.sh` copies the new folder, and `tests/test_appimage_prompt_fonts.py` now checks both. **Slots running out**: `key_slot` logs once the first time all 320 are given out, saying a key bound from then on shows the Switch's icon in texts until the next start. **#1990**: noted. Whichever lands second re-checks `text_code` and the slot/`BIND_BASE` range checks in `test_prompt_font_bind.py`. I'll do that here if #1990 goes in first. **Testing**: agreed, the in-game run so far covered the artwork, not this branch's host code. I'll run a build of this branch through the four cases you list (Keyboard picked, Auto with no controller, a pad plugged in and out, a key rebound with a hint on screen), then update the description with the results and screenshots from that build. `run_all.py` shows the same results with and without the PR on this machine; the prompt checks (`prompt_font_bind`, `prompts_live`, `appimage_prompt_fonts`) pass.
Needicla commented 2026-11-11 21:21:20 +00:00 (Migrated from github.com)

@Joey-Magnus I ran a build of this branch (81a5445f) in game; the results and screenshots from that build are now in the description. Auto with no controller, Keyboard with a rebound key, and Xbox all show what they should at the start.

The live cases didn't run, for a reason outside this PR. @gab9281, this one may interest you (#2366): on native Windows 11 (RTX 4060, the v131072 game) the font part of the live prompts is never found. The textures' pool and the layouts are found:

prompts: the textures' pool at 0x7fc3005000 (+0xe86c000): a new face or new controls show at once
prompts: the layouts at 0x7fe1a31000: the Talk ring and the ocarina hint follow at once

But prompts: the font at ... never comes, even after the pause menu and its pages have drawn their button icons. So hos_prompts_live_parts() lacks HOS_PROMPTS_LIVE_TEXTS, the Button prompts row says "(restart)", and no change is applied live. The build logged the glyph hook as installed (oot_patches: the glyphs' hook in code_017.c).

To rule this PR out, I served a font built without the keyboard face (--faces switch,xbox,ps4,ps5,steamdeck, 33460 bytes, the size #2366 was tested at) to the same build: same result. Your Windows runs were under GE-Proton; this is native. My guess is that the face's stream there isn't the served file's size (base[1] != font.n && base[1] != font.n - 8 in hos_prompts_glyph), but I haven't confirmed it. I can run a build with a log line there if that helps.

@Joey-Magnus I ran a build of this branch (81a5445f) in game; the results and screenshots from that build are now in the description. Auto with no controller, Keyboard with a rebound key, and Xbox all show what they should at the start. The live cases didn't run, for a reason outside this PR. @gab9281, this one may interest you (#2366): on native Windows 11 (RTX 4060, the v131072 game) the font part of the live prompts is never found. The textures' pool and the layouts are found: ``` prompts: the textures' pool at 0x7fc3005000 (+0xe86c000): a new face or new controls show at once prompts: the layouts at 0x7fe1a31000: the Talk ring and the ocarina hint follow at once ``` But `prompts: the font at ...` never comes, even after the pause menu and its pages have drawn their button icons. So `hos_prompts_live_parts()` lacks `HOS_PROMPTS_LIVE_TEXTS`, the Button prompts row says "(restart)", and no change is applied live. The build logged the glyph hook as installed (`oot_patches: the glyphs' hook in code_017.c`). To rule this PR out, I served a font built without the keyboard face (`--faces switch,xbox,ps4,ps5,steamdeck`, 33460 bytes, the size #2366 was tested at) to the same build: same result. Your Windows runs were under GE-Proton; this is native. My guess is that the face's stream there isn't the served file's size (`base[1] != font.n && base[1] != font.n - 8` in `hos_prompts_glyph`), but I haven't confirmed it. I can run a build with a log line there if that helps.
gab9281 commented 2026-11-11 21:23:07 +00:00 (Migrated from github.com)

I don't have any windows PC anymore, sadly 😅

I don't have any windows PC anymore, sadly 😅
Joey-Magnus (Migrated from github.com) requested changes 2026-11-11 21:23:43 +00:00
Joey-Magnus (Migrated from github.com) left a comment

This will turn main red on merge. #2448 landed today with tests/test_prompt_auto_face.py:51, which requires choose_face to contain face_of_name(name). This PR changes that line in host/prompts.c to auto_face(name). Fix the test to look for auto_face(name) in choose_face and face_of_name(name) in auto_face.

Everything else looks right: all five bind[HOS_SW_N] arrays are widened to BINDS, the enum-only vk_api.h change needs no version bump, and the earlier points are addressed. Still pending: the promised in-game run (Auto with no pad, plugging a pad in and out, rebinding with a hint on screen) and a CI run, which hasn't happened on 81a5445f.

This will turn main red on merge. #2448 landed today with `tests/test_prompt_auto_face.py:51`, which requires `choose_face` to contain `face_of_name(name)`. This PR changes that line in `host/prompts.c` to `auto_face(name)`. Fix the test to look for `auto_face(name)` in `choose_face` and `face_of_name(name)` in `auto_face`. Everything else looks right: all five `bind[HOS_SW_N]` arrays are widened to `BINDS`, the enum-only `vk_api.h` change needs no version bump, and the earlier points are addressed. Still pending: the promised in-game run (Auto with no pad, plugging a pad in and out, rebinding with a hint on screen) and a CI run, which hasn't happened on 81a5445f.
Needicla commented 2026-11-11 21:24:52 +00:00 (Migrated from github.com)

I don't have any windows PC anymore, sadly 😅

No worries! I can't dig further on my side right now either. The log lines above are what a native Windows run shows. If someone with a Windows build wants to look, a log line in hos_prompts_glyph comparing the face's stream size (base[1]) with font.n should show whether it's the size check.

> I don't have any windows PC anymore, sadly 😅 No worries! I can't dig further on my side right now either. The log lines above are what a native Windows run shows. If someone with a Windows build wants to look, a log line in `hos_prompts_glyph` comparing the face's stream size (`base[1]`) with `font.n` should show whether it's the size check.
Needicla commented 2026-11-11 21:28:06 +00:00 (Migrated from github.com)

@Joey-Magnus thanks, good catch. Rebased onto main (with #2448), and in b3bb8743 tests/test_prompt_auto_face.py now looks for auto_face(name) in choose_face (and in live_face) and face_of_name(name) in auto_face. It also checks auto_face itself: with no controller, the keyboard's face when the build made it and XInput has no pad either, else the Switch's; with a controller's name, that controller's face. It passes, as do prompt_font_bind, prompts_live, appimage_prompt_fonts and menu_hooks. On this machine run_all.py shows the same results as main, apart from test_prepare_at_build's timing case, which failed once under the parallel run and passes on its own.

On the in-game run: it's in the description, from a build of 81a5445f, which is the same code before this rebase. Auto with no controller, Keyboard with a rebound key, and Xbox all show what they should at the start. The live cases (rebinding with a hint on screen, plugging a pad in and out) didn't run: on native Windows the font part of #2366's live path is never found, with or without the keyboard face (see the comment above), and I have no controller here. CI still needs a maintainer's approval to run.

@Joey-Magnus thanks, good catch. Rebased onto main (with #2448), and in b3bb8743 `tests/test_prompt_auto_face.py` now looks for `auto_face(name)` in `choose_face` (and in `live_face`) and `face_of_name(name)` in `auto_face`. It also checks `auto_face` itself: with no controller, the keyboard's face when the build made it and XInput has no pad either, else the Switch's; with a controller's name, that controller's face. It passes, as do `prompt_font_bind`, `prompts_live`, `appimage_prompt_fonts` and `menu_hooks`. On this machine `run_all.py` shows the same results as main, apart from `test_prepare_at_build`'s timing case, which failed once under the parallel run and passes on its own. On the in-game run: it's in the description, from a build of 81a5445f, which is the same code before this rebase. Auto with no controller, Keyboard with a rebound key, and Xbox all show what they should at the start. The live cases (rebinding with a hint on screen, plugging a pad in and out) didn't run: on native Windows the font part of #2366's live path is never found, with or without the keyboard face (see the comment above), and I have no controller here. CI still needs a maintainer's approval to run.
Joey-Magnus (Migrated from github.com) reviewed 2026-11-11 21:46:35 +00:00
Joey-Magnus (Migrated from github.com) left a comment

b3bb874 fixes what would have turned main red. The branch is rebased on #2448. tests/test_prompt_auto_face.py now looks for auto_face(name) in choose_face and live_face and for face_of_name(name) in auto_face, and it tests auto_face's keyboard cases. At the new head, test_prompt_auto_face, test_prompt_font_bind, test_prompts_live, test_appimage_prompt_fonts and test_menu_hooks all pass for me, and the branch merges cleanly with main.

The earlier points are done: the drawing is in prompt_draw.py, the font is in its own third_party/kenney_input_keyboard/ with provenance and license, and key_slot logs once when its codes run out. The in-game run covers Auto with no pad, a rebound key and a pad face. Plugging a pad in and out, and rebinding with a hint on screen, still weren't tested. Your comparison points to #2366's font lookup on native Windows rather than this PR; that deserves its own issue. What's left is a full CI run on b3bb874. The #1990 HOS_PAD_N heads-up still applies.

b3bb874 fixes what would have turned main red. The branch is rebased on #2448. `tests/test_prompt_auto_face.py` now looks for `auto_face(name)` in `choose_face` and `live_face` and for `face_of_name(name)` in `auto_face`, and it tests `auto_face`'s keyboard cases. At the new head, `test_prompt_auto_face`, `test_prompt_font_bind`, `test_prompts_live`, `test_appimage_prompt_fonts` and `test_menu_hooks` all pass for me, and the branch merges cleanly with main. The earlier points are done: the drawing is in `prompt_draw.py`, the font is in its own `third_party/kenney_input_keyboard/` with provenance and license, and `key_slot` logs once when its codes run out. The in-game run covers Auto with no pad, a rebound key and a pad face. Plugging a pad in and out, and rebinding with a hint on screen, still weren't tested. Your comparison points to #2366's font lookup on native Windows rather than this PR; that deserves its own issue. What's left is a full CI run on b3bb874. The #1990 `HOS_PAD_N` heads-up still applies.
hckrman101 commented 2026-11-11 22:55:53 +00:00 (Migrated from github.com)

This now conflicts with main in gpu/vk/vk_menu.cpp, host/prompts.c, readme.md, tests/test_prompt_font_bind.py. Could you merge main into the branch (or rebase) when you get a chance? I'll take another look once it's up to date.

This now conflicts with main in `gpu/vk/vk_menu.cpp`, `host/prompts.c`, `readme.md`, `tests/test_prompt_font_bind.py`. Could you merge main into the branch (or rebase) when you get a chance? I'll take another look once it's up to date.
polackangry commented 2026-11-12 00:15:46 +00:00 (Migrated from github.com)

Tested this branch (b3bb874) on native Windows 11 (RTX 5060 Ti, v131072), keyboard + mouse, through the control bridge:

  • Auto/Keyboard at the start: ✅ the load screen's Back shows Shift; the pause menu shows Q/R on the tabs, the mouse for Rotate, E for Select, Shift for Back.

The live part not finding the font on native Windows: found it. Your guess about the size check was close: the face's stream has the served file's size (55088 = font.n), so hos_prompts_glyph read from base + 8. But the font starts at base: the bytes at +8 were 00 03 00 30, the OpenType header's entrySelector/rangeShift, against the head 4f54544f ("OTTO"). It's in main's code from #2366, not this PR, so the fix is a separate PR: #2583.

With that fix on top of this branch, Keyboard → Xbox → Keyboard while the game runs applies at once (now the xbox icons in texts / now the keyboard icons in texts), and the pause menu reopened shows each face's icons.

Tested this branch (b3bb874) on native Windows 11 (RTX 5060 Ti, v131072), keyboard + mouse, through the control bridge: - Auto/Keyboard at the start: ✅ the load screen's Back shows Shift; the pause menu shows Q/R on the tabs, the mouse for Rotate, E for Select, Shift for Back. The live part not finding the font on native Windows: found it. Your guess about the size check was close: the face's stream has the served file's size (55088 = `font.n`), so `hos_prompts_glyph` read from `base + 8`. But the font starts at `base`: the bytes at `+8` were `00 03 00 30`, the OpenType header's `entrySelector`/`rangeShift`, against the head `4f54544f` ("OTTO"). It's in main's code from #2366, not this PR, so the fix is a separate PR: #2583. With that fix on top of this branch, Keyboard → Xbox → Keyboard while the game runs applies at once (`now the xbox icons in texts` / `now the keyboard icons in texts`), and the pause menu reopened shows each face's icons.
Needicla commented 2026-11-12 02:22:55 +00:00 (Migrated from github.com)

@hckrman101 rebased onto main (55b976c0); the branch is at 0a766623 and merges cleanly. The conflicts were all with #1990's second gamepad binding:

  • host/prompts.c: the keyboard branches in cmap4_bind and text_code now come before #1990's HOS_PAD_ART_N lines (a paddle still shows its default's icon on the pad faces). HOS_PAD_ART_N keeps the BIND_BASE stride at 17, so the keyboard face's code points don't move. The overlap checks in test_prompt_font_bind.py pass with six faces.
  • gpu/vk/vk_menu.cpp: pad_name keeps #1990's paddle names; the table has one more row, and the keyboard face names pad inputs by place.
  • tests/test_prompt_font_bind.py: #1990's paddle binding (Y on R4) and the keyboard face's keys are both tested.
  • readme.md: both entries kept.

prompt_font_bind, prompt_auto_face, prompts_live, appimage_prompt_fonts, menu_hooks and bound_keys pass. run_all.py matches main here, apart from three .NET builder checks that fail under the parallel run on this machine and pass on their own.

@polackangry thanks for testing it and for finding the font offset! I've added your live result with #2583 to the description.

@hckrman101 rebased onto main (55b976c0); the branch is at 0a766623 and merges cleanly. The conflicts were all with #1990's second gamepad binding: - `host/prompts.c`: the keyboard branches in `cmap4_bind` and `text_code` now come before #1990's `HOS_PAD_ART_N` lines (a paddle still shows its default's icon on the pad faces). `HOS_PAD_ART_N` keeps the `BIND_BASE` stride at 17, so the keyboard face's code points don't move. The overlap checks in `test_prompt_font_bind.py` pass with six faces. - `gpu/vk/vk_menu.cpp`: `pad_name` keeps #1990's paddle names; the table has one more row, and the keyboard face names pad inputs by place. - `tests/test_prompt_font_bind.py`: #1990's paddle binding (Y on R4) and the keyboard face's keys are both tested. - `readme.md`: both entries kept. `prompt_font_bind`, `prompt_auto_face`, `prompts_live`, `appimage_prompt_fonts`, `menu_hooks` and `bound_keys` pass. `run_all.py` matches main here, apart from three .NET builder checks that fail under the parallel run on this machine and pass on their own. @polackangry thanks for testing it and for finding the font offset! I've added your live result with #2583 to the description.
Commenting is not possible because the repository is archived.
No description provided.