CNA-BUG-133: DIRECTX9 implements the window-to-logical transform but never registers for its window, so mouse and touch input ignore it

CNA snapshot 3b43bd86  ·  Known Issues › Current bugs  ·  source links pinned to 3b43bd86

✓

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 3b43bd86; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

Input looks renderers up by window id through IGraphicsRenderer::GetForWindow; DIRECTX9 never calls RegisterForWindow, so Mouse::GetState, Mouse::SetPosition and touch pass raw window coordinates through under a virtual resolution, letterbox or display scale.

Identifier
CNA-BUG-133
Category
Bug
Subsystem
Input
Status
Open
Verified against
CNA 3b43bd86 (3b43bd8687ed46523d873f9bec4b32bd8481dcb5)
Severity
Medium (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(), Mouse::SetPosition(int, int) and TouchPanel positions on the DIRECTX9 renderer

Expected behaviour

IGraphicsRenderer.hpp states the registry rule: “Renderers that implement coordinate conversion register themselves here so input can map platform window-client coordinates”. EasyGL, SDL_GPU, WebGPU and FNA3D call RegisterForWindow.

Actual behaviour at TARGET

DirectX9Renderer.cpp implements TransformWindowToLogical and TransformLogicalToWindow (presentation geometry, letterbox, display scale; added by FULLSCREEN-002) but contains no RegisterForWindow call. window_to_logical and logical_to_window in Mouse.cpp and to_logical_position in SdlInputBridge.cpp find no renderer and return the window coordinate unchanged, so a game whose back buffer differs from the window size receives window pixels as game coordinates.

Source locations

Evidence

Checked by reading and by grepping every renderer source for RegisterForWindow at 3b43bd86; not executed (DIRECTX9 is Windows-only).

Re-verified at c6dec91f: RegisterForWindow is called by EasyGLRenderer.cpp, Fna3dRenderer.cpp, SdlGpuRenderer.cpp and WebGPURenderer.cpp only; DirectX9Renderer.cpp still implements both transforms. Not executed.

Focused reproduction

// Illustrative; not compiled or run. CNA_GRAPHICS_RENDERER=DIRECTX9,
// PreferredBackBuffer 800x480, window resized to 1600x960.
MouseState s = Mouse::GetState();
// Pointer at the window centre: expected (400, 240); actual (800, 480).

Current tests

MouseInputTests.cpp (CoordinateTransformPreservesLetterboxOffsetAndInverse) registers a test renderer by hand; IGraphicsRendererWindowRegistryTests.cpp tests the registry. No test checks that each renderer registers itself.

Regression test

A per-renderer check that constructing the renderer on a window makes GetForWindow(window) return it (the SDL_GPU constructor test already does this); the fix is to register after initialisation and unregister on destruction, as the other renderers do.

Blast radius

Games on DIRECTX9 whose window is not exactly the back-buffer size, including resizable and fullscreen-letterboxed windows: mouse, SetPosition and touch positions are wrong. Other renderers are unaffected.

Workaround

Keep the window at the back-buffer size, or scale mouse coordinates in the game.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

User guide
Input: mouse
Known issues
Bug index