From 29d445460e72532346b4cfe16898d0b0bad74ba2 Mon Sep 17 00:00:00 2001 From: GuangDai <59678726+GuangDai@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:39:37 +0800 Subject: [PATCH] fix(popup): keep global hotkey registered Avoid disabling and re-enabling the popup shortcut for every open/close cycle. KeyboardShortcuts registers a new Carbon hotkey when re-enabled, causing the backing allocations to accumulate. Route repeated popup shortcut presses through the existing popup state machine while keeping the process-wide registration alive. --- Maccy/Observables/Popup.swift | 83 ++++++++++------------------------- 1 file changed, 23 insertions(+), 60 deletions(-) diff --git a/Maccy/Observables/Popup.swift b/Maccy/Observables/Popup.swift index 42ff3cf6f..0ff4ff7d7 100644 --- a/Maccy/Observables/Popup.swift +++ b/Maccy/Observables/Popup.swift @@ -61,8 +61,8 @@ class Popup { guard eventsMonitor == nil else { return } self.eventsMonitor = NSEvent.addLocalMonitorForEvents( - matching: [.flagsChanged, .keyDown], - handler: handleEvent + matching: .flagsChanged, + handler: handleFlagsChanged ) } @@ -78,7 +78,6 @@ class Popup { func reset() { state = .toggle - KeyboardShortcuts.enable(.popup) } func close() { @@ -114,52 +113,10 @@ class Popup { if isClosed() { open(height: height) state = .opening - KeyboardShortcuts.disable(.popup) // Handle events via eventsMonitor. Re-enable on popup close return } - // Maccy was not opened via shortcut. We assume toggle mode and close it - close() - } - - private func handleEvent(_ event: NSEvent) -> NSEvent? { - switch event.type { - case .keyDown: - return handleKeyDown(event) - case .flagsChanged: - return handleFlagsChanged(event) - default: - return event - } - } - - private func handleKeyDown(_ event: NSEvent) -> NSEvent? { - if isHotKeyCode(Int(event.keyCode)) { - if let item = History.shared.pressedShortcutItem { - AppState.shared.navigator.select(item: item) - Task { @MainActor in - AppState.shared.history.select(item) - } - return nil - } - - if state == .opening { - state = .cycle - // Next 'if' will highlight next item and then return nil - } - - if state == .cycle { - AppState.shared.navigator.highlightNext(allowCycle: true) - return nil - } - - if state == .toggle && isHotKeyModifiers(event.modifierFlags) { - close() - return nil - } - } - - return event + handleRepeatedHotKeyDown() } private func handleFlagsChanged(_ event: NSEvent) -> NSEvent? { @@ -180,24 +137,30 @@ class Popup { return event } - private func isHotKeyCode(_ keyCode: Int) -> Bool { - guard let shortcut = KeyboardShortcuts.Name.popup.shortcut else { - return false - } - - return shortcut.key?.rawValue == keyCode + private func allModifiersReleased(_ event: NSEvent) -> Bool { + return event.modifierFlags.isDisjoint(with: .deviceIndependentFlagsMask) } - private func isHotKeyModifiers(_ modifiers: NSEvent.ModifierFlags) -> Bool { - guard let shortcut = KeyboardShortcuts.Name.popup.shortcut else { - return false + private func handleRepeatedHotKeyDown() { + if let item = History.shared.pressedShortcutItem { + AppState.shared.navigator.select(item: item) + Task { @MainActor in + AppState.shared.history.select(item) + } + return } - return modifiers.intersection(.deviceIndependentFlagsMask) == - shortcut.modifiers.intersection(.deviceIndependentFlagsMask) - } + if state == .opening { + state = .cycle + } - private func allModifiersReleased(_ event: NSEvent) -> Bool { - return event.modifierFlags.isDisjoint(with: .deviceIndependentFlagsMask) + if state == .cycle { + AppState.shared.navigator.highlightNext(allowCycle: true) + return + } + + if state == .toggle { + close() + } } }