From af9ca1f9915a959d5b72d93a8bc81ddaedf5489d Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 28 Jan 2026 13:13:02 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20Keybind=20fixes=20(#1033)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Loop/Core/LoopManager.swift | 2 +- Loop/Core/Observers/KeybindTrigger.swift | 30 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Loop/Core/LoopManager.swift b/Loop/Core/LoopManager.swift index ca6ed1ac..33b1712a 100644 --- a/Loop/Core/LoopManager.swift +++ b/Loop/Core/LoopManager.swift @@ -45,7 +45,7 @@ final class LoopManager { windowActionCache: windowActionCache, changeAction: { [weak self] newAction in /// If the mouse moved, that means that the keybind trigger should no longer passthrough special events such as the emoji key. - self?.keybindTrigger.canPassthroughSpecialEvents = false + self?.keybindTrigger.canPassthroughNextSpecialEvent = false self?.changeAction(newAction, canAdvanceCycle: false) }, selectNextCycleItem: { [weak self] in diff --git a/Loop/Core/Observers/KeybindTrigger.swift b/Loop/Core/Observers/KeybindTrigger.swift index 87f4c28e..b19dc8fd 100644 --- a/Loop/Core/Observers/KeybindTrigger.swift +++ b/Loop/Core/Observers/KeybindTrigger.swift @@ -27,8 +27,10 @@ final class KeybindTrigger { private let keybindCacheLifetime: ContinuousClock.Duration = .seconds(30) // Special events only contain the globe key, as it can also be used as an emoji key. - private let specialEvents: [CGKeyCode] = [.kVK_Globe_Emoji] - var canPassthroughSpecialEvents = true // If mouse has been moved + private let specialEventKeys: [CGKeyCode] = [.kVK_Globe_Emoji] + + // Will be set to `false` if the mouse has been moved by LoopManager. + var canPassthroughNextSpecialEvent = true private var useTriggerDelay: Bool { Defaults[.triggerDelay] > 0.1 } private var doubleClickToTrigger: Bool { Defaults[.doubleClickToTrigger] } @@ -97,13 +99,14 @@ final class KeybindTrigger { } // Special events such as the emoji key - if specialEvents.contains(keyCode) { - return canPassthroughSpecialEvents ? .forward : .ignore + if specialEventKeys.contains(keyCode) { + let canPassthrough = canPassthroughNextSpecialEvent + canPassthroughNextSpecialEvent = true // reset + return canPassthrough ? .forward : .ignore } // If this is a valid event, don't passthrough let result = performKeybind( - keyCode: keyCode, type: event.type, isARepeat: event.getIntegerValueField(.keyboardEventAutorepeat) == 1, flags: filteredFlags, @@ -129,11 +132,12 @@ final class KeybindTrigger { } func stop() { - pressedKeys = [] - canPassthroughSpecialEvents = true - eventMonitor?.stop() eventMonitor = nil + + // Reset states + pressedKeys = [] + canPassthroughNextSpecialEvent = true } enum PerformKeybindResult { @@ -149,12 +153,12 @@ final class KeybindTrigger { /// - flags: modifier flags associated with this event. /// - isLoopOpen: whether Loop is currently open. /// - Returns: whether this event was processed by Loop. - private func performKeybind(keyCode: CGKeyCode, type: CGEventType, isARepeat: Bool, flags: CGEventFlags, isLoopOpen: Bool) -> PerformKeybindResult { + private func performKeybind(type: CGEventType, isARepeat: Bool, flags: CGEventFlags, isLoopOpen: Bool) -> PerformKeybindResult { let flagKeys = sideDependentTriggerKey ? flags.keyCodes : flags.keyCodes.baseModifiers let allPressedKeys: Set = pressedKeys.union(flagKeys) - let actionKeys: Set = Set(allPressedKeys.subtracting(triggerKey).map(\.baseModifier)) let containsTrigger = allPressedKeys.isSuperset(of: triggerKey) + let actionKeys: Set = Set(allPressedKeys.subtracting(triggerKey).map(\.baseModifier)) let allPressedKeysBaseModifiers: Set = Set(allPressedKeys.map(\.baseModifier)) if isLoopOpen { @@ -177,9 +181,7 @@ final class KeybindTrigger { if containsTrigger { // Try an match directly with the action keys first, then fallback to just the key code. // This prevents failures when the user is tapping the keys in rapid succession. - let match = windowActionCache.actionsByKeybind[actionKeys] ?? windowActionCache.actionsByKeybind[[keyCode]] - - if let action = match { + if let action = windowActionCache.actionsByKeybind[actionKeys] { if !isARepeat || action.canRepeat { openLoop(startingAction: action, overrideExistingTriggerDelayTimerAction: true) } @@ -233,8 +235,6 @@ final class KeybindTrigger { } private func closeLoop(forceClose: Bool) { - pressedKeys = [] - canPassthroughSpecialEvents = true triggerDelayTimer.cancel() closeCallback(forceClose) }