Skip to content

[P1-35] Add terminal input, hit-testing, and gesture semantics #41

Description

@phranck

Problem

TUIkit has key handling but no coherent SwiftUI-compatible owner for KeyPress/onKeyPress, pointer hover, hit testing, Gesture, TapGesture, LongPressGesture, DragGesture, and gesture state. Focus #22, shortcuts #33, and menus #5 do not own this event-routing layer.

Proposed solution

  • Introduce per-app keyboard and pointer events plus deterministic cell hit testing on the runtime, event, and surface foundations.
  • Add applicable SwiftUI keyboard, hover, hit-testing, and gesture APIs with exact Swift 6.0 signatures.
  • Implement terminal TapGesture/LongPressGesture/DragGesture and gesture composition/state where cell coordinates and duration have deterministic semantics.
  • Route focus, shortcuts, and commands through the shared input model without duplicate dispatch stacks.
  • Explicitly exclude touch-, pressure-, Pencil-, haptic-, and spatial-only APIs in the compatibility manifest.
  • Own KeyEquivalent, EventModifiers, KeyPress, onKeyPress, hover, ContentShapeKinds/contentShape, hit-testing, Gesture, gesture composition, GestureState, TapGesture, LongPressGesture/onLongPressGesture, and DragGesture. Focus stays in [P1-17] Replace the FocusState collision with SwiftUI-compatible focus APIs #22, KeyboardShortcut in [P2-28] Add terminal accessibility, search, refresh, and application actions #33, and data-transfer modifiers/payloads in [P2-36] Add portable clipboard and data-transfer APIs #42.
  • Migrate the existing incompatible KeyEvent, Key, and onKeyPress APIs to the reviewed surface or mark additive compatibility shims for namespacing/removal in [P2-30] Reduce the public implementation surface and namespace TUI-only APIs #35.
  • Record backend capability and fallback semantics for key-up, repeat, modifier-only events, and legacy/SGR/Kitty mouse protocols instead of synthesizing events the terminal did not report.
  • Classify Xcode-27-only GestureInputKinds and inputKinds overloads, including onLongPressGesture(inputKinds:...), as availability-gated surface; only .pointer maps to terminal mouse input. Keyboard remains in KeyPress/EventModifiers, while touch/Pencil-only cases stay excluded.

Acceptance criteria

  • Representative KeyPress, onKeyPress, onHover, allowsHitTesting, Gesture, TapGesture, LongPressGesture/onLongPressGesture, and DragGesture snippets compile under Swift 6.0, including availability fixtures for the OS-27 inputKinds overload.
  • GestureMask, high-priority, simultaneous, sequenced, and exclusive composition match their reviewed generic and isolation contracts.
  • Nested and overlapping views route input deterministically by committed tree, focus, and hit-test order; resize or removal cancels gesture state.
  • Keyboard and pointer backends are injected per app, Sendable-safe, and testable without a real terminal.
  • Cell-coordinate gesture tests cover Unicode-width layouts, clipping, and macOS/Linux parity.
  • Build, tests, SwiftLint strict, and DocC remain warning-free on macOS and Linux.

Dependencies

Depends on runtime #8, event loop #9, stable identity #10, cell surfaces #11, committed effects #13, core API #17, data flow #18, layout #20, modifiers #21, and focus #22. Issue #34 supplies the minimal Transaction value contract needed by GestureState before this issue completes; its later animation propagation and timing work does not block the remaining P1 scope. Public gesture APIs follow the shared input and hit-test contract without waiting for full P2 animation support.

Parallelization

Keyboard routing and pointer/hit-testing can proceed in separate file groups after the shared event contract. Gesture API/state follows hit testing and can integrate independently from clipboard #42 and document work #43.

Commit structure

  • Split this issue into small, thematic, independently revertible commits wherever the work can remain coherent.
  • Every commit must build and keep its applicable tests/gates green. Do not commit an intentionally failing regression test; land it with the smallest fix.
  • Keep characterization/fixtures, mechanical renames or moves, semantic changes, and documentation/migration updates separate when each step remains green.
  • The issue boundary is not a commit boundary; multiple commits are expected for independently reversible changes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestparallel-readyCan proceed independently of the current critical pathpriority: highHigh-impact correctness, compatibility, or SDK completeness work

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions