Skip to content

feat(input): compose held movement into one semantic direction #53

Description

@zoeyrose

Outcome

Implement independent Rust/SDL3 held-direction resolution so active perpendicular movement bindings produce one deterministic eight-way semantic movement intent. Track replacement-client parity separately from the completed Classic work documented by atrinik/classic#62 and atrinik/classic#107; those issues are behavior specifications, not implementation sources.

Scope and invariants

  • Extend the semantic direction/action model to represent north, northeast, east, southeast, south, southwest, west, and northwest.
  • Resolve active semantic movement bindings after input-context/focus arbitration rather than composing raw keycodes, so rebindings, duplicate bindings, keyboard, and controller input share the same behavior.
  • Compose all eight perpendicular pairs: N+E→NE, E+S→SE, S+W→SW, W+N→NW, NW+NE→N, NE+SE→E, SE+SW→S, and SW+NW→W.
  • Produce the same result for either press order and for bindings received in the same SDL poll or in successive polls.
  • Drive each chord through one logical held/repeat stream; constituent repeats must not alternate directions, double cadence, or leave stale queued movement.
  • Recompute immediately on partial release and continue in the remaining direction. Final release/cancel emits the required stop exactly once.
  • Clear held ownership on focus/context loss, disconnect, device removal, or rebinding without leaking gameplay input from text fields or focused UI.
  • Preserve standalone movement, explicit diagonal movement, and the run/fire/stay semantics owned by Rebuild modern controls and onboarding around semantic actions #14. Opposite pairs and combinations of three or more directions need deterministic, non-stuck behavior but no new composition rule.
  • Keep resolution in a pure, bounded client layer; map the resolved intent through released Game Protocol 1 adapters without depending on Classic code or packet behavior.

Acceptance criteria

  • All eight pairs resolve correctly for both press orders and same-poll/sequential input.
  • A held chord emits one direction at normal repeat cadence with no constituent glitch or doubled rate.
  • Partial release resumes the remaining direction immediately; final release stops exactly once.
  • Tests cover custom and duplicate bindings, keyboard/controller parity, run/fire/stay interaction, focus/context transitions, device removal, rebinding, queue pressure, and reconnect cleanup.
  • Opposite and three-or-more-direction input is deterministic and cannot stick movement.
  • Pure resolver tests use fake input/time and require no display, GPU, network, server, or ambient user state; supported SDL3 integration paths also pass.
  • The behavior-parity matrix in Complete the clean-room client behavior-parity matrix #37 records the result, and Rebuild modern controls and onboarding around semantic actions #14 consumes the resolver through its shared action catalog.
  • tools/validate.sh and git diff --check pass.

Dependencies and coordination

Coordinate with #14 for the action catalog/input contexts and #12 for the released Game Protocol 1 adapter. This focused issue owns direction composition and held-stream lifecycle; #13 owns authoritative movement interpolation after an action is accepted.

Licensing

Implement source and tests independently under MIT from public behavior specifications. Do not copy, translate, or use Classic source/tests as an implementation template.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Effort

    None yet

    Projects

    Status
    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions