CNA-GAP-067: ScrollWheelValue granularity depends on the platform backend: SDL3 drops sub-notch wheel motion, Win32 and Wayland keep it

CNA snapshot 009d40f5  ·  Known Issues › Functional gaps  ·  source links pinned to 009d40f5

✓

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

The SDL3 platform truncates every wheel event to whole notches before scaling by 120 (a deliberate FNA-parity rule recorded in docs/input-fna-fidelity.md), so high-resolution wheels and touchpads can scroll without changing ScrollWheelValue, while the Win32 and Wayland backends accumulate 1/120 units as XNA does. SDL delivers the fractional amounts and CNA discards them, so this is a narrower contract on the SDL3 backend, not a host constraint.

Identifier
CNA-GAP-067
Category
Functional gap
Subsystem
Input
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
MouseState::getScrollWheelValueProperty() and getHorizontalScrollWheelValueEXTProperty() as reported by Mouse::GetState()

Expected behaviour

XNA 4.0 on Windows adds the raw signed WM_MOUSEWHEEL delta to the wheel value (MouseMessageHooker.WndProc, decompiled reference), so a high-resolution wheel moves it in steps smaller than 120. The SDL3 backend deliberately follows FNA instead (cast to int before multiplying by 120), which is the documented and tested behaviour; the contract on SDL3 is whole notches.

Actual behaviour at TARGET

  • SDL3: Sdl3EventMapper.cpp passes SDL's float wheel.x/wheel.y, and AccumulateWheel in Sdl3InputServices.cpp converts each event to an integer number of notches before multiplying by 120. An event of 0.25 notch adds nothing, so a touchpad or smooth-scrolling wheel that reports fractions per event can leave ScrollWheelValue unchanged for a whole gesture.
  • Win32: Win32EventMapper::TranslateMouseWheel (Win32EventMapper.cpp) accumulates the raw WHEEL_DELTA units, as XNA does.
  • Wayland: AxisTo120 in WaylandMouse.cpp keeps the compositor's value120, so half a notch is 60.
  • X11 core wheel buttons are whole notches by nature (X11Mouse::AccumulateScroll).

input-fna-fidelity.md records the SDL3 truncation as an intentional FNA match that keeps the value “a clean multiple of 120 exactly like XNA”; XNA's own hook does not truncate, and the Win32 and Wayland backends do not either.

Source locations

Evidence

Checked by reading at 009d40f5; not executed. The XNA behaviour was read from the decompiled XNA 4.0 MouseMessageHooker, FNA's from FNA-XNA/FNA b3551247. Each backend's rule is pinned by its own test (Sdl3MouseTest, Win32EventMapping.WheelTotalsAccumulateInXnaUnits, WaylandWheelMapping), so the difference is deliberate per backend, not accidental. Whether a given touchpad reports sub-notch events through SDL depends on the host and was not observed.

Independent re-verification: Checked by reading at 009d40f5; not executed. Each backend's rule is pinned by its own test (Sdl3MouseTest, Win32EventMapping.WheelTotalsAccumulateInXnaUnits, WaylandWheelMapping). Whether a given touchpad reports sub-notch events through SDL depends on the host and was not observed.

Focused reproduction

No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.

Current tests

Sdl3InputServicesTests.cpp pins the truncation (1.9 notches count as one), Win32EventMapperTests.cpp whole-notch accumulation and WaylandMappingTests.cpp the half notch. No test states a cross-backend rule.

Regression test

If one rule is chosen, a backend-neutral conformance case: two half-notch wheel events must change ScrollWheelValue by the same amount (120, or 60 and 60) on every backend.

Blast radius

Games that read ScrollWheelValue for zoom or scrolling on the SDL3 backend with touchpads or free-spinning wheels, and games whose behaviour differs between the SDL3 and native Win32 or Wayland builds.

Workaround

None inside the XNA surface; a game that needs smooth scrolling on SDL3 has to read wheel events itself.

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

User guide
Input: mouse