Skip to content

Linux gamepad via udev: add a STATE API to gamepad_source/linux.zig (so Linux desktop needn't link SDL) #33

@apotema

Description

@apotema

Summary

Give src/gamepad_source/linux.zig a full gamepad STATE surface (buttons/axes/pump), so Linux desktop gamepad can run on the existing evdev/udev source with no SDL dependency — the intended end-state from the core#28 slice-5 decision (SDL opt-out by default on desktop; Linux uses udev). Today this is deferred because it can't be runtime-verified without bare-metal Linux hardware and would replace the working SDL Linux path.

Tracked locally as a deferred follow-up of core#28; filing it so it survives as a real issue.

Current state

  • gamepad_source/linux.zig is detection-only: it opens each /dev/input/event* node just long enough to read identity (EVIOCGID/EVIOCGNAME) then closes the fd. It implements init/deinit/pollEvents/describe but no update/isAvailable/isButtonDown/isButtonPressed/axisValue (the gamepad_source state contract treats those as optional, so it compiles — but Linux can't serve gamepad STATE).
  • After core#28, the raylib/sokol desktop backends route gamepad through the shared SDL backends/sdl_gamepad source on all desktop OSes incl. Linux.
  • The SDL source is now CI-runtime-verified on Linux (assembler#279, 23/23 via an in-process SDL virtual gamecontroller) — but only the SDL joystick subsystem; it does not exercise the kernel device path.

Scope

  1. core — gamepad_source/linux.zig: add the state surface mirroring backends/sdl_gamepad's Source exactly (canonical raylib-compatible numbering, sticks [-1,1], triggers [0,1], synthesized left/right_trigger_2 at the trigger threshold, per-slot prev/cur edge snapshot):
    • keep the event* fd open per tracked slot (close on disconnect/deinit),
    • update(): per frame, snapshot current state via EVIOCGKEY (button bitmap) + EVIOCGABS(axis) ioctls (recommended for parity with the SDL snapshot-and-edge model) or drain the evdev event stream,
    • isAvailable/isButtonDown/isButtonPressed/axisValue,
    • the KEY_*/ABS_* → canonical button/axis mapping + axis normalization from each axis's input_absinfo{min,max,flat} (read once at connect),
    • matching no-op state methods on the non-Linux FallbackSource so the file still cross-compiles everywhere.
  2. assembler — backend Impl routing: on a Linux desktop target, route raylib/sokol gamepad to core.gamepad_source (udev) instead of sdl_gamepad, and don't link SDL2 there. (This is the per-OS 3-way selection sketched in the core#28 slice-5 plan.)

Acceptance (needs bare-metal Linux + a real pad)

The SDL virtual-device harness can't cover these — they're the kernel-path criteria (overlaps assembler#249):

  • connect/disconnect hotplug via evdev/udev with a physically (re)plugged controller,
  • /dev/input/* permission handling + a clean unavailable_reason when denied,
  • GUID/identity stability across replug,
  • buttons/axes/edges read correctly for at least one real pad (Xbox + one other).

Why deferred

No bare-metal Linux hardware available to runtime-verify, and shipping an unverified evdev state path would replace the working, now-CI-verified SDL Linux path — a regression risk with nothing to catch it. Pick up when Linux hardware (or a Linux runtime-CI job with a real/virtual evdev device) is available.

Related

  • core#28 — gamepad epic; this is its deferred Linux follow-up.
  • assembler#249 — Linux evdev/udev + wasm detection sources (Phase 1); carries the wasm + permissions-UX scope and the kernel-path acceptance criteria.
  • assembler#279 — hardware-free SDL gamepad CI harness (verifies the SDL Linux path, not the kernel path).

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