import Foundation import KeyboardShortcuts import AppKit extension KeyboardShortcuts.Name { static let escapeRecorder = Self("escapeRecorder") static let cancelRecorder = Self("cancelRecorder") static let toggleEnhancement = Self("toggleEnhancement") // AI Prompt selection shortcuts static let selectPrompt1 = Self("selectPrompt1") static let selectPrompt2 = Self("selectPrompt2") static let selectPrompt3 = Self("selectPrompt3") static let selectPrompt4 = Self("selectPrompt4") static let selectPrompt5 = Self("selectPrompt5") static let selectPrompt6 = Self("selectPrompt6") static let selectPrompt7 = Self("selectPrompt7") static let selectPrompt8 = Self("selectPrompt8") static let selectPrompt9 = Self("selectPrompt9") static let selectPrompt10 = Self("selectPrompt10") // Power Mode selection shortcuts static let selectPowerMode1 = Self("selectPowerMode1") static let selectPowerMode2 = Self("selectPowerMode2") static let selectPowerMode3 = Self("selectPowerMode3") static let selectPowerMode4 = Self("selectPowerMode4") static let selectPowerMode5 = Self("selectPowerMode5") static let selectPowerMode6 = Self("selectPowerMode6") static let selectPowerMode7 = Self("selectPowerMode7") static let selectPowerMode8 = Self("selectPowerMode8") static let selectPowerMode9 = Self("selectPowerMode9") static let selectPowerMode10 = Self("selectPowerMode10") } @MainActor class MiniRecorderShortcutManager: ObservableObject { private var whisperState: WhisperState private var visibilityTask: Task? private var isCancelHandlerSetup = false // Double-tap Escape handling private var escFirstPressTime: Date? = nil private let escSecondPressThreshold: TimeInterval = 1.5 private var isEscapeHandlerSetup = false private var escapeTimeoutTask: Task? init(whisperState: WhisperState) { self.whisperState = whisperState setupVisibilityObserver() setupEnhancementShortcut() setupEscapeHandlerOnce() setupCancelHandlerOnce() } private func setupVisibilityObserver() { visibilityTask = Task { @MainActor in for await isVisible in whisperState.$isMiniRecorderVisible.values { if isVisible { activateEscapeShortcut() activateCancelShortcut() KeyboardShortcuts.setShortcut(.init(.e, modifiers: .command), for: .toggleEnhancement) setupPromptShortcuts() setupPowerModeShortcuts() } else { deactivateEscapeShortcut() deactivateCancelShortcut() removeEnhancementShortcut() removePromptShortcuts() removePowerModeShortcuts() } } } } // Setup escape handler once private func setupEscapeHandlerOnce() { guard !isEscapeHandlerSetup else { return } isEscapeHandlerSetup = true KeyboardShortcuts.onKeyDown(for: .escapeRecorder) { [weak self] in Task { @MainActor in guard let self = self, await self.whisperState.isMiniRecorderVisible else { return } // Don't process if custom shortcut is configured guard KeyboardShortcuts.getShortcut(for: .cancelRecorder) == nil else { return } let now = Date() if let firstTime = self.escFirstPressTime, now.timeIntervalSince(firstTime) <= self.escSecondPressThreshold { self.escFirstPressTime = nil SoundManager.shared.playEscSound() await self.whisperState.dismissMiniRecorder() } else { self.escFirstPressTime = now SoundManager.shared.playEscSound() NotificationManager.shared.showNotification( title: "Press ESC again to cancel recording", type: .info, duration: self.escSecondPressThreshold ) self.escapeTimeoutTask = Task { [weak self] in try? await Task.sleep(nanoseconds: UInt64((self?.escSecondPressThreshold ?? 1.5) * 1_000_000_000)) await MainActor.run { self?.escFirstPressTime = nil } } } } } } private func activateEscapeShortcut() { // Don't activate if custom shortcut is configured guard KeyboardShortcuts.getShortcut(for: .cancelRecorder) == nil else { return } KeyboardShortcuts.setShortcut(.init(.escape), for: .escapeRecorder) } // Setup cancel handler once private func setupCancelHandlerOnce() { guard !isCancelHandlerSetup else { return } isCancelHandlerSetup = true KeyboardShortcuts.onKeyDown(for: .cancelRecorder) { [weak self] in Task { @MainActor in guard let self = self, await self.whisperState.isMiniRecorderVisible, KeyboardShortcuts.getShortcut(for: .cancelRecorder) != nil else { return } SoundManager.shared.playEscSound() await self.whisperState.dismissMiniRecorder() } } } private func activateCancelShortcut() { // Handler checks if shortcut exists } private func deactivateEscapeShortcut() { KeyboardShortcuts.setShortcut(nil, for: .escapeRecorder) escFirstPressTime = nil escapeTimeoutTask?.cancel() escapeTimeoutTask = nil } private func deactivateCancelShortcut() { // Shortcut managed by user settings } private func setupEnhancementShortcut() { KeyboardShortcuts.onKeyDown(for: .toggleEnhancement) { [weak self] in Task { @MainActor in guard let self = self, await self.whisperState.isMiniRecorderVisible, let enhancementService = await self.whisperState.getEnhancementService() else { return } enhancementService.isEnhancementEnabled.toggle() } } } private func setupPowerModeShortcuts() { KeyboardShortcuts.setShortcut(.init(.one, modifiers: .option), for: .selectPowerMode1) KeyboardShortcuts.setShortcut(.init(.two, modifiers: .option), for: .selectPowerMode2) KeyboardShortcuts.setShortcut(.init(.three, modifiers: .option), for: .selectPowerMode3) KeyboardShortcuts.setShortcut(.init(.four, modifiers: .option), for: .selectPowerMode4) KeyboardShortcuts.setShortcut(.init(.five, modifiers: .option), for: .selectPowerMode5) KeyboardShortcuts.setShortcut(.init(.six, modifiers: .option), for: .selectPowerMode6) KeyboardShortcuts.setShortcut(.init(.seven, modifiers: .option), for: .selectPowerMode7) KeyboardShortcuts.setShortcut(.init(.eight, modifiers: .option), for: .selectPowerMode8) KeyboardShortcuts.setShortcut(.init(.nine, modifiers: .option), for: .selectPowerMode9) KeyboardShortcuts.setShortcut(.init(.zero, modifiers: .option), for: .selectPowerMode10) // Setup handlers setupPowerModeHandler(for: .selectPowerMode1, index: 0) setupPowerModeHandler(for: .selectPowerMode2, index: 1) setupPowerModeHandler(for: .selectPowerMode3, index: 2) setupPowerModeHandler(for: .selectPowerMode4, index: 3) setupPowerModeHandler(for: .selectPowerMode5, index: 4) setupPowerModeHandler(for: .selectPowerMode6, index: 5) setupPowerModeHandler(for: .selectPowerMode7, index: 6) setupPowerModeHandler(for: .selectPowerMode8, index: 7) setupPowerModeHandler(for: .selectPowerMode9, index: 8) setupPowerModeHandler(for: .selectPowerMode10, index: 9) } private func setupPowerModeHandler(for shortcutName: KeyboardShortcuts.Name, index: Int) { KeyboardShortcuts.onKeyDown(for: shortcutName) { [weak self] in Task { @MainActor in guard let self = self, await self.whisperState.isMiniRecorderVisible else { return } let powerModeManager = PowerModeManager.shared if !powerModeManager.enabledConfigurations.isEmpty { let availableConfigurations = powerModeManager.enabledConfigurations if index < availableConfigurations.count { let selectedConfig = availableConfigurations[index] powerModeManager.setActiveConfiguration(selectedConfig) await PowerModeSessionManager.shared.beginSession(with: selectedConfig) } } } } } private func removePowerModeShortcuts() { KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode1) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode2) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode3) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode4) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode5) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode6) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode7) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode8) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode9) KeyboardShortcuts.setShortcut(nil, for: .selectPowerMode10) } private func setupPromptShortcuts() { KeyboardShortcuts.setShortcut(.init(.one, modifiers: .command), for: .selectPrompt1) KeyboardShortcuts.setShortcut(.init(.two, modifiers: .command), for: .selectPrompt2) KeyboardShortcuts.setShortcut(.init(.three, modifiers: .command), for: .selectPrompt3) KeyboardShortcuts.setShortcut(.init(.four, modifiers: .command), for: .selectPrompt4) KeyboardShortcuts.setShortcut(.init(.five, modifiers: .command), for: .selectPrompt5) KeyboardShortcuts.setShortcut(.init(.six, modifiers: .command), for: .selectPrompt6) KeyboardShortcuts.setShortcut(.init(.seven, modifiers: .command), for: .selectPrompt7) KeyboardShortcuts.setShortcut(.init(.eight, modifiers: .command), for: .selectPrompt8) KeyboardShortcuts.setShortcut(.init(.nine, modifiers: .command), for: .selectPrompt9) KeyboardShortcuts.setShortcut(.init(.zero, modifiers: .command), for: .selectPrompt10) // Setup handlers setupPromptHandler(for: .selectPrompt1, index: 0) setupPromptHandler(for: .selectPrompt2, index: 1) setupPromptHandler(for: .selectPrompt3, index: 2) setupPromptHandler(for: .selectPrompt4, index: 3) setupPromptHandler(for: .selectPrompt5, index: 4) setupPromptHandler(for: .selectPrompt6, index: 5) setupPromptHandler(for: .selectPrompt7, index: 6) setupPromptHandler(for: .selectPrompt8, index: 7) setupPromptHandler(for: .selectPrompt9, index: 8) setupPromptHandler(for: .selectPrompt10, index: 9) } private func setupPromptHandler(for shortcutName: KeyboardShortcuts.Name, index: Int) { KeyboardShortcuts.onKeyDown(for: shortcutName) { [weak self] in Task { @MainActor in guard let self = self, await self.whisperState.isMiniRecorderVisible else { return } guard let enhancementService = await self.whisperState.getEnhancementService() else { return } let availablePrompts = enhancementService.allPrompts if index < availablePrompts.count { if !enhancementService.isEnhancementEnabled { enhancementService.isEnhancementEnabled = true } enhancementService.setActivePrompt(availablePrompts[index]) } } } } private func removePromptShortcuts() { KeyboardShortcuts.setShortcut(nil, for: .selectPrompt1) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt2) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt3) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt4) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt5) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt6) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt7) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt8) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt9) KeyboardShortcuts.setShortcut(nil, for: .selectPrompt10) } private func removeEnhancementShortcut() { KeyboardShortcuts.setShortcut(nil, for: .toggleEnhancement) } deinit { visibilityTask?.cancel() Task { @MainActor in deactivateEscapeShortcut() deactivateCancelShortcut() removeEnhancementShortcut() removePowerModeShortcuts() } } }