CNA-BUG-178: The SDL2 backend negates a flipped mouse wheel while SDL3 passes SDL's adjusted value through, so the two report opposite signs under natural scrolling
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.
Sdl2Platform negates wheel x/y on SDL_MOUSEWHEEL_FLIPPED, undoing the host's natural-scrolling preference, while Sdl3EventMapper passes SDL's adjusted value through; MouseWheelEvent is documented as the post-preference value.
- Identifier
CNA-BUG-178- Category
- Bug
- Subsystem
- Platforms
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - 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
- CNA::Platform::MouseWheelEvent::x / y ("scroll amount after the host's scrolling-direction preference")
Expected behaviour
PlatformEvent.hpp documents MouseWheelEvent::x and y as “scroll amount after the host's scrolling-direction preference.” The SDL3 backend meets that: Sdl3EventMapper copies source.wheel.x/y and comments that SDL “has already applied the host's natural-scrolling preference ... undoing it here would change the established FNA/CNA input behaviour.” Both backends should report the same sign.
Actual behaviour at TARGET
Sdl2Platform::PollEvents negates the deltas when source.wheel.direction == SDL_MOUSEWHEEL_FLIPPED. In SDL2, FLIPPED means the x/y values are already the natural-scrolling (inverted) ones and “Multiply by -1 to change them back”, so this negation reverts to the raw device direction, dropping the host preference the field is documented to keep. Under natural scrolling (where SDL2 sets FLIPPED, for example on macOS), the SDL2 and SDL3 backends therefore report opposite wheel signs for the same gesture.
Source locations
modules/platform/src/Sdl2/Sdl2Platform.cpp— PollEvents SDL_MOUSEWHEEL branch: negates x/y on SDL_MOUSEWHEEL_FLIPPEDmodules/platform/src/Sdl3/Sdl3EventMapper.cpp— SDL_EVENT_MOUSE_WHEEL branch: passes x/y through unchangedmodules/platform/include/CNA/Platform/PlatformEvent.hpp— MouseWheelEvent: value 'after the host's scrolling-direction preference'
Evidence
Checked by reading both event mappers and the MouseWheelEvent documentation at 009d40f5, and SDL2's SDL_MouseWheelDirection semantics (SDL2 SDL_events.h, release-2.30.x: “When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back”; the flag is set only on the Cocoa/UIKit natural-scrolling paths). Not executed on a host; the sign divergence follows from the two mappers' code, and the candidate is stated on the SDL2 page with that hedge.
Focused reproduction
No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.
Current tests
Sdl3EventMapperTests.cpp asserts SDL3 leaves both a NORMAL and a FLIPPED event unchanged. The SDL2 native-queue test does not assert wheel sign, and no test compares the two backends under FLIPPED.
Regression test
A mapper test that feeds a FLIPPED wheel event to both backends and requires the same sign; decide which convention is canonical (SDL3's pass-through matches the field's documentation) and make SDL2 match it.
Blast radius
Games run on the SDL2 backend by players who enabled natural scrolling (mainly macOS); their wheel input is inverted relative to the same game on SDL3 or the native backends.
Workaround
Prefer the SDL3 backend; a game can expose a scroll-inversion setting.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Input: mouse
- Deep dives
- The input model: mouse
- Known issues
- Bug index