Skip to content

Handle minimized windows in winapp ui - #1054

Merged
Nikola Metulev (nmetulev) merged 6 commits into
mainfrom
nmetulev-minimized-window-handling-winapp-ui
Oct 12, 2026
Merged

Nikola Metulev (nmetulev) merged 6 commits into
mainfrom
nmetulev-minimized-window-handling-winapp-ui

Conversation

@nmetulev

Copy link
Copy Markdown
Member

Description

winapp ui couldn't work with a minimized frame-hosted app (UWP/WinUI apps hosted in ApplicationFrameHost, such as Calculator). While the app is minimized, its content window detaches from the frame. winapp ui then saw only an empty frame root and had no reliable way to restore the window.

Repro (Calculator minimized; for each: input → actual → expected):

Input Actual (before) Expected
winapp ui search CalculatorResults -a calculator 0 matches, exit 1 finds the element, or explains that the window is minimized and how to restore it
winapp ui inspect -a calculator a lone empty Pane, exit 0 the same explanation
winapp ui get-value CalculatorResults -a calculator / invoke num7Button -a calculator "No element found", exit 1; window stays minimized an error that says how to restore the window
winapp ui focus CalculatorResults -a calculator "No element found", exit 1 restores the window and focuses the element, exit 0
winapp ui focus <root slug> -w <hwnd> restores the window, but exits 1 with "did not confirm keyboard focus" exit 0
winapp ui list-windows -a calculator lists the detached content window instead of the app frame lists the app frame

A minimized Win32 app (Notepad) keeps its full UI tree, so this only affects frame-hosted apps.

Design

  • Target resolution: when a frame-hosted app is minimized, -a resolves to its app frame, matched by AppUserModelID. If more than one frame matches, it doesn't guess.
  • winapp ui focus: if the target window is minimized, focus restores it, then looks for the element again (polling briefly while the content reattaches) and focuses it. The selector is now optional: focus -a <app> or focus -w <hwnd> restores and activates the window itself. Focus on a window element is confirmed by checking the foreground window, which fixes the false exit 1.
  • Read and other commands: when the element isn't found and the target window is minimized, the error says Run 'winapp ui focus -w <hwnd>' to restore it, then retry. In --json output this is the recoveryHint field. search and inspect print the same hint as a warning when they find nothing.
  • No other automatic restores: only focus restores a window. No other command restores or retries automatically, and mutating commands are never retried.

Usage Example

# Restore and activate a minimized app window (no selector needed)
winapp ui focus -a calculator

# Restore the window if needed, then focus an element in it
winapp ui focus CalculatorResults -a calculator

# Other commands now explain how to recover
winapp ui get-value CalculatorResults -a calculator
# No element found ... The window is minimized. Run 'winapp ui focus -w <hwnd>' to restore it, then retry.

Related Issue

None. Found by the agent UI benchmark in the separate benchmarks/ui PR.

Type of Change

  • 🐛 Bug fix
  • 📝 Documentation
  • 🧪 Test update

Checklist

  • New tests added for new functionality (if applicable)
  • Tested locally on Windows
  • docs/usage.md updated (if CLI commands changed)
  • Shipped skills updated in plugins/winapp/skills/ (if CLI commands/workflows changed)

Screenshots / Demo

N/A (CLI behavior; the benchmark results are below).

Additional Notes

Validation (Windows on Arm64):

Command Result
.\scripts\build-cli.ps1 -SkipMsix -SkipNpm (Release, warnings-as-errors) ✅ Build succeeded, 0 warnings
dotnet run --project src\winapp-CLI\WinApp.Cli.Tests\WinApp.Cli.Tests.csproj -c Debug --no-build -- --filter "FullyQualifiedName~UiCommandTests" ✅ 885/885
dotnet run --project src\winapp-CLI\WinApp.UIAutomation.Tests\WinApp.UIAutomation.Tests.csproj -c Debug --no-build ✅ 954/954
Full CLI test suite 7399/7411 passed; the 12 failures are environmental (details below)
npm unit tests ✅ 92/92
.\scripts\validate-plugin-package.ps1 ✅ Passed
Manual test: minimized Calculator, Release Arm64 build ✅ Every command in the repro table now behaves as expected; minimized Notepad behaves as before

The 12 full-suite failures are environmental and don't involve code changed here:

  • 11 failures: live nuget.org tests (NugetService GetPackageDependenciesAsync_* / GetLatestVersionAsync_*). nuget.org can't be reached from a Microsoft corporate machine.
  • 1 failure: AnalyzeDumpAsync_ManagedDumpWithDeepStack_DetectsStackOverflowShape. The test dump's .NET runtime doesn't match the Arm64 host.

Benchmark (measured with the benchmark from the separate benchmarks/ui PR):

  • Setup: claude-sonnet-5.5, Copilot CLI 1.0.93, this branch's Release build on PATH, this branch's plugin.
  • Median of 5 runs, except the scripted perf sequence (3 runs).
Scenario Before After No plugin (none)
Scripted perf sequence calc-minimized-scientific 0/3 pass 3/3 pass, ~1.6 s –
Agent calc-minimized-scientific 10 turns, 36.9 s, 11.9 credits 5/5 pass; 7 turns, 19 s, 10.0 credits 3 turns, 15.0 s, 3.7 credits
Agent calc-running (regression check) 4 turns, 12.4 s 5/5 pass; 4 turns, 11 s –

Known limitations:

  • If two instances of the same frame-hosted app are minimized, -a is ambiguous. Use -w <hwnd> to pick one.
  • The AppUserModelID window lookup is covered by the manual Calculator test, not an automated test.

Packaged apps hosted in ApplicationFrameHost (Calculator) detach their
content window while minimized, so -a <app> resolved to the hidden
CoreWindow and every lookup missed.

- Resolve a minimized frame-hosted app to its frame (matched by AUMID),
  in both the target resolver and list-windows.
- focus restores a minimized target before finding the element; with no
  selector it restores and activates the window itself. A selected Window
  element is confirmed by foreground, fixing a false focus_not_acquired.
- element_not_found (and empty search/inspect) on a minimized target says
  so and gives the exact 'winapp ui focus -w <hwnd>' to run. Read and
  mutating commands never restore or retry on their own.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 9, 2026 21:17
@nmetulev Nikola Metulev (nmetulev) added the agent-preparing Agent is addressing feedback or completing required validation and CI label Oct 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Ambiguous minimized frames can still select the wrong target, while touch, pen, and record omit the new recovery hint.

2 open findings
What changed in this PR

Adds minimized frame-hosted app support to winapp ui, including window restoration, targeting, recovery guidance, tests, and documentation.

Changes:

  • Resolves minimized packaged apps through their ApplicationFrameHost frame.
  • Extends ui focus to restore windows and allow selector-free activation.
  • Adds minimized-window recovery hints across UI commands.
File Description
UiTargetResolver.cs Resolves detached CoreWindows to hosting frames.
SystemUiQuery.cs Matches minimized frames by AppUserModelID.
ISystemUiQuery.cs Documents minimized-frame lookup behavior.
NativeMethods.txt Adds packaged-app identity APIs.
UiTargetResolverTests.cs Tests minimized hosted-app resolution.
UiErrors.cs Adds restoration recovery hints.
UiSetValueCommand.cs Supplies target context to errors.
UiSendKeysCommand.cs Supplies target context to errors.
UiSearchCommand.cs Warns when empty results come from minimization.
UiScrollIntoViewCommand.cs Supplies target context to errors.
UiScrollCommand.cs Supplies target context to errors.
UiScreenshotCommand.cs Supplies target context to errors.
UiListWindowsCommand.cs Lists hosting frames instead of detached content.
UiInvokeCommand.cs Supplies target context to errors.
UiInspectCommand.cs Warns about minimized empty trees.
UiHoverCommand.cs Supplies target context to errors.
UiGetValueCommand.cs Supplies target context to errors.
UiGetPropertyCommand.cs Supplies target context to errors.
UiFocusCommand.cs Restores and focuses windows or elements.
UiDragCommand.cs Supplies target context to errors.
UiClickCommand.cs Supplies target context to errors.
UiCommandTests.SimpleVerbs.cs Updates optional-selector validation.
UiCommandTests.MinimizedWindow.cs Tests recovery hints and non-restoration.
UiCommandTests.Focus.cs Tests restoration and window activation.
FakeDesktopForegroundService.cs Models restored window state.
SKILL.md Documents minimized-window recovery workflow.
docs/​usage.md Updates the focus command summary.
docs/​ui-automation.md Documents restoration behavior and troubleshooting.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/winapp-CLI/WinApp.UIAutomation/Services/SystemUiQuery.cs Outdated
Comment thread src/winapp-CLI/WinApp.Cli/Helpers/UiErrors.cs
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Build Metrics Report

Validation passed. All required build and validation jobs succeeded.

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 57.77 MB 57.80 MB 📈 +25.5 KB (+0.04%)
CLI (x64) 57.79 MB 57.82 MB 📈 +24.5 KB (+0.04%)
MSIX (ARM64) 24.02 MB 24.04 MB 📈 +18.5 KB (+0.08%)
MSIX (x64) 25.49 MB 25.51 MB 📈 +17.4 KB (+0.07%)
NPM Package 50.08 MB 50.10 MB 📈 +23.9 KB (+0.05%)
NuGet Package 50.19 MB 50.21 MB 📈 +22.8 KB (+0.04%)

.NET Test Results (TRX reports)

Other suites are reflected in the overall validation status above.

✅ 8347 passed, 37 skipped out of 8384 tests in 1311.7s (+16 tests, +139.8s vs. baseline)

Test Coverage

✅ 87.4% line coverage, 82.2% branch coverage · ✅ no change vs. baseline

CLI Startup Time

66ms median (x64, winapp --version) · ✅ no change vs. baseline

Try This Build

Installs the MSIX for your architecture, replacing any previously installed build. Needs the GitHub CLI — the command offers to install it and sign you in if it is missing.

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) 1054
Switching between builds often?

Put the tool on your PATH once:

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) -AddToPath

Then this build is just:

winapp-pr 1054

Run winapp-pr with no arguments to pick from a list of open PRs.


Updated 2026-10-12 16:46:27 UTC · commit 3feb5f6 · workflow run

@nmetulev Nikola Metulev (nmetulev) added ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge and removed agent-preparing Agent is addressing feedback or completing required validation and CI labels Oct 9, 2026
…ch, pen, and record

When several minimized frames match one app, report the ambiguity and ask for --window instead of guessing. Pass the target to the touch, pen, and record element-not-found errors so they include the restore hint.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5c725120-4d00-4fde-9849-078c42e66530

@zateutsch Zach Teutsch (zateutsch) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My review came up clean, approving. I resolved two copilot comments that the lifecycle skill didn't catch.

Comment thread src/winapp-CLI/WinApp.Cli.Tests/UiCommandTests.MinimizedWindow.cs Fixed
AmbiguousHostedAppFrameException is only caught inside the UIAutomation library, so it should not join the package's public API (PublicApiSurfaceTests). The public ISystemUiQuery docs name its base InvalidOperationException.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@nmetulev Nikola Metulev (nmetulev) added agent-preparing Agent is addressing feedback or completing required validation and CI ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge and removed ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge agent-preparing Agent is addressing feedback or completing required validation and CI labels Oct 12, 2026
@nmetulev
Nikola Metulev (nmetulev) merged commit 963d4ba into main Oct 12, 2026
48 checks passed
@nmetulev
Nikola Metulev (nmetulev) deleted the nmetulev-minimized-window-handling-winapp-ui branch October 12, 2026 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review Agent work and technical checks complete; awaiting review or re-review, not approval or merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants