Skip to content

feat(wayland): close the live-input gap with a sovereign virtual-input injector - #3

Merged
tannevaled merged 1 commit into
mainfrom
feat/wayland-live-input
Aug 9, 2026
Merged

feat(wayland): close the live-input gap with a sovereign virtual-input injector#3
tannevaled merged 1 commit into
mainfrom
feat/wayland-live-input

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Task 1 — close the Wayland live-input gap

The Wayland live screenshot proof already passed, but live input was left
pending-on-compositor: the headless sway seat exposed no keyboard, so an
injected key never reached the client. This closes it end to end, with the
behaviour captured (not claimed).

What changed

  • Sovereign virtual-input bindings (internal/wayland/virtual.go): client
    side of zwp_virtual_keyboard_manager_v1/zwp_virtual_keyboard_v1 and
    zwlr_virtual_pointer_manager_v1/zwlr_virtual_pointer_v1. Attaching a
    virtual device to a seat makes it advertise the matching capability, so a
    plain client receives the injected events through the ordinary
    wl_keyboard/wl_pointer path. 100 %-covered (both endian paths).
  • Dynamic input hot-plug: wl_seat gains an OnCapabilities callback; the
    window binds pointer/keyboard when a device appears after bring-up, not
    just at connect time — required for a device-less headless seat.
  • Live test is its own injector (second connection, no wtype/ydotool):
    uploads a real libxkbcommon-compiled us keymap through the virtual
    keyboard, injects KEY_A + a left click, asserts the exact dispatched
    toolkit.Event.
  • Deterministic floor kept: wldynamic_test.go proves the hot-plug path
    in-process; the original fake-compositor input test stays.
  • CI: lane upgraded to live Wayland (input); installs libxkbcommon-tools
    (xkbcli), drops wtype.

Proof (captured, verified live under sway headless)

live input: EventChar 'a' dispatched from a real compositor key
live input: EventClick dispatched at (200,150) from a real compositor button
--- PASS: TestLiveWayland (2.01s)

internal/x11 and internal/wayland both at 100.0 % coverage under -race.

🤖 Generated with Claude Code

…t injector

The Wayland live screenshot proof passed but live INPUT was left
"pending-on-compositor": the headless sway seat exposed no keyboard, so an
injected key never reached the client. This closes it end to end.

- internal/wayland: add sovereign client bindings for
  zwp_virtual_keyboard_v1 (create/keymap/key/modifiers) and
  zwlr_virtual_pointer_v1 (create/motion_absolute/button/frame) plus their
  manager globals. Attaching a virtual device to a seat makes that seat
  advertise the matching capability, so a plain client receives the injected
  events through the ordinary wl_keyboard / wl_pointer path. 100%-covered.

- wl_seat: add an OnCapabilities callback; the window now binds pointer /
  keyboard dynamically when a device appears after bring-up (hot-plug),
  instead of a one-shot read at connect time — required for a device-less
  headless seat that only gains a keyboard once a virtual device attaches.

- live test: over a SECOND connection the test is its own sovereign input
  source (no wtype/ydotool). It uploads a real libxkbcommon-compiled us
  keymap through the virtual keyboard, injects KEY_A and a left click, and
  asserts the exact dispatched toolkit.Event (char 'a', click coordinate) —
  nothing faked. Verified live under sway headless: EventChar 'a' and
  EventClick at (200,150).

- wldynamic_test: deterministic in-process proof of the hot-plug path.

- ci: upgrade the lane to "live Wayland (input)"; install libxkbcommon-tools
  for xkbcli, drop wtype.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 7e0c677 into main Aug 9, 2026
11 checks passed
@tannevaled
tannevaled deleted the feat/wayland-live-input branch August 9, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant