Skip to content

emscripten: don't dispatch user input to hidden windows#15522

Merged
slouken merged 1 commit into
libsdl-org:mainfrom
vittorioromeo:emscripten-hidden-window-input-gate
May 20, 2026
Merged

emscripten: don't dispatch user input to hidden windows#15522
slouken merged 1 commit into
libsdl-org:mainfrom
vittorioromeo:emscripten-hidden-window-input-gate

Conversation

@vittorioromeo

Copy link
Copy Markdown
Contributor
  • I confirm that I am the author of this code and release it to the SDL project under the Zlib license. This contribution does not contain code from other sources, including code generated by a Large Language Model ("AI").

DISCLAIMER: AI assistance was used to identify and understand the bug. The fix was hand-written.

Summary

When two SDL_Windows share the same DOM canvas on Emscripten (e.g. a visible main window alongside a hidden 1×1 window for a shared GL context -- same setup as #15511), mouse button events end up tagged with the hidden window's ID and are silently dropped by code that filters events on event.button.windowID. Symptom: a single physical click behaves as if held down, because the release event never reaches the application.

Details

Both windows register pointer-event listeners on #canvas; both fire on every event.

Each calls SDL_SendMouseMotion(window_data->window, ...), which calls SDL_UpdateMouseFocus.

The motion coordinates are pre-scaled by window->w / canvas_css_w -- so for the hidden 1×1 window, a real cursor at canvas pixel 800 becomes 0.625, which is inside [0, 1).

SDL_UpdateMouseFocus then sets mouse->focus to the hidden window. The next SDL_PrivateSendMouseButton tags event.button.windowID = mouse->focus->id with the hidden window's ID.

Other SDL backends (Win32, Cocoa, X11, Wayland) get an invariant for free: the OS doesn't deliver input events to non-visible windows. Emscripten has no such invariant -- SDL_WINDOW_HIDDEN is just display: none on a (possibly shared) DOM canvas.

Fix

Two early-returns in src/video/emscripten/SDL_emscriptenevents.c, both gated on the runtime SDL_WINDOW_HIDDEN flag:

  • Emscripten_UpdateMouseFromEvent: hidden windows neither update cursor position nor dispatch button events.

  • Emscripten_HandleMouseFocus: hidden windows can't claim mouse->focus on pointerenter.

Checking the flag at dispatch time (rather than gating handler registration) means a window that toggles between hidden and shown via SDL_ShowWindow / SDL_HideWindow participates in input correctly while shown, with no re-registration needed.

Testing

Manually verified on Chrome via emrun using the same multi-window setup as #15511.

Notes

This PR is a follow-up to #15511: same VRSFML hidden-window-for-shared-GL-context pattern.

Similarly, this PR is also related to #12512.

@slouken slouken added this to the 3.4.10 milestone May 20, 2026
@slouken slouken merged commit 35098e9 into libsdl-org:main May 20, 2026
46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants