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: "«")