feat(input): add a second gamepad binding in Controls #1990
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1990
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/gamepad-alternate-bindings"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
I wanted to roll with either the right face button or R4 on my Steam Controller. Hookshot currently lets you assign one gamepad button per action.
This adds Input 1 and Input 2 under Gamepad in the F1 Controls menu. Either input can trigger the action. Existing bindings load into Input 1, and Input 2 starts empty. The menu can also capture rear paddles such as R4 on supported controllers.
Testing
mainatbebb0c6(review round 1). The binding, prompt font, menu click, and touchpad tests pass.mainwith the same tools.Note
gpu/vk/vk_api.his now a host dependency on Windows too (it was Linux-only), so a change to it also rebuilds the host. The host readsHOS_PAD_Nfrom it.Screenshots
Current Controls layout at 1280 × 720
Steam Controller test on v2.0.14
AI disclosure
OpenAI Codex assisted with implementation and automated testing. Claude (Anthropic) assisted with the review changes.
Nice feature, and the core is solid. The binding table moved from
Interlocked*to an SRW lock, and that works on Linux through thehost/posix/windows.hshim. The ini format stays readable both ways: an older build'satoi("1,17")still reads slot 0. The paddles keep SDL3's order (right/left paddle 1, then 2), so R4/L4/R5/L5 are the right names. The tests are extended rather than weakened (test_bound_keys,test_menu_hit,test_touchpad_menu). The one red CI job (test_release_scriptson Ubuntu) is unrelated to this change.The problem is main. This branch is 69 commits behind and conflicts in
gpu/vk/vk_api.h,host/prompts.candtests/test_bound_keys.py. One of those conflicts needs more than picking a side:blocking,
gpu/vk/vk_api.h:47(HOS_PAD_N17 → 21) against main'shost/prompts.c: since #2366, the live button prompts give each Switch button × pad input a code point of its own, atBIND_BASE + (face * HOS_SW_N + b) * HOS_PAD_N + pad(text_codeon main).nx2/prompt_assets.pybuilds the font with a stride oflen(PADS)= 17. Once this PR raisesHOS_PAD_N, the game points texts at code points the font doesn't have at those places. I merged this branch into main locally, kept main'sprompts.c, and set the API version to 18:tests/test_prompt_font_bind.pythen fails withface 0: text code U+E041 became 61471, not 61467. When you rebase, keep the prompts' stride at the 17 inputs that have artwork. For example, give it its own constant (HOS_PAD_RTRIGGER + 1) intext_codeand anywhere elseprompts.cusesHOS_PAD_Nfor code points. Also make a paddle bound in slot 0 fall back toswitch_pad[b], as you did incmap4_bind(host/prompts.c:124here). The alternative is to add the paddles toPADSinprompt_assets.pyand draw artwork for them, but that's a bigger change.blocking,
gpu/vk/vk_api.h:18: main is atMKWVK_API_VERSION 17now, so this needs to become 18, not 15.question,
host/nn_hid.c:608-613(hos_bind): the old swap kept every button bound ("none left without"). With a second slot, binding an input that is already some button's only input into an empty Input 2 moves it there, becauseoldis -1. That button is then left with no gamepad input. For example, put Y's face button into A's Input 2, and Y becomes None. The menu does show it, so this may be what you want, but it's easy to do by accident on the face buttons. Should a slot-1 bind skip inputs that are another button's slot 0, or show a short note in the help box when it takes one?minor,
nx2/build.py:843: makingvk_api.ha host dependency on Windows too is right, now that the host readsHOS_PAD_N. It's worth one sentence in the description, since it changes rebuild behaviour beyond this feature.Thanks for the review! All points are addressed in
49371a5.To your question about
hos_bind: good catch, I went with blocking it. A slot-1 bind no longer takes an input that is another button's only gamepad input, so binding Y's face button into A's empty Input 2 does nothing and Y keeps it. If the other button also has an Input 2, the input is taken and that button's Input 2 moves up to Input 1, so no button is ever left unbound. The Controls help box mentions this in one sentence, andtest_bound_keys.pycovers both cases.The rest:
MKWVK_API_VERSION→ 18.HOS_PAD_ART_N(=HOS_PAD_RTRIGGER + 1, asserted againstPADSintest_prompt_font_bind.py). A paddle bound to Input 1 falls back toswitch_pad[b].vk_api.hhost-dependency change on Windows.Everything from my earlier review is fixed in
49371a5.MKWVK_API_VERSIONis 18. The prompt code points use the 17-input stride throughHOS_PAD_ART_Nintext_codeandcmap4_bind, with paddles falling back toswitch_pad[b]. A slot-1 bind no longer takes another button's only input. I merged it into today's main: no conflict, and run_all gives 376 passed, 0 failed.test_bound_keys,test_prompt_font_bind,test_touchpad_menuandtest_menu_hitall pass on their own too.There's a collision with #2435 (Keyboard prompt face) for whichever PR lands second. #2435 still indexes prompt code points by
HOS_PAD_Nintext_code(BIND_BASE + (face * HOS_SW_N + b) * HOS_PAD_N + pad). Once this PR makesHOS_PAD_N21, that has to becomeHOS_PAD_ART_Nor the font lookups shift. #2435 also adds aHOS_PROMPT_KEYBOARDrow, whilepad_namehere is sized[HOS_PROMPT_N + 1][HOS_PAD_RPADDLE1]. The keyboard row would then be all null pointers, so it has to keep #2435'sface < HOS_PROMPT_KEYBOARDguard. CI still needs approving for this fork.github-sync referenced this pull request2026-11-12 06:22:54 +00:00