From 9347ceffeb14d23cf881721acde4787c541e5536 Mon Sep 17 00:00:00 2001 From: r3dbars Date: Wed, 7 Oct 2026 06:34:58 -0500 Subject: [PATCH] Shortcuts: remove dead paste-last and Hands-Free shortcut code 1.1.70 made dictation one key with a behavior picker, but the old paste-last shortcut and separate Hands-Free binding stayed in the tree. Remove the paste-last action, its event-tap routing, callback and stored binding, plus the unused Hands-Free binding writer and the DictationShortcutMode title/summary/writer. The legacy mode read stays, renamed legacyDictationShortcutMode, for the one-key migration. Kept on purpose: DictationShortcutMode.handsFree (models tap-kept and Tap to toggle takes; raw value is the shortcut_mode telemetry tag), .dictationHandsFree routing, and PasteLastDictationFeedback (the island's "Paste again" chip still uses it). --- Sources/App/TranscriptedApp.swift | 3 - Sources/App/TranscriptedMenuCommands.swift | 2 +- Sources/Capture/ContextCaptureEngine.swift | 34 +-- Sources/Capture/PhysicalShortcutMatcher.swift | 2 - ...DictationRecordingStartOverlayPolicy.swift | 4 +- Sources/Speech/DictationStartReadiness.swift | 3 +- Sources/Support/HotkeyPreferences.swift | 39 +--- .../PhysicalDictationTriggerPreferences.swift | 46 +---- Sources/UI/MenuBar/MenuBarShortcutLabel.swift | 6 +- .../Overlay/DictationSessionController.swift | 2 +- Tests/ContextCaptureEnginePolicyTests.swift | 71 +------ Tests/HotkeyPreferencesTests.swift | 30 +-- ...icalDictationTriggerPreferencesTests.swift | 193 +++--------------- Tests/PhysicalShortcutMatcherTests.swift | 6 - 14 files changed, 72 insertions(+), 369 deletions(-) diff --git a/Sources/App/TranscriptedApp.swift b/Sources/App/TranscriptedApp.swift index d3fe63a71..7638f71e4 100644 --- a/Sources/App/TranscriptedApp.swift +++ b/Sources/App/TranscriptedApp.swift @@ -486,9 +486,6 @@ class TranscriptedAppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegat appState.contextCapture.onMeetingToggle = { [weak self] in self?.meetingOverlayController.toggleFromHotkey() } - appState.contextCapture.onPasteLastDictation = { [weak self] in - self?.pasteLastDictationFromSettings() - } SpeakerNamingSheet.shared.island = notchIsland // Only the island lists voices named on their own ("who was on // the call"), so only then does a meeting with nobody to ask get diff --git a/Sources/App/TranscriptedMenuCommands.swift b/Sources/App/TranscriptedMenuCommands.swift index 2ad96083e..4c971241f 100644 --- a/Sources/App/TranscriptedMenuCommands.swift +++ b/Sources/App/TranscriptedMenuCommands.swift @@ -4,7 +4,7 @@ // // This is purely additive: every action routes through an existing app-delegate // entry point, and none of the user's recordable dictation / meeting triggers -// (push-to-talk, hands-free, meeting, paste-last) are remapped. The commands +// (dictation, meeting) are remapped. The commands // only fire while the app is active (a window is open), which is exactly when // navigation, search, and in-app capture make sense; the global physical // triggers remain the background path. diff --git a/Sources/Capture/ContextCaptureEngine.swift b/Sources/Capture/ContextCaptureEngine.swift index 471963de4..63f9db957 100644 --- a/Sources/Capture/ContextCaptureEngine.swift +++ b/Sources/Capture/ContextCaptureEngine.swift @@ -297,8 +297,6 @@ private final class PhysicalShortcutDetector { onShortcut?(.dictationHandsFree, .press) case .meeting: onShortcut?(.meeting, .press) - case .pasteLastDictation: - onShortcut?(.pasteLastDictation, .press) } return nil @@ -410,13 +408,6 @@ private final class PhysicalShortcutDetector { cancelPendingModifierShortcut() onShortcut?(.meeting, .press) } - case .pasteLastDictation: - if hasChordUsingModifier(keyCode, in: shortcutBindings, excluding: shortcut.action) { - schedulePendingModifierShortcut(keyCode: keyCode, action: .pasteLastDictation) - } else { - cancelPendingModifierShortcut() - onShortcut?(.pasteLastDictation, .press) - } } return nil @@ -606,8 +597,6 @@ class ContextCaptureEngine: ObservableObject { /// the meeting subsystem is unavailable — the hotkey simply does nothing. var onMeetingToggle: (() -> Void)? - var onPasteLastDictation: (() -> Void)? - func registerHotkey() { guard hotkeyChangeObserver == nil else { EventReporter.shared.capture(level: .warning, engine: "capture", event: "hotkey_already_registered", @@ -767,15 +756,13 @@ class ContextCaptureEngine: ObservableObject { handlePhysicalDictationHandsFreeComboInterrupted() case (.meeting, .press): handlePhysicalMeetingPress() - case (.pasteLastDictation, .press): - handlePhysicalPasteLastDictationPress() - case (.dictationHandsFree, .release), (.meeting, .release), (.pasteLastDictation, .release): + case (.dictationHandsFree, .release), (.meeting, .release): break - case (.dictationHandsFree, .tapRelease), (.meeting, .tapRelease), (.pasteLastDictation, .tapRelease): + case (.dictationHandsFree, .tapRelease), (.meeting, .tapRelease): break case (.dictationPushToTalk, .comboInterrupted): handlePhysicalDictationPushToTalkComboInterrupted() - case (.meeting, .comboInterrupted), (.pasteLastDictation, .comboInterrupted): + case (.meeting, .comboInterrupted): break } } @@ -807,21 +794,6 @@ class ContextCaptureEngine: ObservableObject { onMeetingToggle?() } - private func handlePhysicalPasteLastDictationPress() { - guard shouldAcceptHotkeyAction(.pasteLastDictation) else { - EventReporter.shared.capture( - level: .info, - engine: "capture", - event: "hotkey_repeat_ignored", - message: "Ignored rapid repeat paste-last-dictation trigger", - context: ["hotkey_id": "paste_last_dictation_physical_trigger"] - ) - return - } - - onPasteLastDictation?() - } - deinit { if let observer = hotkeyChangeObserver { NotificationCenter.default.removeObserver(observer) diff --git a/Sources/Capture/PhysicalShortcutMatcher.swift b/Sources/Capture/PhysicalShortcutMatcher.swift index c0e7af589..1e3d23c93 100644 --- a/Sources/Capture/PhysicalShortcutMatcher.swift +++ b/Sources/Capture/PhysicalShortcutMatcher.swift @@ -16,7 +16,6 @@ enum PhysicalShortcutAction: Equatable { case dictationPushToTalk case dictationHandsFree case meeting - case pasteLastDictation } struct PhysicalShortcutBinding { @@ -241,7 +240,6 @@ extension PhysicalShortcutAction { case .dictationPushToTalk: return nil case .dictationHandsFree: return "dictation_hands_free" case .meeting: return "meeting_physical_trigger" - case .pasteLastDictation: return "paste_last_dictation_physical_trigger" } } } diff --git a/Sources/Speech/DictationRecordingStartOverlayPolicy.swift b/Sources/Speech/DictationRecordingStartOverlayPolicy.swift index 52e0ea125..c5b372b3b 100644 --- a/Sources/Speech/DictationRecordingStartOverlayPolicy.swift +++ b/Sources/Speech/DictationRecordingStartOverlayPolicy.swift @@ -215,8 +215,8 @@ struct DictationEarlyReleasePresentationPolicy { struct DictationEarlyReleaseCancelReport: Equatable { static let engine = "dictation" static let event = "dictation_cancelled_before_microphone_ready" - // Deliberately not "push-to-talk release": hands-free is the default - // mode, and its stop press reaches here too. + // Deliberately not "push-to-talk release": Tap to toggle (and a + // tap-kept take) stops on a press, and that press reaches here too. static let message = "Dictation hotkey ended the session before the microphone finished opening" /// `.error`, not `.info`: only `.error` events reach the reliability /// counter (PostHog) and Sentry. The user asked to dictate, saw an error, diff --git a/Sources/Speech/DictationStartReadiness.swift b/Sources/Speech/DictationStartReadiness.swift index bfe4cef79..134e9b70f 100644 --- a/Sources/Speech/DictationStartReadiness.swift +++ b/Sources/Speech/DictationStartReadiness.swift @@ -95,8 +95,7 @@ enum DictationStartReadinessPolicy { /// /// Only `physical_key` is listed because it is the only trigger anything /// emits for a global hotkey: `ContextCaptureEngine` uses it for both the - /// push-to-talk press/release pair AND the hands-free toggle (the default - /// mode). `DictationTrigger.keyboardShortcut` and `.rightOptionTap` are + /// push-to-talk press/release pair AND the Tap to toggle press. `DictationTrigger.keyboardShortcut` and `.rightOptionTap` are /// declared but never constructed anywhere in the tree — #1744's guard /// listed them, which read as coverage it did not have. Wire them up here /// if something ever emits them. diff --git a/Sources/Support/HotkeyPreferences.swift b/Sources/Support/HotkeyPreferences.swift index 9927f0247..ad9af2f51 100644 --- a/Sources/Support/HotkeyPreferences.swift +++ b/Sources/Support/HotkeyPreferences.swift @@ -10,29 +10,12 @@ struct HotkeyBinding: Equatable { let modifiers: UInt32 // Carbon modifier mask } -enum DictationShortcutMode: String, CaseIterable, Identifiable, Hashable { +/// How one dictation take is being driven. `.pushToTalk` ends on key release; +/// `.handsFree` (raw value kept for telemetry) is a take that stays listening +/// until the next press: Tap to toggle, or a Hold or tap take kept by a tap. +enum DictationShortcutMode: String, Hashable { case pushToTalk = "push_to_talk" case handsFree = "hands_free" - - var id: String { rawValue } - - var title: String { - switch self { - case .pushToTalk: - return "Push to Talk" - case .handsFree: - return "Hands-Free" - } - } - - var summary: String { - switch self { - case .pushToTalk: - return "Hold the dictation shortcut, speak, then release to paste." - case .handsFree: - return "Press once to start dictation, then press again to paste." - } - } } /// What the one dictation key does, like Handy's Shortcut Behavior. @@ -67,7 +50,6 @@ enum HotkeyPreferences { static let defaultDictation = HotkeyBinding(keyCode: UInt32(kVK_Space), modifiers: UInt32(optionKey)) static let defaultMeeting = HotkeyBinding(keyCode: UInt32(kVK_ANSI_M), modifiers: UInt32(optionKey)) - static let defaultDictationShortcutMode: DictationShortcutMode = .handsFree // MARK: - Right Option Tap-to-Dictate @@ -121,14 +103,16 @@ enum HotkeyPreferences { userDefaults.object(forKey: meetingKeyCodeKey) != nil } - static func dictationShortcutMode(userDefaults: UserDefaults = .standard) -> DictationShortcutMode { + /// Pre-one-key builds stored a Push to Talk or Hands-Free mode. Only the + /// legacy binding migration reads it. A missing or unknown value was + /// treated as Hands-Free, so it still is. + static func legacyDictationShortcutMode(userDefaults: UserDefaults = .standard) -> DictationShortcutMode { guard let rawValue = userDefaults.string(forKey: dictationShortcutModeKey), let mode = DictationShortcutMode(rawValue: rawValue) else { - return defaultDictationShortcutMode + return .handsFree } - return mode } @@ -167,11 +151,6 @@ enum HotkeyPreferences { NotificationCenter.default.post(name: .hotkeysDidChange, object: nil) } - static func setDictationShortcutMode(_ mode: DictationShortcutMode, userDefaults: UserDefaults = .standard) { - userDefaults.set(mode.rawValue, forKey: dictationShortcutModeKey) - NotificationCenter.default.post(name: .hotkeysDidChange, object: nil) - } - static func setDictationShortcutsEnabled(_ enabled: Bool, userDefaults: UserDefaults = .standard) { let ud = userDefaults ud.set(enabled, forKey: dictationShortcutsEnabledKey) diff --git a/Sources/Support/PhysicalDictationTriggerPreferences.swift b/Sources/Support/PhysicalDictationTriggerPreferences.swift index 13f0955ef..b43622702 100644 --- a/Sources/Support/PhysicalDictationTriggerPreferences.swift +++ b/Sources/Support/PhysicalDictationTriggerPreferences.swift @@ -65,15 +65,12 @@ enum PhysicalDictationTriggerPreferences { /// The one dictation key. Right Option, not Fn: Fn also opens emoji or /// switches input unless macOS is set to Do Nothing. static let defaultPushToTalkBinding = PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_RightOption)) - static let defaultHandsFreeBinding = PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_RightOption)) + /// Migration only: the old separate Hands-Free key. + private static let defaultHandsFreeBinding = PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_RightOption)) static let defaultMeetingBinding = PhysicalDictationTriggerBinding( keyCode: UInt32(kVK_ANSI_M), modifiers: PhysicalDictationTriggerModifiers.option ) - static let defaultPasteLastDictationBinding = PhysicalDictationTriggerBinding( - keyCode: UInt32(kVK_ANSI_V), - modifiers: PhysicalDictationTriggerModifiers.option | PhysicalDictationTriggerModifiers.shift - ) static let defaultBinding = defaultPushToTalkBinding private static let keyCodeKey = "dictationTrigger-keyCode" @@ -84,8 +81,6 @@ enum PhysicalDictationTriggerPreferences { private static let handsFreeModifiersKey = "dictationHandsFreeTrigger-modifiers" private static let meetingKeyCodeKey = "meetingTrigger-keyCode" private static let meetingModifiersKey = "meetingTrigger-modifiers" - private static let pasteLastDictationKeyCodeKey = "pasteLastDictationTrigger-keyCode" - private static let pasteLastDictationModifiersKey = "pasteLastDictationTrigger-modifiers" private static let oneDictationKeyMigratedKey = "dictationOneKeyMigrated" private static let functionKeyUsageDomain = "com.apple.HIToolbox" as CFString private static let functionKeyUsageKey = "AppleFnUsageType" as CFString @@ -105,7 +100,7 @@ enum PhysicalDictationTriggerPreferences { ) } - static func handsFreeBinding(userDefaults: UserDefaults = .standard) -> PhysicalDictationTriggerBinding { + private static func handsFreeBinding(userDefaults: UserDefaults = .standard) -> PhysicalDictationTriggerBinding { safeBinding( storedBinding( keyCodeKey: handsFreeKeyCodeKey, @@ -127,17 +122,6 @@ enum PhysicalDictationTriggerPreferences { ) } - static func pasteLastDictationBinding(userDefaults: UserDefaults = .standard) -> PhysicalDictationTriggerBinding { - safeBinding( - storedBinding( - keyCodeKey: pasteLastDictationKeyCodeKey, - modifiersKey: pasteLastDictationModifiersKey, - userDefaults: userDefaults - ) ?? defaultPasteLastDictationBinding, - fallback: defaultPasteLastDictationBinding - ) - } - static func save(_ binding: PhysicalDictationTriggerBinding, userDefaults: UserDefaults = .standard) { savePushToTalk(binding, userDefaults: userDefaults) } @@ -151,15 +135,6 @@ enum PhysicalDictationTriggerPreferences { ) } - static func saveHandsFree(_ binding: PhysicalDictationTriggerBinding, userDefaults: UserDefaults = .standard) { - saveBinding( - binding, - keyCodeKey: handsFreeKeyCodeKey, - modifiersKey: handsFreeModifiersKey, - userDefaults: userDefaults - ) - } - static func saveMeeting(_ binding: PhysicalDictationTriggerBinding, userDefaults: UserDefaults = .standard) { saveBinding( binding, @@ -169,15 +144,6 @@ enum PhysicalDictationTriggerPreferences { ) } - static func savePasteLastDictation(_ binding: PhysicalDictationTriggerBinding, userDefaults: UserDefaults = .standard) { - saveBinding( - binding, - keyCodeKey: pasteLastDictationKeyCodeKey, - modifiersKey: pasteLastDictationModifiersKey, - userDefaults: userDefaults - ) - } - private static func saveBinding( _ binding: PhysicalDictationTriggerBinding, keyCodeKey: String, @@ -210,9 +176,7 @@ enum PhysicalDictationTriggerPreferences { static func resetToDefaults(userDefaults: UserDefaults = .standard) { savePushToTalk(defaultPushToTalkBinding, userDefaults: userDefaults) - saveHandsFree(defaultHandsFreeBinding, userDefaults: userDefaults) saveMeeting(defaultMeetingBinding, userDefaults: userDefaults) - savePasteLastDictation(defaultPasteLastDictationBinding, userDefaults: userDefaults) } static func functionKeySystemAction() -> FunctionKeySystemAction { @@ -592,7 +556,7 @@ enum PhysicalDictationTriggerPreferences { } private static func migratedPushToTalkBinding(userDefaults: UserDefaults) -> PhysicalDictationTriggerBinding { - guard HotkeyPreferences.dictationShortcutMode(userDefaults: userDefaults) == .pushToTalk else { + guard HotkeyPreferences.legacyDictationShortcutMode(userDefaults: userDefaults) == .pushToTalk else { return defaultPushToTalkBinding } @@ -606,7 +570,7 @@ enum PhysicalDictationTriggerPreferences { } private static func migratedHandsFreeBinding(userDefaults: UserDefaults) -> PhysicalDictationTriggerBinding { - guard HotkeyPreferences.dictationShortcutMode(userDefaults: userDefaults) == .handsFree else { + guard HotkeyPreferences.legacyDictationShortcutMode(userDefaults: userDefaults) == .handsFree else { return defaultHandsFreeBinding } diff --git a/Sources/UI/MenuBar/MenuBarShortcutLabel.swift b/Sources/UI/MenuBar/MenuBarShortcutLabel.swift index 4c5e6fae6..4ec41af4a 100644 --- a/Sources/UI/MenuBar/MenuBarShortcutLabel.swift +++ b/Sources/UI/MenuBar/MenuBarShortcutLabel.swift @@ -3,9 +3,9 @@ import Foundation -/// A button shows its shortcut beside the title when there's room. Dictation -/// can have two triggers ("Fn / Right ⌥": push-to-talk, then hands-free), and -/// the pair doesn't fit a half-width button, so the button tries the full +/// A button shows its shortcut beside the title when there's room. A shortcut +/// can be a pair ("A / B"), and the pair +/// doesn't fit a half-width button, so the button tries the full /// text first and then just the first key. enum MenuBarShortcutLabel { static func candidates(for shortcut: String) -> [String] { diff --git a/Sources/UI/Overlay/DictationSessionController.swift b/Sources/UI/Overlay/DictationSessionController.swift index db9b4de4f..80a1a6856 100644 --- a/Sources/UI/Overlay/DictationSessionController.swift +++ b/Sources/UI/Overlay/DictationSessionController.swift @@ -136,7 +136,7 @@ class DictationSessionController: ObservableObject { /// press or after recording starts (see `DictationStartCuePolicy`). var didPlayStartCue = false /// The shortcut that started this session, when a shortcut did. Read from - /// the press itself, never from `HotkeyPreferences.dictationShortcutMode()`. + /// the press itself, never from a stored setting. var currentDictationShortcutMode: DictationShortcutMode? var stoppedAudioRecovery: DictationStoppedAudioRecovery? var stoppedAudioRecoveryPreservationSessionID: UUID? diff --git a/Tests/ContextCaptureEnginePolicyTests.swift b/Tests/ContextCaptureEnginePolicyTests.swift index c6eee3b8d..2490c8d95 100644 --- a/Tests/ContextCaptureEnginePolicyTests.swift +++ b/Tests/ContextCaptureEnginePolicyTests.swift @@ -59,7 +59,6 @@ func testContextCaptureEnginePolicy() { var debouncer = HotkeyActionDebouncer(interval: 0.2) assertTrue(debouncer.shouldAccept(.dictationHandsFree, now: 50), "hands-free press goes through") assertTrue(debouncer.shouldAccept(.meeting, now: 50.05), "a meeting press right after a dictation press still goes through") - assertTrue(debouncer.shouldAccept(.pasteLastDictation, now: 50.1), "paste-last-dictation has its own window too") assertFalse(debouncer.shouldAccept(.meeting, now: 50.1), "a repeat meeting press is still dropped") } @@ -85,11 +84,6 @@ func testContextCaptureEnginePolicy() { runSuite("Hotkey repeat guard — telemetry ids stay stable") { assertEqual(PhysicalShortcutAction.dictationHandsFree.hotkeyDebounceID, "dictation_hands_free", "hands-free bucket id") assertEqual(PhysicalShortcutAction.meeting.hotkeyDebounceID, "meeting_physical_trigger", "meeting bucket id") - assertEqual( - PhysicalShortcutAction.pasteLastDictation.hotkeyDebounceID, - "paste_last_dictation_physical_trigger", - "paste-last-dictation bucket id" - ) } runSuite("Tap re-enable — a push-to-talk key let go while the tap was off gets its release") { @@ -345,34 +339,23 @@ func testContextCaptureEnginePolicy() { // when dictation shortcuts are enabled, prepends push-to-talk and // hands-free. Pin the defaults a fresh install hands the snapshot. - runSuite("PhysicalDictationTriggerPreferences fresh install — engine binding snapshot sees Right Option / Option-M / Option-Shift-V") { + runSuite("PhysicalDictationTriggerPreferences fresh install — engine binding snapshot sees Right Option / Option-M") { let (defaults, suiteName) = makeContextCaptureDefaults() defer { defaults.removePersistentDomain(forName: suiteName) } let pushToTalk = PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: defaults) - let handsFree = PhysicalDictationTriggerPreferences.handsFreeBinding(userDefaults: defaults) let meeting = PhysicalDictationTriggerPreferences.meetingBinding(userDefaults: defaults) - let pasteLastDictation = PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults) assertEqual(pushToTalk.keyCode, UInt32(kVK_RightOption), "the dictation key default should be Right Option") assertEqual(pushToTalk.modifiers, 0, "push-to-talk default should have no modifiers") - assertEqual(handsFree.keyCode, UInt32(kVK_RightOption), "hands-free default keyCode should be Right Option") - assertEqual(handsFree.modifiers, 0, "hands-free default should have no modifiers") assertEqual(meeting.keyCode, UInt32(kVK_ANSI_M), "meeting default keyCode should be M") assertEqual(meeting.modifiers, PhysicalDictationTriggerModifiers.option, "meeting default modifier should be Option") - assertEqual(pasteLastDictation.keyCode, UInt32(kVK_ANSI_V), "paste-last-dictation default keyCode should be V") - assertEqual( - pasteLastDictation.modifiers, - PhysicalDictationTriggerModifiers.option | PhysicalDictationTriggerModifiers.shift, - "paste-last-dictation default modifiers should be Option Shift" - ) } - runSuite("PhysicalDictationTriggerPreferences fresh install — meeting and paste bindings are independent of dictation shortcuts toggle") { - // The engine's binding snapshot always includes the meeting and paste bindings, + runSuite("PhysicalDictationTriggerPreferences fresh install — meeting binding is independent of dictation shortcuts toggle") { + // The engine's binding snapshot always includes the meeting binding, // even when dictation shortcuts are off. The meeting default must - // therefore survive in the absence of any saved dictation preference, - // and paste-last-dictation stays available as a recovery action. + // therefore survive in the absence of any saved dictation preference. let (defaults, suiteName) = makeContextCaptureDefaults() defer { defaults.removePersistentDomain(forName: suiteName) } @@ -389,11 +372,6 @@ func testContextCaptureEnginePolicy() { PhysicalDictationTriggerPreferences.defaultMeetingBinding, "meeting binding should stay available even when dictation shortcuts are disabled" ) - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "paste-last-dictation binding should stay available even when dictation shortcuts are disabled" - ) } // MARK: - dictationShortcutsEnabled default @@ -525,25 +503,12 @@ func testContextCaptureEnginePolicy() { ) } - runSuite("PhysicalDictationTriggerPreferences.displayString — paste-last-dictation default formats as Option-Shift-V chord") { - assertEqual( - PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding), - "⌥⇧V", - "paste-last-dictation default should render as ⌥⇧V in shortcut editors" - ) - } - runSuite("PhysicalDictationTriggerPreferences.displayString — dictation defaults render as Right Option") { assertEqual( PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultPushToTalkBinding), "Right ⌥", "the dictation key default should render as Right Option for dictationShortcutDisplay" ) - assertEqual( - PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultHandsFreeBinding), - "Right ⌥", - "hands-free default should render as Right ⌥ for dictationShortcutDisplay" - ) } // MARK: - PhysicalShortcutDetector matcher dispatch @@ -565,28 +530,6 @@ func testContextCaptureEnginePolicy() { ) } - runSuite("PhysicalDictationTriggerPreferences.matchesKeyDown — paste-last-dictation Option-Shift-V binding accepts ⌥⇧V keyDown") { - let pasteLastDictation = PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding - - assertTrue( - PhysicalDictationTriggerPreferences.matchesKeyDown( - pasteLastDictation, - keyCode: UInt32(kVK_ANSI_V), - modifiers: PhysicalDictationTriggerModifiers.option | PhysicalDictationTriggerModifiers.shift - ), - "engine's keyDown matcher should accept the configured paste-last-dictation chord" - ) - } - - runSuite("PhysicalDictationTriggerPreferences.matchesKeyDown — paste-last-dictation binding rejects bare V") { - let pasteLastDictation = PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding - - assertFalse( - PhysicalDictationTriggerPreferences.matchesKeyDown(pasteLastDictation, keyCode: UInt32(kVK_ANSI_V), modifiers: 0), - "bare V should not fire paste-last-dictation while a user is typing" - ) - } - runSuite("PhysicalDictationTriggerPreferences.matchesKeyDown — meeting binding rejects bare M without Option") { let meeting = PhysicalDictationTriggerPreferences.defaultMeetingBinding @@ -881,7 +824,7 @@ func testContextCaptureEnginePolicy() { ) ), PhysicalShortcutBinding( - action: .pasteLastDictation, + action: .dictationHandsFree, binding: PhysicalDictationTriggerBinding( keyCode: UInt32(kVK_ANSI_V), modifiers: PhysicalDictationTriggerModifiers.option | PhysicalDictationTriggerModifiers.shift @@ -897,8 +840,8 @@ func testContextCaptureEnginePolicy() { assertEqual( match?.action, - .pasteLastDictation, - "keyDown matcher should resolve the Option-Shift-V chord to paste-last-dictation" + .dictationHandsFree, + "keyDown matcher should resolve the Option-Shift-V chord to its binding" ) assertNil( PhysicalShortcutMatcher.matchingKeyDownShortcut( diff --git a/Tests/HotkeyPreferencesTests.swift b/Tests/HotkeyPreferencesTests.swift index 4246a2aee..2b2b16da2 100644 --- a/Tests/HotkeyPreferencesTests.swift +++ b/Tests/HotkeyPreferencesTests.swift @@ -1,29 +1,21 @@ import Foundation func testHotkeyPreferences() { - runSuite("HotkeyPreferences dictation mode defaults to hands-free") { + runSuite("HotkeyPreferences legacy dictation mode defaults to hands-free") { let suiteName = "HotkeyPreferencesTests.default.\(UUID().uuidString)" let defaults = UserDefaults(suiteName: suiteName)! defer { defaults.removePersistentDomain(forName: suiteName) } assertEqual( - HotkeyPreferences.dictationShortcutMode(userDefaults: defaults), + HotkeyPreferences.legacyDictationShortcutMode(userDefaults: defaults), .handsFree, - "dictation should keep the existing tap-to-toggle behavior by default" + "a missing legacy mode was hands-free, so migration must keep treating it that way" ) - } - - runSuite("HotkeyPreferences stores push-to-talk dictation mode") { - let suiteName = "HotkeyPreferencesTests.pushToTalk.\(UUID().uuidString)" - let defaults = UserDefaults(suiteName: suiteName)! - defer { defaults.removePersistentDomain(forName: suiteName) } - - HotkeyPreferences.setDictationShortcutMode(.pushToTalk, userDefaults: defaults) - + defaults.set("push_to_talk", forKey: "hotkey-dictation-shortcut-mode") assertEqual( - HotkeyPreferences.dictationShortcutMode(userDefaults: defaults), + HotkeyPreferences.legacyDictationShortcutMode(userDefaults: defaults), .pushToTalk, - "users should be able to opt into hold-to-record behavior" + "an explicit legacy push-to-talk mode must still be read" ) } @@ -95,26 +87,20 @@ func testHotkeyPreferences() { defaults.set("not-a-real-mode", forKey: "hotkey-dictation-shortcut-mode") assertEqual( - HotkeyPreferences.dictationShortcutMode(userDefaults: defaults), + HotkeyPreferences.legacyDictationShortcutMode(userDefaults: defaults), .handsFree, "unknown saved modes should fall back to hands-free" ) } - runSuite("HotkeyPreferences reset restores hands-free dictation mode") { + runSuite("HotkeyPreferences reset restores dictation defaults") { let suiteName = "HotkeyPreferencesTests.reset.\(UUID().uuidString)" let defaults = UserDefaults(suiteName: suiteName)! defer { defaults.removePersistentDomain(forName: suiteName) } - HotkeyPreferences.setDictationShortcutMode(.pushToTalk, userDefaults: defaults) HotkeyPreferences.setDictationShortcutsEnabled(false, userDefaults: defaults) HotkeyPreferences.resetToDefaults(userDefaults: defaults) - assertEqual( - HotkeyPreferences.dictationShortcutMode(userDefaults: defaults), - .handsFree, - "reset should restore the default dictation mode" - ) assertEqual( HotkeyPreferences.dictationShortcutsEnabled(userDefaults: defaults), true, diff --git a/Tests/PhysicalDictationTriggerPreferencesTests.swift b/Tests/PhysicalDictationTriggerPreferencesTests.swift index bb6bb856c..b7269cb2f 100644 --- a/Tests/PhysicalDictationTriggerPreferencesTests.swift +++ b/Tests/PhysicalDictationTriggerPreferencesTests.swift @@ -4,7 +4,7 @@ import CoreGraphics import Foundation func testPhysicalDictationTriggerPreferences() { - runSuite("PhysicalDictationTriggerPreferences defaults to Right Option, Option-Shift-V, and Option M") { + runSuite("PhysicalDictationTriggerPreferences defaults to Right Option and Option M") { let (defaults, suiteName) = makePhysicalTriggerDefaults() defer { defaults.removePersistentDomain(forName: suiteName) } @@ -13,41 +13,21 @@ func testPhysicalDictationTriggerPreferences() { PhysicalDictationTriggerPreferences.defaultPushToTalkBinding, "fresh installs should use Right Option for the dictation key" ) - assertEqual( - PhysicalDictationTriggerPreferences.handsFreeBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultHandsFreeBinding, - "fresh installs should use Right Option for hands-free" - ) assertEqual( PhysicalDictationTriggerPreferences.meetingBinding(userDefaults: defaults), PhysicalDictationTriggerPreferences.defaultMeetingBinding, "fresh installs should use Option M for meetings" ) - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "fresh installs should use Option Shift V for paste-last-dictation" - ) assertEqual( PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultPushToTalkBinding), "Right ⌥", "the dictation key default should display as Right Option, not Fn (which opens emoji)" ) - assertEqual( - PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultHandsFreeBinding), - "Right ⌥", - "hands-free default should display as Right Option" - ) assertEqual( PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultMeetingBinding), "⌥M", "meeting default should display as Option M" ) - assertEqual( - PhysicalDictationTriggerPreferences.displayString(for: PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding), - "⌥⇧V", - "paste-last-dictation default should display as Option Shift V" - ) } runSuite("PhysicalDictationTriggerPreferences persists explicit physical keys") { @@ -61,105 +41,16 @@ func testPhysicalDictationTriggerPreferences() { assertEqual(PhysicalDictationTriggerPreferences.displayString(for: fn), "Fn", "Fn should have a readable display name") } - runSuite("PhysicalDictationTriggerPreferences persists paste-last-dictation shortcut") { - let (defaults, suiteName) = makePhysicalTriggerDefaults() - defer { defaults.removePersistentDomain(forName: suiteName) } - - let commandShiftP = PhysicalDictationTriggerBinding( - keyCode: UInt32(kVK_ANSI_P), - modifiers: PhysicalDictationTriggerModifiers.command | PhysicalDictationTriggerModifiers.shift - ) - - PhysicalDictationTriggerPreferences.savePasteLastDictation(commandShiftP, userDefaults: defaults) - - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - commandShiftP, - "paste-last-dictation should persist its own independent shortcut" - ) - assertEqual( - PhysicalDictationTriggerPreferences.displayString(for: commandShiftP), - "⇧⌘P", - "custom paste-last-dictation shortcuts should share the normal display formatter" - ) - } - - runSuite("PhysicalDictationTriggerPreferences records paste-last editor chord from keyDown") { + runSuite("PhysicalDictationTriggerPreferences records an editor chord from keyDown") { let recorded = PhysicalDictationTriggerPreferences.bindingForKeyDown( - keyCode: UInt32(kVK_ANSI_V), - modifierFlags: [.option, .shift] + keyCode: UInt32(kVK_ANSI_M), + modifierFlags: [.option] ) assertEqual( recorded, - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "shortcut editor input for Option-Shift-V should round-trip into the paste-last default" - ) - } - - runSuite("PhysicalDictationTriggerPreferences saving paste-last posts hotkeysDidChange") { - let (defaults, suiteName) = makePhysicalTriggerDefaults() - defer { defaults.removePersistentDomain(forName: suiteName) } - - var notificationCount = 0 - let observer = NotificationCenter.default.addObserver( - forName: .hotkeysDidChange, - object: nil, - queue: nil - ) { _ in - notificationCount += 1 - } - defer { NotificationCenter.default.removeObserver(observer) } - - PhysicalDictationTriggerPreferences.savePasteLastDictation( - PhysicalDictationTriggerBinding( - keyCode: UInt32(kVK_ANSI_P), - modifiers: PhysicalDictationTriggerModifiers.command | PhysicalDictationTriggerModifiers.shift - ), - userDefaults: defaults - ) - - assertEqual( - notificationCount, - 1, - "changing paste-last should ask ContextCaptureEngine to re-register physical shortcuts" - ) - } - - runSuite("PhysicalDictationTriggerPreferences masks invalid stored paste-last modifiers") { - let (defaults, suiteName) = makePhysicalTriggerDefaults() - defer { defaults.removePersistentDomain(forName: suiteName) } - - defaults.set(Int(kVK_ANSI_V), forKey: "pasteLastDictationTrigger-keyCode") - defaults.set( - Int(PhysicalDictationTriggerModifiers.option | PhysicalDictationTriggerModifiers.shift | (1 << 20)), - forKey: "pasteLastDictationTrigger-modifiers" - ) - - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "corrupt persisted modifier bits should be ignored instead of changing the shortcut contract" - ) - } - - runSuite("PhysicalDictationTriggerPreferences paste-last ignores legacy dictation and meeting shortcuts") { - let (defaults, suiteName) = makePhysicalTriggerDefaults() - defer { defaults.removePersistentDomain(forName: suiteName) } - - HotkeyPreferences.save( - dictation: HotkeyBinding(keyCode: UInt32(kVK_Space), modifiers: UInt32(cmdKey)), - userDefaults: defaults - ) - HotkeyPreferences.save( - meeting: HotkeyBinding(keyCode: UInt32(kVK_ANSI_M), modifiers: UInt32(controlKey)), - userDefaults: defaults - ) - - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "paste-last should default independently when only older dictation or meeting shortcuts exist" + PhysicalDictationTriggerPreferences.defaultMeetingBinding, + "shortcut editor input for Option-M should round-trip into the meeting default" ) } @@ -234,7 +125,7 @@ func testPhysicalDictationTriggerPreferences() { ) } - runSuite("PhysicalDictationTriggerPreferences migrates legacy hands-free shortcut when right Option is disabled") { + runSuite("PhysicalDictationTriggerPreferences migrates the legacy single dictation shortcut when right Option is disabled") { let (defaults, suiteName) = makePhysicalTriggerDefaults() defer { defaults.removePersistentDomain(forName: suiteName) } @@ -244,7 +135,8 @@ func testPhysicalDictationTriggerPreferences() { userDefaults: defaults ) - let migrated = PhysicalDictationTriggerPreferences.handsFreeBinding(userDefaults: defaults) + PhysicalDictationTriggerPreferences.migrateToOneDictationKeyIfNeeded(userDefaults: defaults) + let migrated = PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: defaults) assertEqual(migrated.keyCode, UInt32(kVK_Space), "disabled right Option should fall back to the old dictation shortcut key") assertEqual( @@ -261,25 +153,27 @@ func testPhysicalDictationTriggerPreferences() { let capsLock = PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_CapsLock)) defaults.set(Int(capsLock.keyCode), forKey: "dictationTrigger-keyCode") defaults.set(Int(capsLock.modifiers), forKey: "dictationTrigger-modifiers") - HotkeyPreferences.setDictationShortcutMode(.pushToTalk, userDefaults: defaults) + defaults.set("push_to_talk", forKey: "hotkey-dictation-shortcut-mode") assertEqual( PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: defaults), capsLock, "existing push-to-talk users should keep their saved physical key" ) + PhysicalDictationTriggerPreferences.migrateToOneDictationKeyIfNeeded(userDefaults: defaults) assertEqual( - PhysicalDictationTriggerPreferences.handsFreeBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultHandsFreeBinding, - "hands-free should move to the new default when the saved key belonged to push-to-talk" + PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: defaults), + capsLock, + "the old hands-free slot held the default, so migration must not replace the saved key" ) + assertEqual(HotkeyPreferences.dictationKeyBehavior(userDefaults: defaults), .holdOrTap, "and the behavior stays Hold or tap") } runSuite("One dictation key: a custom hands-free key carries over as Tap to toggle") { let (defaults, suiteName) = makePhysicalTriggerDefaults() defer { defaults.removePersistentDomain(forName: suiteName) } let f5 = PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_F5)) - PhysicalDictationTriggerPreferences.saveHandsFree(f5, userDefaults: defaults) + seedLegacyHandsFree(f5, in: defaults) PhysicalDictationTriggerPreferences.migrateToOneDictationKeyIfNeeded(userDefaults: defaults) assertEqual(PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: defaults), f5, "their key becomes the dictation key") @@ -309,7 +203,7 @@ func testPhysicalDictationTriggerPreferences() { defer { custom.removePersistentDomain(forName: customSuite) } let capsLock = PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_CapsLock)) PhysicalDictationTriggerPreferences.savePushToTalk(capsLock, userDefaults: custom) - PhysicalDictationTriggerPreferences.saveHandsFree(PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_F5)), userDefaults: custom) + seedLegacyHandsFree(PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_F5)), in: custom) PhysicalDictationTriggerPreferences.migrateToOneDictationKeyIfNeeded(userDefaults: custom) assertEqual(PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: custom), capsLock, "a chosen hold key wins") } @@ -450,7 +344,7 @@ func testPhysicalDictationTriggerPreferences() { ) } - runSuite("PhysicalDictationTriggerPreferences reset writes all four modern bindings") { + runSuite("PhysicalDictationTriggerPreferences reset writes the modern bindings") { let (defaults, suiteName) = makePhysicalTriggerDefaults() defer { defaults.removePersistentDomain(forName: suiteName) } @@ -458,18 +352,10 @@ func testPhysicalDictationTriggerPreferences() { PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_A)), userDefaults: defaults ) - PhysicalDictationTriggerPreferences.saveHandsFree( - PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_B)), - userDefaults: defaults - ) PhysicalDictationTriggerPreferences.saveMeeting( PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_C)), userDefaults: defaults ) - PhysicalDictationTriggerPreferences.savePasteLastDictation( - PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_D)), - userDefaults: defaults - ) PhysicalDictationTriggerPreferences.resetToDefaults(userDefaults: defaults) @@ -478,21 +364,11 @@ func testPhysicalDictationTriggerPreferences() { PhysicalDictationTriggerPreferences.defaultPushToTalkBinding, "reset should restore push-to-talk" ) - assertEqual( - PhysicalDictationTriggerPreferences.handsFreeBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultHandsFreeBinding, - "reset should restore hands-free" - ) assertEqual( PhysicalDictationTriggerPreferences.meetingBinding(userDefaults: defaults), PhysicalDictationTriggerPreferences.defaultMeetingBinding, "reset should restore meeting shortcut" ) - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "reset should restore paste-last-dictation shortcut" - ) } runSuite("PhysicalDictationTriggerPreferences rejects chords the event tap must never swallow") { @@ -530,11 +406,9 @@ func testPhysicalDictationTriggerPreferences() { } let allowed: [(String, PhysicalDictationTriggerBinding)] = [ - ("default paste-last ⌥⇧V", PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding), ("default meeting ⌥M", PhysicalDictationTriggerPreferences.defaultMeetingBinding), ("default dictation key Right ⌥", PhysicalDictationTriggerPreferences.defaultPushToTalkBinding), ("Fn", PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_Function))), - ("default hands-free Right ⌥", PhysicalDictationTriggerPreferences.defaultHandsFreeBinding), ("bare F5", PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_F5))), ("⌥⌘V", PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_V), modifiers: command | option)), ("⌃V", PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_V), modifiers: control)), @@ -558,36 +432,27 @@ func testPhysicalDictationTriggerPreferences() { // Older builds let the recorder save these. Reading them back must not // hand the event tap a chord it would swallow system-wide, and Settings // must show the same binding the tap installs. - PhysicalDictationTriggerPreferences.savePasteLastDictation( - PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_V), modifiers: PhysicalDictationTriggerModifiers.command), - userDefaults: defaults - ) PhysicalDictationTriggerPreferences.saveMeeting( PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_ANSI_M)), userDefaults: defaults ) - PhysicalDictationTriggerPreferences.saveHandsFree( + PhysicalDictationTriggerPreferences.savePushToTalk( PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_LeftArrow), modifiers: PhysicalDictationTriggerModifiers.function), userDefaults: defaults ) - assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultPasteLastDictationBinding, - "a stored ⌘V paste-last chord must read back as the default instead of hijacking every paste" - ) assertEqual( PhysicalDictationTriggerPreferences.meetingBinding(userDefaults: defaults), PhysicalDictationTriggerPreferences.defaultMeetingBinding, "a stored bare-letter meeting chord must read back as the default" ) assertEqual( - PhysicalDictationTriggerPreferences.handsFreeBinding(userDefaults: defaults), - PhysicalDictationTriggerPreferences.defaultHandsFreeBinding, - "a stored bare arrow hands-free chord must read back as the default" + PhysicalDictationTriggerPreferences.pushToTalkBinding(userDefaults: defaults), + PhysicalDictationTriggerPreferences.defaultPushToTalkBinding, + "a stored bare arrow dictation chord must read back as the default" ) - PhysicalDictationTriggerPreferences.savePasteLastDictation( + PhysicalDictationTriggerPreferences.saveMeeting( PhysicalDictationTriggerBinding( keyCode: UInt32(kVK_ANSI_V), modifiers: PhysicalDictationTriggerModifiers.command | PhysicalDictationTriggerModifiers.option @@ -595,7 +460,7 @@ func testPhysicalDictationTriggerPreferences() { userDefaults: defaults ) assertEqual( - PhysicalDictationTriggerPreferences.pasteLastDictationBinding(userDefaults: defaults).modifiers, + PhysicalDictationTriggerPreferences.meetingBinding(userDefaults: defaults).modifiers, PhysicalDictationTriggerModifiers.command | PhysicalDictationTriggerModifiers.option, "a safe stored chord must read back unchanged" ) @@ -632,7 +497,7 @@ func testPhysicalDictationTriggerPreferences() { ) assertNil( PhysicalDictationTriggerPreferences.duplicateReason( - for: PhysicalDictationTriggerPreferences.defaultHandsFreeBinding, + for: PhysicalDictationTriggerPreferences.defaultPushToTalkBinding, otherShortcuts: others ), "Right Option is free when no other shortcut uses it" @@ -640,7 +505,7 @@ func testPhysicalDictationTriggerPreferences() { assertNil( PhysicalDictationTriggerPreferences.duplicateReason( for: PhysicalDictationTriggerBinding(keyCode: UInt32(kVK_Option)), - otherShortcuts: [(name: "Hands-Free", binding: PhysicalDictationTriggerPreferences.defaultHandsFreeBinding)] + otherShortcuts: [(name: "Dictation", binding: PhysicalDictationTriggerPreferences.defaultPushToTalkBinding)] ), "Left and Right Option are different keys" ) @@ -654,3 +519,9 @@ private func makePhysicalTriggerDefaults() -> (UserDefaults, String) { defaults.removePersistentDomain(forName: suiteName) return (defaults, suiteName) } + +/// Pre-one-key builds stored a separate Hands-Free key under these raw keys. +private func seedLegacyHandsFree(_ binding: PhysicalDictationTriggerBinding, in defaults: UserDefaults) { + defaults.set(Int(binding.keyCode), forKey: "dictationHandsFreeTrigger-keyCode") + defaults.set(Int(binding.modifiers), forKey: "dictationHandsFreeTrigger-modifiers") +} diff --git a/Tests/PhysicalShortcutMatcherTests.swift b/Tests/PhysicalShortcutMatcherTests.swift index 2689d973f..14d9784dc 100644 --- a/Tests/PhysicalShortcutMatcherTests.swift +++ b/Tests/PhysicalShortcutMatcherTests.swift @@ -29,7 +29,6 @@ func testPhysicalShortcutMatcher() { binding(.dictationPushToTalk, keyCode: kVK_Function), binding(.dictationHandsFree, keyCode: kVK_RightOption), binding(.meeting, keyCode: kVK_ANSI_M, modifiers: option), - binding(.pasteLastDictation, keyCode: kVK_ANSI_V, modifiers: option | shift), ] let meeting = PhysicalShortcutMatcher.matchingKeyDownShortcut( @@ -37,11 +36,6 @@ func testPhysicalShortcutMatcher() { ) assertTrue(meeting?.action == .meeting, "M+⌥ should resolve to the meeting binding") - let paste = PhysicalShortcutMatcher.matchingKeyDownShortcut( - shortcuts, keyCode: UInt32(kVK_ANSI_V), modifiers: option | shift - ) - assertTrue(paste?.action == .pasteLastDictation, "V+⌥⇧ should resolve to paste-last-dictation") - // Extra modifiers break the exact match — a key-down chord is precise. let withExtra = PhysicalShortcutMatcher.matchingKeyDownShortcut( shortcuts,