Browse Source

fix: ultra-fast zero-delay switching, truncated digit 'د' support, and extensive acoustic Antigravity/IDE variations

main
Ali Alavi 4 hours ago
parent
commit
c8503d8c52
  1. 88
      src/VoiceCommandExecutor.swift

88
src/VoiceCommandExecutor.swift

@ -419,19 +419,44 @@ public final class VoiceCommandExecutor {
private func matchAntigravity(normalized: String) -> String? { private func matchAntigravity(normalized: String) -> String? {
let hasAnti = normalized.contains("انتی") || normalized.contains("anti") || let hasAnti = normalized.contains("انتی") || normalized.contains("anti") ||
normalized.contains("on the") || normalized.contains("in the") || normalized.contains("and the") normalized.contains("on the") || normalized.contains("in the") || normalized.contains("and the")
let hasGravity = normalized.contains("گراویتی") || normalized.contains("گرویتی") || normalized.contains("gravity") || normalized.contains("graphity")
guard (hasAnti && hasGravity) || normalized.contains("antigravity") || normalized.contains("انتیگراویتی") || normalized.contains("انتیگرویتی") else {
let hasGravity = normalized.contains("گراویتی") ||
normalized.contains("گرویتی") ||
normalized.contains("گریویتی") ||
normalized.contains("گریتی") ||
normalized.contains("گرایتی") ||
normalized.contains("گروتی") ||
normalized.contains("گویتی") ||
normalized.contains("gravity") ||
normalized.contains("graphity") ||
normalized.contains("graviti") ||
normalized.contains("gravty")
let isFusedAntiGravity = normalized.contains("antigravity") ||
normalized.contains("انتیگراویتی") ||
normalized.contains("انتیگرویتی") ||
normalized.contains("انتیگریویتی") ||
normalized.contains("انتیگریتی") ||
normalized.contains("انتیگرایتی")
guard (hasAnti && hasGravity) || isFusedAntiGravity else {
return nil return nil
} }
// Strict explicit check for IDE / Editor (Black Icon App) // Strict explicit check for IDE / Editor (Black Icon App)
let isIDE = normalized.contains("ای دی ای") || let isIDE = normalized.contains("ای دی ای") ||
normalized.contains("ایدی ای") || normalized.contains("ایدی ای") ||
normalized.contains("ای دی") ||
normalized.contains("ایدی") ||
normalized.contains("ایدیای") || normalized.contains("ایدیای") ||
normalized.contains("ایدیا") ||
normalized.contains("آیدی ای") || normalized.contains("آیدی ای") ||
normalized.contains("آی دی ای") ||
normalized.contains("آیدی") ||
normalized.contains("آی دی") ||
normalized.contains("ide") || normalized.contains("ide") ||
normalized.contains("ادیتور")
normalized.contains("ادیتور") ||
normalized.contains("کد")
// If IDE is mentioned -> "Antigravity IDE" (Black icon) // If IDE is mentioned -> "Antigravity IDE" (Black icon)
// If standalone / "2" -> "Antigravity" (White icon app, Antigravity 2) // If standalone / "2" -> "Antigravity" (White icon app, Antigravity 2)
@ -640,9 +665,9 @@ public final class VoiceCommandExecutor {
// 2. Word numbers (Persian & English cardinal and ordinal) // 2. Word numbers (Persian & English cardinal and ordinal)
let numberWords: [(names: [String], num: Int)] = [ let numberWords: [(names: [String], num: Int)] = [
(["یک", "اول", "نخست", "one", "first"], 1),
(["دو", "دوم", "two", "second"], 2),
(["سه", "سوم", "three", "third"], 3),
(["یک", "اول", "نخست", "ی", "one", "first"], 1),
(["دو", "دوم", "د", "two", "second"], 2),
(["سه", "سوم", "س", "three", "third"], 3),
(["چهار", "چهارم", "four", "fourth"], 4), (["چهار", "چهارم", "four", "fourth"], 4),
(["پنج", "پنجم", "five", "fifth"], 5), (["پنج", "پنجم", "five", "fifth"], 5),
(["شش", "ششم", "six", "sixth"], 6), (["شش", "ششم", "six", "sixth"], 6),
@ -768,7 +793,7 @@ public final class VoiceCommandExecutor {
guard let code = keyCodes[number] else { return } guard let code = keyCodes[number] else { return }
// For Telegram Desktop: Send Cmd+[number] and Cmd+Shift+[number] (configured via shortcuts-custom.json) // For Telegram Desktop: Send Cmd+[number] and Cmd+Shift+[number] (configured via shortcuts-custom.json)
pressHotkey(keyCode: code, modifiers: .maskCommand) pressHotkey(keyCode: code, modifiers: .maskCommand)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.12) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) {
self.pressHotkey(keyCode: code, modifiers: [.maskCommand, .maskShift]) self.pressHotkey(keyCode: code, modifiers: [.maskCommand, .maskShift])
} }
} }
@ -1080,15 +1105,13 @@ public final class VoiceCommandExecutor {
} }
private func pressHotkey(keyCode: CGKeyCode, modifiers: CGEventFlags) { private func pressHotkey(keyCode: CGKeyCode, modifiers: CGEventFlags) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.08) {
let source = CGEventSource(stateID: .combinedSessionState)
if let down = CGEvent(keyboardEventSource: source, virtualKey: keyCode, keyDown: true),
let up = CGEvent(keyboardEventSource: source, virtualKey: keyCode, keyDown: false) {
down.flags = modifiers
up.flags = modifiers
down.post(tap: .cghidEventTap)
up.post(tap: .cghidEventTap)
}
let source = CGEventSource(stateID: .combinedSessionState)
if let down = CGEvent(keyboardEventSource: source, virtualKey: keyCode, keyDown: true),
let up = CGEvent(keyboardEventSource: source, virtualKey: keyCode, keyDown: false) {
down.flags = modifiers
up.flags = modifiers
down.post(tap: .cghidEventTap)
up.post(tap: .cghidEventTap)
} }
} }
@ -1114,6 +1137,13 @@ public final class VoiceCommandExecutor {
}) })
if let running = runningApp { if let running = runningApp {
// Instant path: if the app is ALREADY frontmost (e.g. user is in Telegram switching accounts)
if running.isActive {
ensureWindowFullScreen(app: running)
completion?()
return
}
// Check if app has any open windows // Check if app has any open windows
let appElem = AXUIElementCreateApplication(running.processIdentifier) let appElem = AXUIElementCreateApplication(running.processIdentifier)
var winListObj: CFTypeRef? var winListObj: CFTypeRef?
@ -1121,18 +1151,22 @@ public final class VoiceCommandExecutor {
((winListObj as? [AXUIElement])?.isEmpty == false) ((winListObj as? [AXUIElement])?.isEmpty == false)
if hasWindows { if hasWindows {
// Force macOS WindowServer to switch Spaces
runAppleScript("tell application \"\(appName)\" to activate")
let task = Process()
task.executableURL = URL(fileURLWithPath: "/usr/bin/open")
task.arguments = ["-a", appName]
try? task.run()
running.activate(options: [.activateIgnoringOtherApps]) running.activate(options: [.activateIgnoringOtherApps])
// Force macOS WindowServer to switch Spaces asynchronously
DispatchQueue.global(qos: .userInteractive).async {
let task = Process()
task.executableURL = URL(fileURLWithPath: "/usr/bin/open")
task.arguments = ["-a", appName]
try? task.run()
}
ensureWindowFullScreen(app: running) ensureWindowFullScreen(app: running)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
running.activate(options: [.activateIgnoringOtherApps])
completion?()
if let comp = completion {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.03) {
comp()
}
} }
return return
} else { } else {
@ -1144,7 +1178,7 @@ public final class VoiceCommandExecutor {
task.arguments = ["-a", appName] task.arguments = ["-a", appName]
try? task.run() try? task.run()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.08) {
self.pollAndMakeFullScreen(app: running, targetBid: targetBid, appName: appName, completion: completion) self.pollAndMakeFullScreen(app: running, targetBid: targetBid, appName: appName, completion: completion)
} }
return return

Loading…
Cancel
Save