A game was playable standalone and completely dead under Studio — which is
exactly where it gets developed. The cause is structural, not a binding: an
app hosted by Studio is a child process with no window of its own, so the
OS hands controller input to Studio and never to it. On macOS the child
never even reaches `init_cx_os`, so `apple_game_input` is None and
`game_input_states()` returns an empty slice forever.
So controllers now travel the same road mouse and key events already do.
`StudioToApp::GameInput` carries the whole controller set; the run view
polls its own `game_input_states` on the tick it already uses to batch
messages, and the app lands them in `Cx::game_input_remote`, which
`game_input_states()` reads whenever `in_makepad_studio` is set.
Details worth knowing:
- Sent on change only. A pad at rest reports identical level state every
tick, and that is not worth the wire. The memo drops on focus loss so
regaining focus resends rather than assuming the app still holds it.
- Only the focused run view forwards, so two open run views cannot both be
driven by one stick. That is the rule the keyboard already follows.
- The set is replaced wholesale rather than merged, so a pad that unplugs
disappears by being absent instead of freezing at its last state.
- Wheels ride along with gamepads. Forwarding only pads would have left a
wheel silently dead under Studio while a pad worked, which is a worse
failure than both being dead.
- Linux gains controllers under Studio that it does not have standalone:
its native backend is a stub, but the forwarded path is platform-neutral.
The 21-field mapping lives in ONE place with both directions together.
Written per-side it would have drifted the first time a button was added —
one end gaining a field and the other quietly reporting zero for it. The
round-trip tests give every field a distinct value, because a fixture of
uniform numbers cannot detect two crossed wires, and the sticks are pinned
separately since flattening a Vec2 to scalars is where a swap would hide.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>