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:
- HWND targeting.
PostMessage WM_KEYDOWN -w <hwnd> posts to a specific window's message queue. SendKeys.SendWait can't do this.
- 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.
- 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
- 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.
- One verb vs two (
send-keys vs send-key + type-text) — affects user-facing syntax. Recommend one verb.
- 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.
Proposal: new
winapp ui send-keysverb for synthetic keyboard inputThe gap
winapp uihas 15 verbs — none send keystrokes. The closest isset-value(writes text atomically viaValuePattern). 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 noIKeyboardProviderpattern. 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-TypeC# definingKEYBDINPUTstructs and callingPostMessage WM_KEYDOWN/UP. Pure boilerplate that belongs in the tool.Why it belongs in winapp (not "just use SendKeys")
If
clickis in scope,send-keysis in scope — they're the same category of work:PostMessage WM_KEYDOWN -w <hwnd>posts to a specific window's message queue.SendKeys.SendWaitcan't do this.clickalready documents the UIPI limit;send-keysdefaults to PostMessage specifically to bypass it. That's app-driving knowledge, not generic input.click), commands ✅ (invoke/set-value), keyboard ❌ ← the missing pillar. WinUI 3 / Windows App SDK apps lean heavily on keyboard nav.Plus two clinchers:
Add-Typeworkaround excludes Python / Go / Node users entirely.Direction (not a locked-in design)
winapp ui send-keysalongsideclick/invoke/set-value, with standard-w/-a/--jsonoptions.PostMessage(HWND-targeted, bypasses UIPI, default candidate) andSendInput(OS-wide, hits LL hooks, subject to UIPI) — selectable via a--viaflag.down), sequences (down down enter), modifier combos (ctrl+shift+t), and literal text (hello), withvk=0xNNfor keys without names.WH_KEYBOARD_LLglobal hotkeys (architectural — LL hooks tap upstream of any HWND queue); SendInput is UIPI-blocked from elevated → AppX.Open questions worth deciding up front
WM_KEYDOWN. Wants a small empirical matrix before locking the default.send-keysvssend-key+type-text) — affects user-facing syntax. Recommend one verb.winapp.exe— separate architectural track, but determines whether--via send-inputis usable from elevated runners (also unlocksclickfrom 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.