|
|
|
@ -265,21 +265,47 @@ public final class FocusedInputSync { |
|
|
|
lastObservedText = cleanText |
|
|
|
lastObservedCursor = targetCursor |
|
|
|
|
|
|
|
let (elemOpt, appName) = getFocusedElement() |
|
|
|
let (_, appName) = getFocusedElement() |
|
|
|
lastObservedApp = appName |
|
|
|
|
|
|
|
// Try fast direct native AX write if supported (TextEdit, Notes, Finder) |
|
|
|
if let elem = elemOpt { |
|
|
|
let setErr = AXUIElementSetAttributeValue(elem, kAXValueAttribute as CFString, cleanText as CFTypeRef) |
|
|
|
if setErr == .success { |
|
|
|
print("FocusedInputSync: ✅ Updated native AXValue for \(appName)") |
|
|
|
return true |
|
|
|
// Universal Quartz CGEvent Keystroke Engine (Cmd+A -> Cmd+V / Backspace or pure Cmd+V) |
|
|
|
// Works 100% reliably across native, web, and Electron/Chromium apps (e.g. Antigravity, VS Code, Slack, Firefox) |
|
|
|
print("FocusedInputSync: 🚀 Injecting text into '\(appName)' (replace: \(isFullReplace), len: \(cleanText.count))") |
|
|
|
if isFullReplace { |
|
|
|
return executeCleanFullReplace(cleanText) |
|
|
|
} else { |
|
|
|
return pasteOnlyViaCleanKeystroke(cleanText) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Universal Native Replace (Cmd+A -> Cmd+V / Backspace) |
|
|
|
print("FocusedInputSync: 🔄 Syncing full text to '\(appName)' (len: \(cleanText.count))") |
|
|
|
return executeCleanFullReplace(cleanText) |
|
|
|
/** |
|
|
|
* Inserts speech directly at active cursor via clean Cmd+V |
|
|
|
*/ |
|
|
|
private func pasteOnlyViaCleanKeystroke(_ text: String) -> Bool { |
|
|
|
guard !text.isEmpty else { return true } |
|
|
|
|
|
|
|
let pasteboard = NSPasteboard.general |
|
|
|
pasteboard.clearContents() |
|
|
|
pasteboard.setString(text, forType: .string) |
|
|
|
|
|
|
|
let src = CGEventSource(stateID: .hidSystemState) |
|
|
|
let kVK_ANSI_V: CGKeyCode = 9 |
|
|
|
|
|
|
|
// Paste: Cmd + V |
|
|
|
if let vDown = CGEvent(keyboardEventSource: src, virtualKey: kVK_ANSI_V, keyDown: true) { |
|
|
|
vDown.flags = .maskCommand |
|
|
|
vDown.post(tap: .cghidEventTap) |
|
|
|
vDown.post(tap: .cgSessionEventTap) |
|
|
|
} |
|
|
|
usleep(12000) |
|
|
|
|
|
|
|
if let vUp = CGEvent(keyboardEventSource: src, virtualKey: kVK_ANSI_V, keyDown: false) { |
|
|
|
vUp.flags = .maskCommand |
|
|
|
vUp.post(tap: .cghidEventTap) |
|
|
|
vUp.post(tap: .cgSessionEventTap) |
|
|
|
} |
|
|
|
usleep(10000) |
|
|
|
return true |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
|