import Cocoa /// 菜单栏控制器:管理状态栏图标和菜单 final class MenuBarController: NSObject { private let statusItem: NSStatusItem private let menu = NSMenu() private var languageMenuItems: [NSMenuItem] = [] // Input LLM (Fn 键 - 语音输入纠错) private let inputLLMSubmenu = NSMenu() private let inputLLMEnabledItem: NSMenuItem // Assist LLM (Control 键 - AI 助手) private let assistLLMSubmenu = NSMenu() private let assistLLMEnabledItem: NSMenuItem // 设置窗口 private let inputSettingsWindow: SettingsWindow private let assistSettingsWindow: SettingsWindow override init() { statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) // Input LLM 启用项 inputLLMEnabledItem = NSMenuItem( title: "Enable", action: #selector(toggleInputLLM), keyEquivalent: "" ) // Assist LLM 启用项 assistLLMEnabledItem = NSMenuItem( title: "Enable", action: #selector(toggleAssistLLM), keyEquivalent: "" ) // 创建两个设置窗口 inputSettingsWindow = SettingsWindow(mode: .input) assistSettingsWindow = SettingsWindow(mode: .assist) super.init() configureStatusItem() buildMenu() } private func configureStatusItem() { if let button = statusItem.button { button.image = NSImage( systemSymbolName: "mic.fill", accessibilityDescription: "Voice Input" ) button.toolTip = "Voice Input — 按住 Fn 键录音" } } private func buildMenu() { // 当前语言显示 let currentLanguageItem = NSMenuItem( title: "Language: \(Config.shared.language.displayName)", action: nil, keyEquivalent: "" ) currentLanguageItem.isEnabled = false menu.addItem(currentLanguageItem) menu.addItem(.separator()) // 语言选择子菜单 let languageMenu = NSMenu() for lang in RecognitionLanguage.allCases { let item = NSMenuItem( title: lang.displayName, action: #selector(selectLanguage(_:)), keyEquivalent: "" ) item.representedObject = lang item.state = lang == Config.shared.language ? .on : .off languageMenu.addItem(item) languageMenuItems.append(item) } let languageSubmenuItem = NSMenuItem() languageSubmenuItem.title = "Language" languageSubmenuItem.submenu = languageMenu menu.addItem(languageSubmenuItem) menu.addItem(.separator()) // ===== Input LLM (Fn 键 - 语音输入纠错) ===== inputLLMSubmenu.addItem(inputLLMEnabledItem) inputLLMEnabledItem.target = self inputLLMEnabledItem.action = #selector(toggleInputLLM) updateInputLLMMenuState() let inputSettingsItem = NSMenuItem( title: "Settings...", action: #selector(openInputSettings), keyEquivalent: "" ) inputSettingsItem.target = self inputLLMSubmenu.addItem(inputSettingsItem) let inputSubmenuItem = NSMenuItem() inputSubmenuItem.title = "🎤 Input LLM (Fn)" inputSubmenuItem.submenu = inputLLMSubmenu menu.addItem(inputSubmenuItem) menu.addItem(.separator()) // ===== Assist LLM (Control 键 - AI 助手) ===== assistLLMSubmenu.addItem(assistLLMEnabledItem) assistLLMEnabledItem.target = self assistLLMEnabledItem.action = #selector(toggleAssistLLM) updateAssistLLMMenuState() let assistSettingsItem = NSMenuItem( title: "Settings...", action: #selector(openAssistSettings), keyEquivalent: "" ) assistSettingsItem.target = self assistLLMSubmenu.addItem(assistSettingsItem) let assistSubmenuItem = NSMenuItem() assistSubmenuItem.title = "💬 Assist LLM (Control)" assistSubmenuItem.submenu = assistLLMSubmenu menu.addItem(assistSubmenuItem) menu.addItem(.separator()) // 退出 let quitItem = NSMenuItem( title: "Quit", action: #selector(quit), keyEquivalent: "q" ) quitItem.target = self menu.addItem(quitItem) statusItem.menu = menu } private func updateInputLLMMenuState() { inputLLMEnabledItem.state = Config.shared.inputLLM.enabled ? .on : .off } private func updateAssistLLMMenuState() { assistLLMEnabledItem.state = Config.shared.assistLLM.enabled ? .on : .off } private func updateLanguageMenuState() { for item in languageMenuItems { guard let lang = item.representedObject as? RecognitionLanguage else { continue } item.state = lang == Config.shared.language ? .on : .off } // 更新第一项的显示 if let first = menu.items.first { first.title = "Language: \(Config.shared.language.displayName)" } } @objc private func selectLanguage(_ sender: NSMenuItem) { guard let lang = sender.representedObject as? RecognitionLanguage else { return } Config.shared.language = lang updateLanguageMenuState() print("[Menu] Language switched to: \(lang.displayName)") } @objc private func toggleInputLLM() { var config = Config.shared.inputLLM config.enabled.toggle() Config.shared.inputLLM = config updateInputLLMMenuState() print("[Menu] Input LLM: \(config.enabled ? "ON" : "OFF")") } @objc private func toggleAssistLLM() { var config = Config.shared.assistLLM config.enabled.toggle() Config.shared.assistLLM = config updateAssistLLMMenuState() print("[Menu] Assist LLM: \(config.enabled ? "ON" : "OFF")") } @objc private func openInputSettings() { inputSettingsWindow.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) } @objc private func openAssistSettings() { assistSettingsWindow.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) } @objc private func quit() { NSApp.terminate(nil) } }