emscripten: don't dispatch user input to hidden windows#15522
Merged
slouken merged 1 commit intoMay 20, 2026
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 onevent.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 callsSDL_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_UpdateMouseFocusthen setsmouse->focusto the hidden window. The nextSDL_PrivateSendMouseButtontagsevent.button.windowID = mouse->focus->idwith 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_HIDDENis justdisplay: noneon a (possibly shared) DOM canvas.Fix
Two early-returns in
src/video/emscripten/SDL_emscriptenevents.c, both gated on the runtimeSDL_WINDOW_HIDDENflag:Emscripten_UpdateMouseFromEvent: hidden windows neither update cursor position nor dispatch button events.Emscripten_HandleMouseFocus: hidden windows can't claimmouse->focusonpointerenter.Checking the flag at dispatch time (rather than gating handler registration) means a window that toggles between hidden and shown via
SDL_ShowWindow/SDL_HideWindowparticipates in input correctly while shown, with no re-registration needed.Testing
Manually verified on Chrome via
emrunusing 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.