Skip to content

[Feature]: Add bounded ui tab-trace focus diagnostic #692

Description

Is your feature request related to a problem? Please describe.

Tracing keyboard focus today requires repeatedly composing winapp ui get-focused and winapp ui send-keys, which is slow and race-prone for agents and developers. A hands-on Paint trace captured 13 focus states but took many commands. Existing accessibility tooling was intrusive/incomplete for this debugging task.

This is blocked by #691. For hosted apps such as Calculator, the visible HWND belongs to ApplicationFrameHost while focused UIA controls belong to CalculatorApp; current PID equality filtering makes ui get-focused -w <host-hwnd> report no focus.

Describe the solution you'd like

After #691 Stage 1 lands, add a narrow diagnostic:

winapp ui tab-trace -a <app>
winapp ui tab-trace -w <hwnd>
winapp ui tab-trace -a <app> --reverse
winapp ui tab-trace -a <app> --max-steps 20 --json

Job to be done

Send bounded, user-equivalent Tab or Shift+Tab input to a selected window and factually record the UIA keyboard-focus state observed before and after each key.

It is not an accessibility-compliance checker, a tab-order correctness validator, or a complete keyboard-navigation audit. It must not output pass/fail, valid/invalid, expected order, or compliance claims.

V1 UX

  • --app/-a or --window/-w selects the target using existing conventions.
  • Default traversal is Tab; --reverse sends Shift+Tab.
  • --max-steps defaults to 20 and is bounded.
  • Existing --timeout bounds the whole run (default 30 seconds).
  • Use guarded SendInput only; do not expose a --via transport option. post-message can silently fail for XAML/UWP controls.
  • Start at the currently focused element. No selector/start-focus option in v1.
  • Before every key, verify the selected input-root HWND is foreground. Stop before any later injection on foreground loss, focus escape, or scope uncertainty.
  • Stop normally on maximum steps, target escape, scope uncertainty, or overall timeout. A repeated focus identity is reported as revisitedStep; it is not a correctness verdict.

Example text:

Tracing Tab focus in Paint (HWND 0x0001A2B3)
0  observed Button "Paste"
1  Tab  observed Button "Select"
2  Tab  observed Button "Crop"
Stopped: focus escaped the target window after 13 steps.

Required shared prerequisite

Consume the focus snapshot/membership operation from #691 rather than reimplementing it. A focus snapshot must distinguish no focus, provider/read error, focus outside target, and focus in a hosted foreign-PID descendant. Target membership is based on top-level HWND/UIA subtree containment, never PID equality.

Output and exit behavior

  • Text output is factual and concise.
  • --json emits one NativeAOT-safe result document with schemaVersion, provenance, initial snapshot, steps, warnings, and terminal reason.
  • Each step records requested key, injection outcome (injected means Windows accepted input only), before/after snapshots, target relation, settle timing, and optional revisitedStep.
  • Return 0 for a finalized factual trace, including escape, revisit, max steps, unchanged focus, or timeout.
  • Return 1 for invalid options/target, unavailable interactive desktop, foreground loss, injection failure, or unrecoverable UIA sampling failure. Emit valid partial JSON before a mid-run failure where possible.
  • Return 130 after Ctrl+C finalizes partial output.
  • Do not ship NDJSON in v1. Reconsider only if a demonstrated streaming consumer needs it.

Implementation and validation boundaries

  1. [Feature]: Support hosted cross-process UIA targeting #691 Stage 1: shared focus snapshot + UIA/HWND membership, including hosted Calculator focus.
  2. Add UiTabTraceCommand and a bounded trace state machine using SendInput plus polling/settled snapshots. Do not depend on ui watch or UIA event callbacks in v1.
  3. Update CLI schema, UI automation docs, skill fragment/generated skills, and tests.

Acceptance criteria:

  • One invocation reproduces the existing Paint 13-state trace in order across three local interactive runs.
  • Targeting Calculator by app/frame HWND reports CalculatorApp focus as in-target; a child-process PID is not required.
  • Tests prove no key is injected after foreground loss, target escape, or scope uncertainty.
  • Launch evidence covers local interactive Win32/WinForms, WPF, WinUI 3, and packaged/UWP hosted apps on Windows 10 19041+ and current Windows 11. Electron/WebView2, RDP, IME, and popups are staged/report-only until independently validated.

Kill/redesign if hosted focus cannot be classified safely, any wrong-target input is possible, or Paint/Calculator traces are not reliable.

Additional context

This intentionally does not replace or depend on PR #602 (ui watch). ui watch is a broad live-event stream with NDJSON/callback complexity and does not provide per-key causality or input safety. If general event watching has a demonstrated future need, it should be reconsidered separately after #691; it is not needed for this diagnostic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions