Skip to content

feat(sokol/ios+tvos): GameController.framework source — detection + full state (Phase 1+3) #251

@apotema

Description

@apotema

Phase 1 + 3 (combined) of controller-support epic: labelle-toolkit/labelle-engine#609.

Goal

Controller support on iOS and tvOS (Apple TV) via Apple's GameController.framework (GCController) — both detection/removal and full button/axis state in one self-contained source. iOS is sokol-only (verified, same as Android), so it rides the same Phase 0 pollGamepadEvents abstraction.

Why this is combined (and cheap)

Unlike Android, GameController.framework is fully independent of sokol's event pipeline — it delivers events via NotificationCenter and exposes pollable state objects, so it never touches the AInputQueue sokol owns. That means:

  • No sokol-fork patch required (the expensive Android Phase-3 blocker doesn't exist here).
  • No mapping/quirk table — Apple normalizes every supported pad to the GCExtendedGamepad profile.

So Phase 1 (detect) and Phase 3 (state) collapse into a single issue for this platform.

Platform facts

  • GCController since iOS 7; iOS 13 / tvOS 13 added native Xbox Wireless + PlayStation (DualShock 4 → DualSense) over Bluetooth, alongside MFi.
  • Apple TV (tvOS) is the iOS-family analog of Android TV; Siri Remote surfaces as GCMicroGamepad.

Scope

Add an iOS/tvOS impl to the gamepad_source sub-package (the Phase 0 comptime fallback for sokol):

  1. Detection/removal: observe GCControllerDidConnect/GCControllerDidDisconnect notifications → push GamepadEvents into the ring buffer drained by the engine. Enumerate GCController.controllers() at startup. Populate name (vendorName), source_class (extended gamepad vs GCMicroGamepad/Siri Remote), type_hint.
  2. State: implement the poll methods (isGamepadButtonDown/Pressed, getGamepadAxisValue) against the connected controller's GCExtendedGamepad profile — buttons A/B/X/Y, shoulders, triggers, both thumbsticks, dpad. No semantic mapping needed (profile is already logical).
  3. Wire the sokol backend on iOS/tvOS to this source (engine fallback path from Phase 0).
  4. tvOS: handle Siri Remote as dpad_remote source class; respect the menu/play-pause buttons so they don't fight system navigation.

Known limitation

Acceptance criteria

  • iOS/tvOS: connect/disconnect emits GamepadEvents (incl. pre-connected at startup); no polling loop needed for detection.
  • Full button/axis state readable via the standard poll methods, no quirk table.
  • Siri Remote distinguished as dpad_remote; extended pads as gamepad.
  • No sokol-fork patch required (verify the framework path stays independent of sokol's event handling).

Non-goals

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions