From ca9c48e1b7ef5e709475f36871576582097710ec Mon Sep 17 00:00:00 2001 From: Colin Neilens Date: Tue, 6 Oct 2026 18:17:16 -0700 Subject: [PATCH] Reveal the reopened promotion submenu by keyboard when hover is dropped The UIA gate's first "Promote to" submenu open already falls back to keyboard navigation of the real native menu when injected hover is not delivered. The reopen after cancelling Turn promotion only hovered, so on a desktop that drops injected mouse input the gate failed with "Turn promotion submenu did not reopen natively" even though the shell's menu was open and foreground. Apply the same bounded keyboard reveal to the reopen and log which path was used. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Signed-off-by: Colin Neilens --- .../windows/Tests/ValidationRunner.Tests.ps1 | 1 + Tools/windows/uia-live-gate.ps1 | 33 ++++++++++++++----- graphcode-workspace.159bee7166972fae.json | 1 + 3 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 graphcode-workspace.159bee7166972fae.json diff --git a/Tools/windows/Tests/ValidationRunner.Tests.ps1 b/Tools/windows/Tests/ValidationRunner.Tests.ps1 index d87aa520..b1bb6207 100644 --- a/Tools/windows/Tests/ValidationRunner.Tests.ps1 +++ b/Tools/windows/Tests/ValidationRunner.Tests.ps1 @@ -3572,6 +3572,7 @@ Start-Sleep -Seconds 60 $uiaLiveGateSource -notmatch 'public static bool RevealSubmenuByKeyboard\(IntPtr popup, IntPtr menu, int position\)' -or $uiaLiveGateSource -notmatch '\$submenuKeyboardReveal = \[GraphCodeUiaGateState\]::RevealSubmenuByKeyboard\(' -or $uiaLiveGateSource -notmatch 'real Promote to submenu popup did not open by hover or keyboard' -or + $uiaLiveGateSource -notmatch '(?s)\$reopen = Open-SketchNodeMenu \$title.*?\$reopenKeyboardReveal = \[GraphCodeUiaGateState\]::RevealSubmenuByKeyboard\(.*?Turn promotion submenu did not reopen by hover or keyboard' -or $uiaLiveGateSource -match 'SendCommand\(\s*\$renameShellWindow, \[uint32\]\$case\.Command\)' -or $uiaLiveGateSource -notmatch 'modalCommandFallback' -or $uiaLiveGateSource -notmatch 'function Stop-UiaOwnedProviderProcesses' -or diff --git a/Tools/windows/uia-live-gate.ps1 b/Tools/windows/uia-live-gate.ps1 index 51974d38..a943cb90 100644 --- a/Tools/windows/uia-live-gate.ps1 +++ b/Tools/windows/uia-live-gate.ps1 @@ -10374,17 +10374,32 @@ try { $reopen = Open-SketchNodeMenu $title $parent = @($reopen.items | Where-Object { $_.Text -eq "Promote to..." -and $_.Enabled }) Require ($parent.Count -eq 1) "cancelled sketch promotion disappeared from menu" - $handle = [GraphCodeUiaGateState]::NativeSubMenu( - [GraphCodeUiaGateState]::PopupMenuHandle($reopen.popup), [int]$parent[0].Position) - Require ([GraphCodeUiaGateState]::HoverPopupMenuItem($renameShellWindow, - [GraphCodeUiaGateState]::PopupMenuHandle($reopen.popup), [int]$parent[0].Position)) ` - "Turn promotion submenu did not reopen" + $reopenRoot = [GraphCodeUiaGateState]::PopupMenuHandle($reopen.popup) + $handle = [GraphCodeUiaGateState]::NativeSubMenu($reopenRoot, [int]$parent[0].Position) + $reopenKeyboardReveal = $false + $reopenHoverRevealed = [GraphCodeUiaGateState]::HoverPopupMenuItem($renameShellWindow, + $reopenRoot, [int]$parent[0].Position) $subPopup = [IntPtr]::Zero - for ($retry = 0; $retry -lt 60 -and $subPopup -eq [IntPtr]::Zero; $retry++) { - $subPopup = [GraphCodeUiaGateState]::FindPopupForMenu([uint32]$renameProcess.Id, $handle) - if ($subPopup -eq [IntPtr]::Zero) { Start-Sleep -Milliseconds 50 } + if ($reopenHoverRevealed) { + for ($retry = 0; $retry -lt 60 -and $subPopup -eq [IntPtr]::Zero; $retry++) { + $subPopup = [GraphCodeUiaGateState]::FindPopupForMenu([uint32]$renameProcess.Id, $handle) + if ($subPopup -eq [IntPtr]::Zero) { Start-Sleep -Milliseconds 50 } + } + } + if ($subPopup -eq [IntPtr]::Zero) { + # Same keyboard reveal as the first open: injected hover is not delivered + # on every desktop, and a WM_COMMAND to the shell would be a no-op. + $reopenKeyboardReveal = [GraphCodeUiaGateState]::RevealSubmenuByKeyboard( + $reopen.popup, $reopenRoot, [int]$parent[0].Position) + Require $reopenKeyboardReveal ` + "Turn promotion parent item could not be selected for keyboard submenu reveal" + for ($retry = 0; $retry -lt 60 -and $subPopup -eq [IntPtr]::Zero; $retry++) { + $subPopup = [GraphCodeUiaGateState]::FindPopupForMenu([uint32]$renameProcess.Id, $handle) + if ($subPopup -eq [IntPtr]::Zero) { Start-Sleep -Milliseconds 50 } + } } - Require ($subPopup -ne [IntPtr]::Zero) "Turn promotion submenu did not reopen natively" + Write-Host "UIA_SKETCH_SUBMENU_REOPEN title='$title' hoverRevealed=$reopenHoverRevealed keyboardReveal=$reopenKeyboardReveal popup=$($subPopup -ne [IntPtr]::Zero)" + Require ($subPopup -ne [IntPtr]::Zero) "Turn promotion submenu did not reopen by hover or keyboard" $null = Sketch-ClickMenu @{ popup = $subPopup; items = @(Get-NativeMenuItems $handle) } 5117 $modal = Assert-SketchModal "Promote $title to Turn" $submitFields = @{ pause = Sketch-Combo 9100 1 "Only before it writes files" } diff --git a/graphcode-workspace.159bee7166972fae.json b/graphcode-workspace.159bee7166972fae.json new file mode 100644 index 00000000..72894154 --- /dev/null +++ b/graphcode-workspace.159bee7166972fae.json @@ -0,0 +1 @@ +{"schemaVersion":2,"project":"C:\\v7\\9bd69edc5a444088ab28df14bae7d858\\temp\\gu-3105f799a95b493280820005d224ec6e\\project","selectedTab":1,"tabs":[{"id":1,"direction":"horizontal","focused":0,"panes":[{"id":"11111111-1111-4111-8111-111111111111","agent":true}]},{"id":2,"direction":"horizontal","focused":0,"panes":[{"id":"ed498986-ee0f-525f-ec6d-bbdab7bf0afc","agent":false}]}]} \ No newline at end of file