fix(menu): keep the mouse free after Escape then F1 #2035

Merged
Arkex-ai merged 1 commit from fix/escape-mouse-capture into main 2026-11-11 02:46:07 +00:00
Arkex-ai commented 2026-11-11 00:42:29 +00:00 (Migrated from github.com)

Summary

With the default menu shortcut, Esc releases the mouse. Opening and closing the menu with F1 later could grab it again. F1 now restores capture only if the mouse was captured when F1 opened the menu. The opt-in Esc shortcut still restores the capture it released.

Closes #2031.

Technical changes

  • Send the opening shortcut with the existing menu-state message. Windows and SDL use it to decide whether to restore capture released by Esc.
  • Keep the opening reason and requested menu state in the same SDL atomic. Discard the remembered Escape capture on focus loss.

Validation

  • At 1519603d on d47206ed, the pointer fixture passed on Windows LLVM and Ubuntu Clang 18. It checks default Esc then F1, opt-in Esc, and F1 while captured on both host paths.

  • The Windows shortcut suite and all 18 window-procedure cases in the screensaver fixture passed. The first hosted Windows run found a stale two-argument test stub for the updated menu handler. The stub now matches the handler.

  • On the first revision, two negative controls independently reproduced stale recapture in the Windows and SDL host paths. In a Windows Kokiri smoke test at 600960cd, the default Esc-then-F1 sequence, direct F1, and opt-in Esc opening returned to gameplay. The run exited normally and preserved the original checkpoint hashes. Cursor confinement was asserted in the fixtures; the native run verified the menu transitions.

  • Both hosted Windows source shards pass at this head. Main includes the startup fixture fix from #2051.

Current-head check Result
Linux AppImage Passed
Windows build Passed
Source suite Passed
## Summary With the default menu shortcut, Esc releases the mouse. Opening and closing the menu with F1 later could grab it again. F1 now restores capture only if the mouse was captured when F1 opened the menu. The opt-in Esc shortcut still restores the capture it released. Closes #2031. ## Technical changes - Send the opening shortcut with the existing menu-state message. Windows and SDL use it to decide whether to restore capture released by Esc. - Keep the opening reason and requested menu state in the same SDL atomic. Discard the remembered Escape capture on focus loss. ## Validation - At `1519603d` on `d47206ed`, the pointer fixture passed on Windows LLVM and Ubuntu Clang 18. It checks default Esc then F1, opt-in Esc, and F1 while captured on both host paths. - The Windows shortcut suite and all **18 window-procedure cases** in the screensaver fixture passed. The first hosted Windows run found a stale two-argument test stub for the updated menu handler. The stub now matches the handler. - On the first revision, two negative controls independently reproduced stale recapture in the Windows and SDL host paths. In a Windows Kokiri smoke test at `600960cd`, the default Esc-then-F1 sequence, direct F1, and opt-in Esc opening returned to gameplay. The run exited normally and preserved the original checkpoint hashes. Cursor confinement was asserted in the fixtures; the native run verified the menu transitions. - Both hosted Windows source shards pass at this head. Main includes the startup fixture fix from #2051. <!-- pr-ci-status --> | Current-head check | Result | |---|---| | [Linux AppImage](https://github.com/NotRexed/Hookshot/actions/runs/42938158976) | Passed | | [Windows build](https://github.com/NotRexed/Hookshot/actions/runs/42938158986) | Passed | | [Source suite](https://github.com/NotRexed/Hookshot/actions/runs/42938158865) | Passed | <!-- /pr-ci-status -->
hckrman101 (Migrated from github.com) approved these changes 2026-11-11 02:17:35 +00:00
hckrman101 (Migrated from github.com) left a comment

Looks good. I traced it through the code and the logic holds.

  • menu_tick computes esc_opens in the same tick that flips open_now, so the lparam on WM_APP + 8 really means "this open came from the Esc shortcut". F1/Insert/pad opens send 0, so the stale esc_had_capture is dropped (Windows) or ignored (SDL, request == 2) as intended.
  • The opt-in Esc path is unchanged: WM_KEYDOWN/SDL key-down notes the capture before the menu thread sees the key, and the menu open consumes it.
  • Clearing esc_had_capture on WM_KILLFOCUS / FOCUS_LOST is the right call; otherwise a note from before an alt-tab could restore capture later.
  • Packing the reason into menu_asked (0 / 1 / 2) keeps the SDL request atomic, so state and reason can't be read torn. Default stays -1, menu_mouse(int request) handles it correctly.
  • Tests exercise both host paths for default Esc then F1, opt-in Esc, and F1 while captured. The screensaver stub signature was updated to match. All current-head checks are green.

No prior discussion on the PR to address. Nothing blocking.

Looks good. I traced it through the code and the logic holds. - `menu_tick` computes `esc_opens` in the same tick that flips `open_now`, so the lparam on WM_APP + 8 really means "this open came from the Esc shortcut". F1/Insert/pad opens send 0, so the stale `esc_had_capture` is dropped (Windows) or ignored (SDL, `request == 2`) as intended. - The opt-in Esc path is unchanged: WM_KEYDOWN/SDL key-down notes the capture before the menu thread sees the key, and the menu open consumes it. - Clearing `esc_had_capture` on WM_KILLFOCUS / FOCUS_LOST is the right call; otherwise a note from before an alt-tab could restore capture later. - Packing the reason into `menu_asked` (0 / 1 / 2) keeps the SDL request atomic, so state and reason can't be read torn. Default stays -1, `menu_mouse(int request)` handles it correctly. - Tests exercise both host paths for default Esc then F1, opt-in Esc, and F1 while captured. The screensaver stub signature was updated to match. All current-head checks are green. No prior discussion on the PR to address. Nothing blocking.
Commenting is not possible because the repository is archived.
No description provided.