Files
orca/src/shared/computer-use-key-spec.ts
T
Neil d0f341ad69 fix(computer-use): make modifier clicks interruption-safe (#11451)
* fix(computer-use): make modifier clicks interruption-safe

* fix(computer-use): pace modified Windows multiclicks

* fix(computer-use): address modifier safety review
2026-07-29 18:29:10 -07:00

69 lines
1.7 KiB
TypeScript

const HOTKEY_MODIFIERS = new Set([
'alt',
'cmd',
'cmdorctrl',
'command',
'commandorcontrol',
'control',
'ctrl',
'meta',
'option',
'shift',
'super',
'win'
])
const HOTKEY_HINT =
'Hotkey requires a modifier and one key, e.g. CmdOrCtrl+A. Use press-key for a single key.'
const PRESS_KEY_HINT =
'Press-key accepts one key only, e.g. Return, Escape, Tab, or +. Use hotkey for modifier combinations.'
const CLICK_MODIFIERS_HINT =
'Click modifiers accept modifier keys only, e.g. CmdOrCtrl or CmdOrCtrl+Shift.'
export function computerUseHotkeyValidationMessage(key: string): string | null {
const parts = key.split('+').map((part) => part.trim())
if (parts.length < 2 || parts.some((part) => part.length === 0)) {
return HOTKEY_HINT
}
let keyPartCount = 0
for (const part of parts) {
if (!HOTKEY_MODIFIERS.has(normalizeHotkeyPart(part))) {
keyPartCount += 1
}
}
if (keyPartCount !== 1) {
return HOTKEY_HINT
}
return null
}
export function computerUsePressKeyValidationMessage(key: string): string | null {
const trimmed = key.trim()
if (trimmed.length === 0) {
return PRESS_KEY_HINT
}
if (trimmed !== '+' && trimmed.includes('+')) {
return PRESS_KEY_HINT
}
return null
}
export function computerUseClickModifiersValidationMessage(modifiers: string): string | null {
const parts = modifiers.split('+').map((part) => part.trim())
if (
parts.length === 0 ||
parts.length > 4 ||
parts.some((part) => part.length === 0 || !HOTKEY_MODIFIERS.has(part.toLowerCase()))
) {
return CLICK_MODIFIERS_HINT
}
return null
}
function normalizeHotkeyPart(part: string): string {
return part.toLowerCase().replace(/[\s_-]/g, '')
}