fix(display): publish coherent pointer and drawable samples #1428

Merged
Arkex-ai merged 5 commits from fix/pointer-coordinate-snapshot into main 2026-11-10 18:25:34 +00:00
Arkex-ai commented 2026-11-10 01:54:39 +00:00 (Migrated from github.com)

Pointer geometry and pending input cross from the window thread to the renderer/game threads. Independent coordinate, size and press fields can describe different events during movement or resize. Publish and consume one coherent sample instead.

Windows and SDL use a short locked mailbox. A press retains its event position and geometry until consumed, wheel fractions accumulate, and reset clears pending input. Windows game menus have a separate mailbox so they cannot consume Insert-menu input. Windows button events use signed client coordinates; captured movement/timer paths return before OS queries, and leave tracking is armed once per enter. SDL window queries stay on its main thread.

Merged main d224dc0680ad418b1ab111555c7d19cc483dcfdc in 8a6f1e5a0a18b1542265ce0ad1c2b994862c2f56, retaining the earlier fixes in 09685de. The only merge conflict was tests/run_all.py: the upstream runner is byte-identical, with RUN_ALL_ARGS declared in this PR's test. All seven pointer production/header/fixture files are byte-identical to the previous reviewed head. Main's API13 and ultrawide-menu callback are preserved.

Validation: pointer, screensaver and Windows startup checks pass. Full local suite: 278 passed / 3 failed / 20 skipped, versus 277 / 3 / 20 on this exact main. Failure names match: Windows disk-usage extended-path fixture, symlink privilege and MSVC headers. The expanded fixture covers independent mailboxes, event/poll divergence, resize, hidden-cursor wheel, capture/focus transitions and concurrent consumers. Prior four behavioral mutation results apply to the unchanged pointer source/fixture. No native game run of this merged head is claimed; integrated input/menu runtime still needs validation.

Fresh exact-head source, Windows Builder and AppImage workflows are being requested. Earlier greens belong to their recorded heads; the full local suite is not entirely green.

Pointer geometry and pending input cross from the window thread to the renderer/game threads. Independent coordinate, size and press fields can describe different events during movement or resize. Publish and consume one coherent sample instead. Windows and SDL use a short locked mailbox. A press retains its event position and geometry until consumed, wheel fractions accumulate, and reset clears pending input. Windows game menus have a separate mailbox so they cannot consume Insert-menu input. Windows button events use signed client coordinates; captured movement/timer paths return before OS queries, and leave tracking is armed once per enter. SDL window queries stay on its main thread. Merged main `d224dc0680ad418b1ab111555c7d19cc483dcfdc` in `8a6f1e5a0a18b1542265ce0ad1c2b994862c2f56`, retaining the earlier fixes in `09685de`. The only merge conflict was `tests/run_all.py`: the upstream runner is byte-identical, with `RUN_ALL_ARGS` declared in this PR's test. All seven pointer production/header/fixture files are byte-identical to the previous reviewed head. Main's API13 and ultrawide-menu callback are preserved. Validation: pointer, screensaver and Windows startup checks pass. Full local suite: **278 passed / 3 failed / 20 skipped**, versus **277 / 3 / 20** on this exact main. Failure names match: Windows disk-usage extended-path fixture, symlink privilege and MSVC headers. The expanded fixture covers independent mailboxes, event/poll divergence, resize, hidden-cursor wheel, capture/focus transitions and concurrent consumers. Prior four behavioral mutation results apply to the unchanged pointer source/fixture. No native game run of this merged head is claimed; integrated input/menu runtime still needs validation. Fresh exact-head source, Windows Builder and AppImage workflows are being requested. Earlier greens belong to their recorded heads; the full local suite is not entirely green.
hckrman101 (Migrated from github.com) approved these changes 2026-11-10 04:17:59 +00:00
hckrman101 (Migrated from github.com) left a comment

