Skip to content

Proposal: new winapp ui send-keys verb for synthetic keyboard input #562

@LegendaryBlair

Description

@LegendaryBlair

Proposal: new winapp ui send-keys verb for synthetic keyboard input

The gap

winapp ui has 15 verbs — none send keystrokes. The closest is set-value (writes text atomically via ValuePattern). No arrow keys, no Enter, no Tab, no Escape, no shortcuts.

Any script that needs keyboard navigation falls off a cliff — pressing Down to move a ListView highlight, Enter to commit, Tab to traverse focus, Ctrl+C / Ctrl+V, custom KeyboardAccelerators, etc. UIA can't help: there's no IKeyboardProvider pattern. The framework was designed for assistive tech (read state + invoke commands), not input simulation. So any send-keys implementation must be at the Win32 layer.

Today every PowerShell script that needs this ships 30+ lines of inline Add-Type C# defining KEYBDINPUT structs and calling PostMessage WM_KEYDOWN/UP. Pure boilerplate that belongs in the tool.

Why it belongs in winapp (not "just use SendKeys")

If click is in scope, send-keys is in scope — they're the same category of work:

  1. HWND targeting. PostMessage WM_KEYDOWN -w <hwnd> posts to a specific window's message queue. SendKeys.SendWait can't do this.
  2. UIPI / IL awareness. Test automation routinely runs at a different integrity level than the target. click already documents the UIPI limit; send-keys defaults to PostMessage specifically to bypass it. That's app-driving knowledge, not generic input.
  3. It completes the interaction model. Read state ✅, mouse ✅ (click), commands ✅ (invoke / set-value), keyboard ❌ ← the missing pillar. WinUI 3 / Windows App SDK apps lean heavily on keyboard nav.

Plus two clinchers:

  • Cross-language: winapp is a language-agnostic CLI. The PowerShell-only Add-Type workaround excludes Python / Go / Node users entirely.
  • Discoverability tax: every new user hits the "SendInput failed silently across IL" wall once and burns hours on Stack Overflow before discovering the PostMessage workaround. A CLI verb absorbs that cost once.

Direction (not a locked-in design)

  • New verb winapp ui send-keys alongside click / invoke / set-value, with standard -w / -a / --json options.
  • Two transports: PostMessage (HWND-targeted, bypasses UIPI, default candidate) and SendInput (OS-wide, hits LL hooks, subject to UIPI) — selectable via a --via flag.
  • A friendly key-string grammar covering single keys (down), sequences (down down enter), modifier combos (ctrl+shift+t), and literal text (hello), with vk=0xNN for keys without names.
  • Honest documentation of the hard limits: PostMessage can't trigger WH_KEYBOARD_LL global hotkeys (architectural — LL hooks tap upstream of any HWND queue); SendInput is UIPI-blocked from elevated → AppX.

Open questions worth deciding up front

  1. Default transport — depends on how many WinUI 3 / Windows App SDK apps hook raw input and ignore WM_KEYDOWN. Wants a small empirical matrix before locking the default.
  2. One verb vs two (send-keys vs send-key + type-text) — affects user-facing syntax. Recommend one verb.
  3. UIAccess marking of winapp.exe — separate architectural track, but determines whether --via send-input is usable from elevated runners (also unlocks click from elevated → AppContainer).

Happy to write up the full API surface, grammar, error model, and risk register as a follow-up doc / PR once the direction is acknowledged.

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