From c169c62838e402f02319b4d522a2161e48e17416 Mon Sep 17 00:00:00 2001 From: Ali Alavi Date: Fri, 23 Oct 2026 09:58:46 +0330 Subject: [PATCH] fix(input-box): eliminate focus stealing to browser address bar on hotkey trigger (v2.06) --- Info.plist | 2 +- src/InputBoxManager.swift | 57 +++------------------------------------ src/TextProcessor.swift | 23 ++++++++++++++++ 3 files changed, 27 insertions(+), 55 deletions(-) diff --git a/Info.plist b/Info.plist index ee7475d..6b6d430 100644 --- a/Info.plist +++ b/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.0 + 2.06 CFBundleVersion 1 LSMinimumSystemVersion diff --git a/src/InputBoxManager.swift b/src/InputBoxManager.swift index 53d881d..abbb4af 100644 --- a/src/InputBoxManager.swift +++ b/src/InputBoxManager.swift @@ -44,38 +44,8 @@ public final class InputBoxManager { return } - guard let frontApp = NSWorkspace.shared.frontmostApplication else { return } - if let bid = frontApp.bundleIdentifier?.lowercased(), - bid.contains("siri") || bid.contains("shortcuts") { - print("InputBoxManager: Frontmost app is Siri/Shortcuts (\(bid)), preserving user app focus.") - return - } - let appElem = AXUIElementCreateApplication(frontApp.processIdentifier) - - // 1. Check if an element is already focused in the frontmost application - var focusedObj: CFTypeRef? - if AXUIElementCopyAttributeValue(appElem, kAXFocusedUIElementAttribute as CFString, &focusedObj) == .success, - focusedObj != nil { - return - } - - // 2. Check systemWide focus - let sysWide = AXUIElementCreateSystemWide() - if AXUIElementCopyAttributeValue(sysWide, kAXFocusedUIElementAttribute as CFString, &focusedObj) == .success, - focusedObj != nil { - return - } - - // 3. Only if NOTHING is focused, search active window and gently set focus - var windowObj: CFTypeRef? - if AXUIElementCopyAttributeValue(appElem, kAXFocusedWindowAttribute as CFString, &windowObj) == .success, - let win = windowObj { - let winElem = (win as! AXUIElement) - if let bestInput = findBestInputElement(in: winElem) { - print("InputBoxManager: No active focus detected. Gently focusing target input field in \(frontApp.localizedName ?? "").") - AXUIElementSetAttributeValue(bestInput, kAXFocusedAttribute as CFString, kCFBooleanTrue) - } - } + // Focus is 100% user-directed. We preserve whatever the user focused (web text input, + // native text box, code editor, or address bar). Never forcibly steal focus to any toolbar or omnibox. } /// Streams word-by-word delta text directly into the focused input box in real time @@ -408,26 +378,5 @@ public final class InputBoxManager { } } - private func findBestInputElement(in parent: AXUIElement, maxDepth: Int = 8, depth: Int = 0) -> AXUIElement? { - if depth > maxDepth { return nil } - - var roleObj: CFTypeRef? - AXUIElementCopyAttributeValue(parent, kAXRoleAttribute as CFString, &roleObj) - let role = (roleObj as? String) ?? "" - - if role == "AXTextField" || role == "AXTextArea" || role == "AXComboBox" { - return parent - } - - var childrenObj: CFTypeRef? - if AXUIElementCopyAttributeValue(parent, kAXChildrenAttribute as CFString, &childrenObj) == .success, - let children = childrenObj as? [AXUIElement] { - for child in children { - if let found = findBestInputElement(in: child, maxDepth: maxDepth, depth: depth + 1) { - return found - } - } - } - return nil - } + } diff --git a/src/TextProcessor.swift b/src/TextProcessor.swift index 61f411e..b56ae53 100644 --- a/src/TextProcessor.swift +++ b/src/TextProcessor.swift @@ -49,6 +49,9 @@ public final class TextProcessor { // 3. Number Formatting result = applyNumberFormatting(result, format: SonioxSettings.shared.numberFormat) + // 3.5. Sanitize foreign hallucinations & word loops + result = SonioxLiveSession.sanitizeText(result) + // 4. Text Normalization if SonioxSettings.shared.normalizeText { result = normalizeText(result) @@ -120,6 +123,14 @@ public final class TextProcessor { private func applyDomainVocabulary(_ text: String) -> String { var t = text let terms: [(String, String)] = [ + ("این اپ پرچس", "In-App Purchase"), + ("این اپ پرشرز", "In-App Purchase"), + ("اپ پرشرز", "In-App Purchases"), + ("اپل کانکت", "App Store Connect"), + ("اپ استور کانکت", "App Store Connect"), + ("حجزی مرچنت", "Hajzee Merchant"), + ("حجزی یوزر", "Hajzee User"), + ("حجزی", "Hajzee"), ("نیوهورایزن", "NewHorizon"), ("نیو هورایزن", "NewHorizon"), ("نیوهوریزن", "NewHorizon"), @@ -247,6 +258,18 @@ public final class TextProcessor { for p in [".", "،", "؛", "؟", "!"] { t = t.replacingOccurrences(of: p, with: p + " ") } + // Common ASR stutter & merged word fixes + let speechFixes: [(String, String)] = [ + (" ماا ", " ما "), + (" اینپیگیری ", " این پیگیری "), + (" می‌کنکنیم ", " می‌کنیم "), + (" سر سمانش ", " سر و سامانش "), + (" دست و پا گیرلی ", " دست و پا گیر ولی ") + ] + for (bad, good) in speechFixes { + t = t.replacingOccurrences(of: bad, with: good) + } + // Fix spaces inside parentheses / quotes t = t.replacingOccurrences(of: "( ", with: "(") t = t.replacingOccurrences(of: "« ", with: "«")