From ae8e3e1c37a0d45ae575f58d6eeea3dc79f3978d Mon Sep 17 00:00:00 2001 From: Joe Esposito <87134601+jespo2021@users.noreply.github.com> Date: Mon, 26 Oct 2026 08:59:08 -0400 Subject: [PATCH] fix(computer-use): send the plain chord for uppercase hotkey letters on Windows (#27642) SendKeys presses Shift for an uppercase letter (VkKeyScan reports the shift state), so `orca computer hotkey --key CmdOrCtrl+A` (the documented example) sent Ctrl+Shift+A on Windows. Lower-case a single-character key when the hotkey has modifiers; Shift is still sent when written explicitly. Extract ConvertTo-OrcaSendKeysHotkey so runtime-render.test.ps1 can assert the SendKeys strings case-sensitively. Fixes #27589 Co-authored-by: jespo2021 Co-authored-by: Neil --- native/computer-use-windows/runtime-render.test.ps1 | 5 +++++ native/computer-use-windows/runtime.ps1 | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/native/computer-use-windows/runtime-render.test.ps1 b/native/computer-use-windows/runtime-render.test.ps1 index 3e52b1a203e..6168d4da876 100644 --- a/native/computer-use-windows/runtime-render.test.ps1 +++ b/native/computer-use-windows/runtime-render.test.ps1 @@ -218,6 +218,11 @@ try { $MaxDepth = $originalMaxDepth } + foreach ($case in @(@("CmdOrCtrl+A", "^a"), @("Ctrl+Shift+T", "^+t"), @("Ctrl+Enter", "^{ENTER}"))) { + $keys = ConvertTo-OrcaSendKeysHotkey $case[0] + if ($keys -cne $case[1]) { throw "hotkey $($case[0]) expected '$($case[1])', received '$keys'" } + } + Write-Output "windows-snapshot-render-tests-ok" } finally { Remove-Item -LiteralPath $operationPath -Force -ErrorAction SilentlyContinue diff --git a/native/computer-use-windows/runtime.ps1 b/native/computer-use-windows/runtime.ps1 index aaf4be3c8a1..bc3b0c7f432 100644 --- a/native/computer-use-windows/runtime.ps1 +++ b/native/computer-use-windows/runtime.ps1 @@ -1102,18 +1102,25 @@ function Get-OrcaClickModifierVirtualKeys([string]$Modifiers) { @($parts | ForEach-Object { Get-OrcaModifierVirtualKey $_ }) } -function Send-OrcaHotkey([IntPtr]$WindowHandle, [string]$KeySpec) { +function ConvertTo-OrcaSendKeysHotkey([string]$KeySpec) { $parts = @($KeySpec.Split("+") | ForEach-Object { $_.Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) if ($parts.Count -eq 0) { throw "Unsupported key: $KeySpec" } $key = $parts[$parts.Count - 1] $prefix = "" if ($parts.Count -gt 1) { + # SendKeys adds Shift for an uppercase letter, turning Ctrl+A into Ctrl+Shift+A. + if ($key.Length -eq 1) { $key = $key.ToLowerInvariant() } foreach ($modifier in $parts[0..($parts.Count - 2)]) { $prefix += ConvertTo-OrcaSendKeysModifier $modifier } } + $prefix + (ConvertTo-OrcaSendKeysKey $key) +} + +function Send-OrcaHotkey([IntPtr]$WindowHandle, [string]$KeySpec) { + $keys = ConvertTo-OrcaSendKeysHotkey $KeySpec [void][OrcaDesktopWin32]::SetForegroundWindow($WindowHandle) - [System.Windows.Forms.SendKeys]::SendWait($prefix + (ConvertTo-OrcaSendKeysKey $key)) + [System.Windows.Forms.SendKeys]::SendWait($keys) } function ConvertTo-OrcaSendKeysText([string]$Text) {