CNA-BUG-134: Inside a letterbox bar, Mouse::GetState reports the raw window coordinate on renderers whose transform declines the point
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
EasyGL (every GL-family identity), SDL_GPU and WEBGPU decline points outside the presented rectangle, and Mouse and the input bridge then report the untransformed window coordinate, which can look like a valid game position. The presented rectangle is smaller than the window only under CnaPresentationMode::Letterbox (the default mode) when the window aspect differs from the back buffer's; Overscan, Stretch, NativeBackBuffer and FixedHeightDynamicWidth present a rectangle that covers the whole window, so only a pointer outside the window itself is declined there.
- Identifier
CNA-BUG-134- Category
- Bug
- Subsystem
- Input
- Status
- Open
- Verified against
- CNA
c1c316b9(c1c316b9c7a846ce8002809c151fcd1af14942c9) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- Mouse::GetState() and touch positions under a letterboxed or overscanned presentation
Expected behaviour
A mouse position should always be in one coordinate space. Vulkan returns the logical coordinate even outside the presented rectangle (negative or beyond the back buffer), so a game can tell the pointer is in a bar.
Actual behaviour at TARGET
WindowToLogical in GlPresentationSurfaceState.hpp (EasyGL) computes the logical coordinates and then returns windowX >= clientViewportX && ..., i.e. false inside a Letterbox bar; SDL_GPU and WebGPU do the same. On false, window_to_logical in Mouse.cpp leaves the output at the raw window coordinate, and to_logical_position in SdlInputBridge.cpp returns it too. With a 100-pixel left bar, a pointer at window x = 50 is reported as game x = 50, inside the playfield. Under Overscan the presented rectangle extends past every window edge, so in-window points always map.
Source locations
modules/renderers/easygl/include/CNA/Internal/Renderers/EasyGL/GlPresentationSurfaceState.hpp— WindowToLogical: returns false outside the viewportmodules/input/src/Xna/Mouse.cpp— window_to_logical keeps the raw coordinate on falsemodules/input/src/Internal/SdlInputBridge.cpp— to_logical_position returns the raw coordinate on falsemodules/renderers/vulkan/src/VulkanRenderer.cpp— TransformWindowToLogical returns true with out-of-range logical coordinates, for contrast
Evidence
Checked by reading every renderer's TransformWindowToLogical at c1c316b9; not executed.
Independent re-verification: Read every TransformWindowToLogical override and every RegisterForWindow call at c1c316b9; not executed. DIRECTX11 and METAL also decline outside the rectangle but never register for their window (CNA-BUG-133), so input never consults them; VULKAN, FNA3D and the SDL renderer return true without a range check; DIRECTX9's transform (added by FULLSCREEN-002) has no range check either, but DIRECTX9 never registers (CNA-BUG-133).
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
MouseInputTests.cpp tests the transform inside the presented rectangle only (CoordinateTransformPreservesLetterboxOffsetAndInverse).
Regression test
A test renderer that declines points in a bar, asserting that Mouse::GetState reports an out-of-range logical coordinate (or a documented clamp), never the raw one.
Blast radius
Letterboxed or overscanned windows on the renderers named (every EasyGL identity, SDL_GPU and WEBGPU); clicks in the bars land on game coordinates.
Workaround
Ignore mouse input while the window aspect differs from the back buffer, or compute the bars in the game.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Input: mouse
- Internals
- Input internals: mouse
- Deep dives
- Input model: logical coordinates
- Known issues
- Bug index