From 82fe16767c4a0a92b4d3ff7c9308cdaa6d00498a Mon Sep 17 00:00:00 2001 From: ciregenz Date: Sun, 12 Jul 2026 21:26:49 -0700 Subject: [PATCH] [eric] browser: handleType reads back its fill and falls back to real keystrokes = the main type action now detects when execCommand insertText did not commit (editors that reject synthetic input) and retypes via wv.sendInputEvent, same lever as the composer finder's keystrokeFill --- frontend/src/shared/browserCommandHandler.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/frontend/src/shared/browserCommandHandler.ts b/frontend/src/shared/browserCommandHandler.ts index c34745bf..ff566f49 100644 --- a/frontend/src/shared/browserCommandHandler.ts +++ b/frontend/src/shared/browserCommandHandler.ts @@ -317,6 +317,9 @@ async function handleType(wv: BrowserWebview, params: Record): Prom if (text == null) return { error: 'text parameter is required' }; const safeSelector = JSON.stringify(selector); const safeText = JSON.stringify(text); + // Try the cheap in-page fill first, and read it back: an editor that rejects synthetic + // execCommand insertText (Reddit's Lexical, strict React contenteditables) leaves the box + // empty, and we only learn that by checking the value, not by assuming the call worked. const code = `(async ()=>{ const el = document.querySelector(${safeSelector}); if (!el) return { error: 'Element not found: ' + ${safeSelector} }; @@ -330,11 +333,17 @@ async function handleType(wv: BrowserWebview, params: Record): Prom bubbles: true, cancelable: true, inputType: 'insertText', data: ${safeText}, })); el.dispatchEvent(new Event('change', { bubbles: true })); - return { - text: 'Typed into: ' + el.tagName.toLowerCase() + (el.id ? '#' + el.id : ''), - }; + const now = (el.value != null ? el.value : (el.textContent || '')); + return { text: 'Typed into: ' + el.tagName.toLowerCase() + (el.id ? '#' + el.id : ''), + committed: now.includes(${safeText}) }; })()`; const result = await evalInPage(wv, code); + // Real-keystroke fallback when the synthetic fill did not commit (same lever the finder uses). + if (result && !result.error && result.committed === false) { + const ok = await keystrokeFill(wv, selector, text); + result.text = ok ? `Typed into ${selector} via keystrokes` : `Type may not have committed into ${selector}`; + result.committed = ok; + } return result; }