Looks good. The mailbox is correct: every read and write of the shared sample goes through one SRW lock (pthread rwlock on the POSIX shim), so no torn samples and no atomics/ordering subtleties to worry about. Presses OR together until a take, whole wheel notches are consumed and the remainder kept, and reset leaves the dimensions alone. On SDL, pointer_update runs on the main thread after every event and once per loop pass (4 ms wait), and RESIZED publishes before rx_resize, so the drawable-size callback is never more than a tick stale. The Windows and SDL paths match in behavior, the test is registered in tests/run_all.py with {cxx}, and the screensaver test stubs line up with the new wndproc calls. No settings option ids are touched.

The nits below are non-blocking. I can't see upstream CI on this head (approval-gated), so I'm relying on the fork runs you linked; the source-regressions run was still in progress in the description.

Looks good. The mailbox is correct: every read and write of the shared sample goes through one SRW lock (pthread rwlock on the POSIX shim), so no torn samples and no atomics/ordering subtleties to worry about. Presses OR together until a take, whole wheel notches are consumed and the remainder kept, and reset leaves the dimensions alone. On SDL, pointer_update runs on the main thread after every event and once per loop pass (4 ms wait), and RESIZED publishes before rx_resize, so the drawable-size callback is never more than a tick stale. The Windows and SDL paths match in behavior, the test is registered in tests/run_all.py with {cxx}, and the screensaver test stubs line up with the new wndproc calls. No settings option ids are touched. The nits below are non-blocking. I can't see upstream CI on this head (approval-gated), so I'm relying on the fork runs you linked; the source-regressions run was still in progress in the description.
@ -268,6 +305,7 @@ static LRESULT CALLBACK wndproc(HWND w, UINT msg, WPARAM wp, LPARAM lp) {
if (game_menu_open) menus_mouse(w, menu_open, 0);
hckrman101 (Migrated from github.com) commented 2026-11-10 04:17:59 +00:00

Nit: this now does TrackMouseEvent plus pointer_update (3x GetAsyncKeyState, WindowFromPoint, GetCursorPos, lock) on every WM_MOUSEMOVE, including while the mouse is captured for the camera, where the result is always inactive. A cheap early-out when mouse_captured (still clearing the sample once) would keep the hot path as light as before. TrackMouseEvent used to run only on the first move after leaving, too.

Nit: this now does TrackMouseEvent plus pointer_update (3x GetAsyncKeyState, WindowFromPoint, GetCursorPos, lock) on every WM_MOUSEMOVE, including while the mouse is captured for the camera, where the result is always inactive. A cheap early-out when mouse_captured (still clearing the sample once) would keep the hot path as light as before. TrackMouseEvent used to run only on the first move after leaving, too.
@ -45,24 +48,32 @@ void hos_mouse_give_back(int32_t dx, int32_t dy) {
}
hckrman101 (Migrated from github.com) commented 2026-11-10 04:17:59 +00:00

Nit: a menu click now takes its position from GetMouseState at pump time rather than from the event's x/y, so if the cursor moved within the same event batch the press can land at the later position. Probably invisible at a 4 ms poll, but worth knowing.

Nit: a menu click now takes its position from GetMouseState at pump time rather than from the event's x/y, so if the cursor moved within the same event batch the press can land at the later position. Probably invisible at a 4 ms poll, but worth knowing.
Arkex-ai (Migrated from github.com) reviewed 2026-11-10 11:24:13 +00:00
@ -268,6 +305,7 @@ static LRESULT CALLBACK wndproc(HWND w, UINT msg, WPARAM wp, LPARAM lp) {
if (game_menu_open) menus_mouse(w, menu_open, 0);
Arkex-ai (Migrated from github.com) commented 2026-11-10 11:24:13 +00:00

Addressed in e51cb58. Captured WM_MOUSEMOVE and periodic refresh now return before OS sampling or mailbox publication. The capture transition clears the sample once and cancels existing leave tracking; uncaptured moves arm TrackMouseEvent only when needed, retry on failure, and rearm after WM_MOUSELEAVE.

The fixture exercises the actual capture transition and window-message cases, including 100 captured moves plus periodic refresh with zero OS queries, and tracking/cancellation/retry assertions. The candidate passes and the corresponding compiled behavioral mutations fail. Exact-head fork source, Windows builder and Linux AppImage runs are all green; the description now links those runs.

Addressed in e51cb58. Captured WM_MOUSEMOVE and periodic refresh now return before OS sampling or mailbox publication. The capture transition clears the sample once and cancels existing leave tracking; uncaptured moves arm TrackMouseEvent only when needed, retry on failure, and rearm after WM_MOUSELEAVE. The fixture exercises the actual capture transition and window-message cases, including 100 captured moves plus periodic refresh with zero OS queries, and tracking/cancellation/retry assertions. The candidate passes and the corresponding compiled behavioral mutations fail. Exact-head fork source, Windows builder and Linux AppImage runs are all green; the description now links those runs.
Arkex-ai (Migrated from github.com) reviewed 2026-11-10 11:24:15 +00:00
@ -45,24 +48,32 @@ void hos_mouse_give_back(int32_t dx, int32_t dy) {
}
Arkex-ai (Migrated from github.com) commented 2026-11-10 11:24:15 +00:00

Addressed in e51cb58. SDL button-down now publishes the event's x/y. The mailbox also latches the first pending press position and its drawable geometry, so the normal post-event refresh cannot replace them with a later cursor position or resize before consumption. Press bits still OR together; the drawable-size callback continues to expose the latest dimensions, and the following pointer read returns the latest cursor sample.

The actual SDL button-event path is covered by an event/poll divergence regression with fractional 2x coordinates and an intervening resize, plus coalesced presses and focus-loss clearing. Both polling the click position and overwriting the pending point are detected by compiled mutation controls. Windows LLVM and Linux GCC fixtures pass, the changed Linux C units compile, and all three exact-head fork CIs are green. No additional native game or physical Linux-window test is claimed for this follow-up.

Addressed in e51cb58. SDL button-down now publishes the event's x/y. The mailbox also latches the first pending press position and its drawable geometry, so the normal post-event refresh cannot replace them with a later cursor position or resize before consumption. Press bits still OR together; the drawable-size callback continues to expose the latest dimensions, and the following pointer read returns the latest cursor sample. The actual SDL button-event path is covered by an event/poll divergence regression with fractional 2x coordinates and an intervening resize, plus coalesced presses and focus-loss clearing. Both polling the click position and overwriting the pending point are detected by compiled mutation controls. Windows LLVM and Linux GCC fixtures pass, the changed Linux C units compile, and all three exact-head fork CIs are green. No additional native game or physical Linux-window test is claimed for this follow-up.
hckrman101 (Migrated from github.com) reviewed 2026-11-10 16:20:46 +00:00
hckrman101 (Migrated from github.com) left a comment

Both earlier nits are fixed, thanks. Captured WM_MOUSEMOVE and the timer refresh now return before any OS query or lock (mouse_capture clears the mailbox on entry and cancels leave tracking), and TrackMouseEvent is armed once per enter. On SDL the click uses the event's x/y, and the latched press keeps that position and its geometry until the renderer takes it. The publish/take logic still looks right to me: every read and write of the sample, the press latch and the wheel happens under the one SRW lock, so there are no torn samples and no ordering to reason about. drawable_size reads under the shared lock, and RESIZED publishes before rx_resize. Upstream CI is green on this head.

What's blocking now is the merge with main. #1500 (mouse in the game's own menus) landed today and host/display.c conflicts in 4 hunks. The other files merge cleanly. The textual conflict is the easy part. The harder part is that #1500 is built on the ptr_x/ptr_y/ptr_w/ptr_h/ptr_in globals this PR removes:

  • hos_mouse_game_pointer (called on the game thread from oot_menu.c, Windows only) reads ptr_x/ptr_y/ptr_w/ptr_h/ptr_in directly. That's the same unsynchronized multi-field read this PR fixes for the Insert menu, so please don't bring the volatiles back for it. It should read the mailbox. It can't use hos_pointer_take, though, because that would consume the Insert menu's press and wheel. I see two options: a non-consuming shared-lock peek of point plus active, or (cleaner, I think) a second HosPointer for the game menus. With the second mailbox, game_menu_press publishes its press there and the game thread takes it, so game-menu clicks also get the event position and the press latch instead of a separate gm_pressed paired with whatever the latest position happens to be.
  • game_menu_press and menus_mouse (gm_mx = ptr_x) write or read ptr_x/ptr_y. In WM_MOUSEMOVE, the "moved since last time" check (gm_mx/gm_my, gm_mouse_used) can use the lp coordinates in locals. The if (mouse_captured) return 0; early-out is fine there, since the game menus release capture.
  • WM_MOUSEWHEEL needs to keep #1500's three-way routing (Insert, then gm_wheel, then play_wheel), with only the Insert branch going through pointer_update(w, 0, delta).
  • menus_mouse still clears ptr_pressed/ptr_wheel on every transition. Map that to hos_pointer_reset plus pointer_update, as menu_mouse does here.
  • tests/test_display_pointer.py pastes the WM_MOUSEMOVE case into the fixture. After the merge that body references game_menu_open, menu_open, gm_mx/gm_my and gm_mouse_used, so the fixture's win namespace will need stubs for them. screensaver_test.c merges cleanly, and its pointer_updates == 5 timer check still holds with #1500's WM_TIMER additions.

The Linux side isn't affected: #1500 didn't touch display_sdl.c, and the game-menu mouse in oot_menu.c is _WIN32 only.

The code at this head is good. I'll approve once it's merged with main and the game-menu path goes through the mailbox, so there's one coherent sample source on Windows rather than two.

Both earlier nits are fixed, thanks. Captured WM_MOUSEMOVE and the timer refresh now return before any OS query or lock (mouse_capture clears the mailbox on entry and cancels leave tracking), and TrackMouseEvent is armed once per enter. On SDL the click uses the event's x/y, and the latched `press` keeps that position and its geometry until the renderer takes it. The publish/take logic still looks right to me: every read and write of the sample, the press latch and the wheel happens under the one SRW lock, so there are no torn samples and no ordering to reason about. drawable_size reads under the shared lock, and RESIZED publishes before rx_resize. Upstream CI is green on this head. What's blocking now is the merge with main. #1500 (mouse in the game's own menus) landed today and `host/display.c` conflicts in 4 hunks. The other files merge cleanly. The textual conflict is the easy part. The harder part is that #1500 is built on the `ptr_x/ptr_y/ptr_w/ptr_h/ptr_in` globals this PR removes: - `hos_mouse_game_pointer` (called on the game thread from oot_menu.c, Windows only) reads `ptr_x/ptr_y/ptr_w/ptr_h/ptr_in` directly. That's the same unsynchronized multi-field read this PR fixes for the Insert menu, so please don't bring the volatiles back for it. It should read the mailbox. It can't use `hos_pointer_take`, though, because that would consume the Insert menu's press and wheel. I see two options: a non-consuming shared-lock peek of `point` plus `active`, or (cleaner, I think) a second `HosPointer` for the game menus. With the second mailbox, `game_menu_press` publishes its press there and the game thread takes it, so game-menu clicks also get the event position and the press latch instead of a separate `gm_pressed` paired with whatever the latest position happens to be. - `game_menu_press` and `menus_mouse` (`gm_mx = ptr_x`) write or read `ptr_x/ptr_y`. In WM_MOUSEMOVE, the "moved since last time" check (`gm_mx/gm_my`, `gm_mouse_used`) can use the lp coordinates in locals. The `if (mouse_captured) return 0;` early-out is fine there, since the game menus release capture. - WM_MOUSEWHEEL needs to keep #1500's three-way routing (Insert, then `gm_wheel`, then `play_wheel`), with only the Insert branch going through `pointer_update(w, 0, delta)`. - `menus_mouse` still clears `ptr_pressed/ptr_wheel` on every transition. Map that to `hos_pointer_reset` plus `pointer_update`, as `menu_mouse` does here. - `tests/test_display_pointer.py` pastes the WM_MOUSEMOVE case into the fixture. After the merge that body references `game_menu_open`, `menu_open`, `gm_mx/gm_my` and `gm_mouse_used`, so the fixture's `win` namespace will need stubs for them. screensaver_test.c merges cleanly, and its `pointer_updates == 5` timer check still holds with #1500's WM_TIMER additions. The Linux side isn't affected: #1500 didn't touch display_sdl.c, and the game-menu mouse in oot_menu.c is `_WIN32` only. The code at this head is good. I'll approve once it's merged with main and the game-menu path goes through the mailbox, so there's one coherent sample source on Windows rather than two.
@ -55,3 +57,3 @@
static int game_menu_open;
static volatile LONG64 game_menu_seen_ns;
static volatile LONG gm_pressed, gm_wheel;
static HosPointer game_pointer = HOS_POINTER_INIT;
hckrman101 (Migrated from github.com) commented 2026-11-10 16:20:46 +00:00

After merging main, #1500's game-menu reader (hos_mouse_game_pointer, game thread) needs a coherent source too. I'd suggest a second HosPointer for the game menus, or at least a shared-lock peek of this one, rather than restoring the ptr_* volatiles. Details in the review body.

After merging main, #1500's game-menu reader (`hos_mouse_game_pointer`, game thread) needs a coherent source too. I'd suggest a second `HosPointer` for the game menus, or at least a shared-lock peek of this one, rather than restoring the `ptr_*` volatiles. Details in the review body.
hckrman101 (Migrated from github.com) commented 2026-11-10 16:20:47 +00:00

Nit, the Windows twin of the SDL point: the click position now comes from GetCursorPos when the message is processed, not from the button-down's lp. lp is exact client coordinates for the click, so it could be fed through the same way pointer_publish_at does on SDL. It's very unlikely to be visible at message-pump latency, so non-blocking.

Nit, the Windows twin of the SDL point: the click position now comes from GetCursorPos when the message is processed, not from the button-down's lp. lp is exact client coordinates for the click, so it could be fed through the same way `pointer_publish_at` does on SDL. It's very unlikely to be visible at message-pump latency, so non-blocking.
Arkex-ai commented 2026-11-10 16:49:58 +00:00 (Migrated from github.com)

Addressed both findings in 09685de31e. This merges main snapshot 2877284a55 and preserves acf9dae and the earlier review fixes.

The game-menu reader now takes its own HosPointer, with coherent geometry, a latched press and fractional wheel. It makes no Windows queries and cannot consume Insert input. Both Windows button helpers publish the message's signed client coordinates. Movement detection uses local message coordinates; menu transitions/capture/focus clear pending state. Wheel routing keeps Insert priority, then the game menu (including while its cursor is hidden), then play_wheel.

Validation: the expanded Windows LLVM pointer fixture and 18-case screensaver fixture pass; the actual display.c compiles with C11 and -Wall -Wextra -Werror. The fixture exercises cross-thread game consumption, independent mailboxes, event/poll divergence plus resize, hidden-cursor wheel, transitions/capture/focus and the real wheel case. Four compiled behavioral mutations fail the intended assertions. The full local suite reports 254 passed / 6 failed / 22 skipped; all six failures reproduce on untouched main 2877284 (listed in the updated description).

Fork CI for this exact head is pending: source regressions, Windows builder, Linux AppImage. No new native game run or full integrated game link is claimed; native menu/input integration still needs a coordinated test. Earlier runtime evidence remains tied to its recorded hashes.

Addressed both findings in 09685de31e98ef4b6781f9b6b3196204186f05ee. This merges main snapshot 2877284a55f82f683ab975d51957441c45f46947 and preserves acf9dae and the earlier review fixes. The game-menu reader now takes its own HosPointer, with coherent geometry, a latched press and fractional wheel. It makes no Windows queries and cannot consume Insert input. Both Windows button helpers publish the message's signed client coordinates. Movement detection uses local message coordinates; menu transitions/capture/focus clear pending state. Wheel routing keeps Insert priority, then the game menu (including while its cursor is hidden), then play_wheel. Validation: the expanded Windows LLVM pointer fixture and 18-case screensaver fixture pass; the actual display.c compiles with C11 and -Wall -Wextra -Werror. The fixture exercises cross-thread game consumption, independent mailboxes, event/poll divergence plus resize, hidden-cursor wheel, transitions/capture/focus and the real wheel case. Four compiled behavioral mutations fail the intended assertions. The full local suite reports 254 passed / 6 failed / 22 skipped; all six failures reproduce on untouched main 2877284 (listed in the updated description). Fork CI for this exact head is pending: [source regressions](https://github.com/Arkex-ai/Hookshot/actions/runs/42858421003), [Windows builder](https://github.com/Arkex-ai/Hookshot/actions/runs/42858426695), [Linux AppImage](https://github.com/Arkex-ai/Hookshot/actions/runs/42858431454). No new native game run or full integrated game link is claimed; native menu/input integration still needs a coordinated test. Earlier runtime evidence remains tied to its recorded hashes.
hckrman101 commented 2026-11-10 17:49:17 +00:00 (Migrated from github.com)

Heads-up: this conflicts with main now (a lot landed today). Could you merge main into the branch (or rebase) and resolve the conflicts? Thanks!

Heads-up: this conflicts with main now (a lot landed today). Could you merge main into the branch (or rebase) and resolve the conflicts? Thanks!
Arkex-ai commented 2026-11-10 18:06:19 +00:00 (Migrated from github.com)

Merged main d224dc0680ad418b1ab111555c7d19cc483dcfdc into this branch at 8a6f1e5a0a18b1542265ce0ad1c2b994862c2f56. The only conflict was the old runner argument table; the new upstream runner is preserved byte-for-byte, and the pointer test declares its own arguments. The reviewed pointer production and fixture blobs are unchanged, including the separate game-menu mailbox and Windows event-coordinate fixes. Main’s API13/ultrawide callback is retained.

Three focused checks pass. Full local suite:278/3/20 versus277/3/20 on the exact base, with identical failure names; the description records their limits. Fresh exact-head fork checks were requested:

Native integration of this merged revision remains untested; no earlier-head runtime or CI result is presented as validation of this head.

Merged main `d224dc0680ad418b1ab111555c7d19cc483dcfdc` into this branch at `8a6f1e5a0a18b1542265ce0ad1c2b994862c2f56`. The only conflict was the old runner argument table; the new upstream runner is preserved byte-for-byte, and the pointer test declares its own arguments. The reviewed pointer production and fixture blobs are unchanged, including the separate game-menu mailbox and Windows event-coordinate fixes. Main’s API13/ultrawide callback is retained. Three focused checks pass. Full local suite:278/3/20 versus277/3/20 on the exact base, with identical failure names; the description records their limits. Fresh exact-head fork checks were requested: - [Game-free source regressions](https://github.com/Arkex-ai/Hookshot/actions/runs/42871740404) Native integration of this merged revision remains untested; no earlier-head runtime or CI result is presented as validation of this head.
hckrman101 (Migrated from github.com) approved these changes 2026-11-10 18:12:45 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks for the merge and the game-menu rework. Everything from the last round is addressed:

  • The game menus now have their own HosPointer (game_pointer). hos_mouse_game_pointer takes from it on the game thread, so it gets a coherent sample, the latched press position and the fractional wheel, without querying the window and without touching the Insert menu's press or wheel. pointer_publish_at gates the routing: Insert gets press and wheel only while menu_open, and the game mailbox is active only for game_menu_open && !menu_open. The ptr_* volatiles and gm_pressed/gm_wheel are gone.
  • WM_MOUSEWHEEL keeps #1500's order: the menus go through pointer_update, where Insert wins, then the game menu (hidden cursor included, return 2). Otherwise it falls back to play_wheel within the 200 ms window.
  • menus_mouse resets both mailboxes and republishes on every transition. The WM_MOUSEMOVE "moved" check uses the lp coordinates in locals, and the open-transition snapshot of gm_mx/gm_my reads the cursor directly.
  • Both button paths (menu_press, game_menu_press) publish the message's own client coordinates, so the nit is fixed too.
  • The fixture now pulls in hos_mouse_game_pointer, game_menu_press, menus_mouse and the real wheel case, with stubs for the #1500 state. It covers cross-thread game consumption next to an Insert sample, hidden-cursor wheel, the three-way wheel routing and stale input across transitions. test_display_pointer.py declares RUN_ALL_ARGS and doesn't touch run_all.py.

One small behaviour difference, not blocking: main counted game-menu wheel notches even when the cursor was outside the client area. Now they're dropped because the mailbox goes inactive. That seems right to me.

Upstream CI on 8a6f1e5 is still pending as I write this. If it shows the known main failures (test_recomplauncher_json, test_lift_cleanup_error, nx2/test_draw_parameters, nx2/test_nup_out_of_space), those aren't from this PR. As you said, native game-menu input on this merged revision hasn't been tested yet, so a quick in-game check of the pause/file-select menus on Windows before merging would be good.

Thanks for the merge and the game-menu rework. Everything from the last round is addressed: - The game menus now have their own `HosPointer` (`game_pointer`). `hos_mouse_game_pointer` takes from it on the game thread, so it gets a coherent sample, the latched press position and the fractional wheel, without querying the window and without touching the Insert menu's press or wheel. `pointer_publish_at` gates the routing: Insert gets press and wheel only while `menu_open`, and the game mailbox is active only for `game_menu_open && !menu_open`. The `ptr_*` volatiles and `gm_pressed`/`gm_wheel` are gone. - WM_MOUSEWHEEL keeps #1500's order: the menus go through `pointer_update`, where Insert wins, then the game menu (hidden cursor included, return 2). Otherwise it falls back to `play_wheel` within the 200 ms window. - `menus_mouse` resets both mailboxes and republishes on every transition. The WM_MOUSEMOVE "moved" check uses the lp coordinates in locals, and the open-transition snapshot of `gm_mx/gm_my` reads the cursor directly. - Both button paths (`menu_press`, `game_menu_press`) publish the message's own client coordinates, so the nit is fixed too. - The fixture now pulls in `hos_mouse_game_pointer`, `game_menu_press`, `menus_mouse` and the real wheel case, with stubs for the #1500 state. It covers cross-thread game consumption next to an Insert sample, hidden-cursor wheel, the three-way wheel routing and stale input across transitions. `test_display_pointer.py` declares `RUN_ALL_ARGS` and doesn't touch run_all.py. One small behaviour difference, not blocking: main counted game-menu wheel notches even when the cursor was outside the client area. Now they're dropped because the mailbox goes inactive. That seems right to me. Upstream CI on 8a6f1e5 is still pending as I write this. If it shows the known main failures (test_recomplauncher_json, test_lift_cleanup_error, nx2/test_draw_parameters, nx2/test_nup_out_of_space), those aren't from this PR. As you said, native game-menu input on this merged revision hasn't been tested yet, so a quick in-game check of the pause/file-select menus on Windows before merging would be good.
Commenting is not possible because the repository is archived.
No description provided.