macOS input improvements: control groups, Cmd-as-Ctrl, trackpad camera pan - #22
macOS input improvements: control groups, Cmd-as-Ctrl, trackpad camera pan#22redbeard wants to merge 4 commits into
Conversation
SDL3 has no DirectInput-style KEY_LOST, so modifier key-up events swallowed while unfocused (Cmd-Tab, Mission Control) left Alt/Ctrl stuck down and silently broke modifier hotkeys. Mirror the Win32 device-loss path by calling resetKeys() on SDL_EVENT_WINDOW_FOCUS_GAINED, and guard refreshAltKeys() against focus events arriving before the message stream exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SagePatch's SDL_PollEvent interposer consumed Ctrl+1..5 for window snapping, which silently swallowed the game's control-group assignment hotkeys on every launch that loads the patch. Cmd+Option+number is unbound in the game (Cmd now acts as Ctrl in-game, so bare Cmd+number must stay free for control groups too). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cmd+1..0 now assigns/uses control groups just like Ctrl+1..0, and Cmd works for every other Ctrl combo (force attack, etc). The physical Ctrl key keeps working unchanged. macOS only: on Linux the GUI scancode is the desktop's Super key and stays unmapped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Trackpad scrolls are distinguished from mouse-wheel notches by their precise fractional deltas and horizontal axis (with a 300ms latch for mid-gesture whole-number ticks), un-flipped per SDL's natural-scrolling direction flag, and carried as two extra arguments on the existing MSG_RAW_MOUSE_WHEEL message so UI listbox scrolling keeps working. LookAtXlat pans via userScrollBy using the same magnitude convention and speed options as the other scroll modes; Alt/Option + scroll zooms, since a trackpad has no discrete wheel, and real mouse wheels keep the classic zoom. Horizontal-only pan events skip the window manager so it does not misread zero vertical spin as a wheel-down. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SDL3 has no DirectInput-style KEY_LOST, so a modifier key-up that happens while the window is unfocused - Cmd-Tab, Mission Control, any app switch with a modifier held - never reaches the engine. Alt or Ctrl stays latched down afterwards and silently breaks every modifier hotkey, control groups included, until the key is pressed and released again. Reset keyboard state when focus returns, mirroring what the Win32 device loss path already does. Both games poll the same way, so both get it. resetKeys() calls refreshAltKeys(), which posts to TheMessageStream, and a focus event can land before that exists - so guard it. Without the guard this fix would trade a stuck modifier for a null dereference during startup. Found by redbeard, ammaarreshi PR ammaarreshi#22. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A trackpad had only the wheel's job: two fingers zoomed, and there was no way to push the camera around without going to the screen edge or the keyboard. Now two fingers pan, so the map follows the fingers. A trackpad has no detent to zoom with, so Alt/Option + scroll takes that job, and a real wheel is untouched and still zooms. The two cannot be mistaken for each other, because they are not being told apart - the gesture is simply reassigned per device. What is being told apart is the device: a trackpad reports precise fractional deltas and a horizontal axis, a wheel ticks in whole notches on Y alone, and a latch keeps the middle of a gesture from flipping back when a delta lands on a whole number. A high resolution mouse that reports the same way will pan rather than zoom; that is the known edge of the heuristic. Synthetic events are excluded outright, which redbeard's original does not do. The iOS touch translator turns a pinch into a wheel event, so it flows through exactly this code. It emits whole steps with no horizontal component and so classifies correctly on the arithmetic alone - but only by coincidence, and the latch could still catch a pinch right after a Magic Keyboard trackpad scroll and pan instead of zoom. SDL_TOUCH_MOUSEID states that the event did not come from a pointing device, so iPad pinch is safe by construction rather than by luck. Pan deltas ride along as two extra arguments on MSG_RAW_MOUSE_WHEEL, after the existing three, so anything reading only the first three is unaffected - which is how UI listbox scrolling keeps working. A sideways pan carries no vertical spin, and the window translator would read that zero as a wheel-down, so it lets those through to the camera instead. From redbeard, ammaarreshi PR ammaarreshi#22. Ported by hand rather than cherry-picked: the upstream merge unified LookAtXlat and WindowXlat into Core, so the logic lives once now instead of once per game. The one regression that review had flagged - taking the un-flipped value for wheelPos, inverting wheel zoom under natural scrolling - turned out to be moot, since this tree already un-flips there. Magnitude follows the other scroll modes: 120 * keyboardScrollFactor, scaled by the user's scroll speed options. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Confirming the diagnosis and the snap rebind on macOS (Apple Silicon, We hit exactly the symptom described — control groups 1-5 dead, 6-0 fine — and tracked it to the same cause: the Cherry-picked Scope caveat so this isn't read as more than it is: we took only that one commit, so this is not a signal on the other three (Cmd-as-Ctrl, focus-gain keyboard reset, trackpad camera pan) — those are untested on our side. Thanks for chasing it down — the root cause writeup made this a five-minute fix on our end. |
Summary
Four related macOS input fixes and features, found while chasing why Ctrl+number control groups were dead on Mac:
SDL_PollEventinterposer consumed Ctrl+1..5 for window snapping, silently swallowing the game's control-group hotkeys on everyrun.shlaunch (the dev run script doesn't load SagePatch, which made the bug look intermittent). Snap now lives on Cmd+Option+1..5.KEY_LOST, so modifier key-ups swallowed while Cmd-Tabbed away left Alt/Ctrl stuck down. Mirrors the Win32 device-loss reset.Testing
CREATE_TEAMmessages), trackpad pan verified in-game in all four directions, mouse-free zoom via Option+scroll, menus still scroll.GeneralsXZHandGeneralsXtargets build clean; shared Core changes keep the extra wheel-message arguments invisible to consumers that read only the first three.🤖 Generated with Claude Code