From d77d35981ccd3f64c34727b8d21ac599012007bb Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 02 Jul 2026 02:42:34 +0800
Subject: [PATCH] Update App Store release records
---
src/Apptag/ApptagApp.swift | 156 ++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 138 insertions(+), 18 deletions(-)
diff --git a/src/Apptag/ApptagApp.swift b/src/Apptag/ApptagApp.swift
index 53dfb40..2ef8916 100644
--- a/src/Apptag/ApptagApp.swift
+++ b/src/Apptag/ApptagApp.swift
@@ -28,7 +28,14 @@
// MARK: - App Delegate (menubar + overlay window + hotkey)
+private enum HotkeyRegistrationAttempt {
+ case success(EventHotKeyRef)
+ case failure(OSStatus)
+}
+
final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
+ static private(set) weak var shared: AppDelegate?
+
private static let showDockIconKey = "showDockIcon"
private static let statusItemAutosaveName = AppIdentity.statusItemAutosaveName
private static let statusItemButtonIdentifier = NSUserInterfaceItemIdentifier("TagLauncherStatusItemButton")
@@ -58,6 +65,7 @@
private var quickSearchHotkeyRef: EventHotKeyRef?
private var overlaySpaceHotkeyRef: EventHotKeyRef?
private var hotkeyEventHandlerInstalled = false
+ private var configuredHotkeysSuspendedForRecording = false
private var isQuickSearchOpen = false
private var quickSearchShouldHideOverlayOnClose = false
private var quickSearchOnlyOverlaySession = false
@@ -72,6 +80,11 @@
private var overlayOpenedByQuickSearchOnly = false
private var didFinishLaunching = false
private var pendingShowOverlayInvocation = false
+
+ override init() {
+ super.init()
+ Self.shared = self
+ }
private lazy var overlayController = OverlayWindowController(
dependencies: OverlayWindowController.Dependencies(
@@ -220,6 +233,7 @@
observeApplicationMenuChanges()
observeChromeSettings()
observeLanguageChanges()
+ observeProEntitlementChanges()
setupLaunchAtLogin()
suppressReopenUntil = Date().addingTimeInterval(1.0)
didFinishLaunching = true
@@ -889,7 +903,7 @@
if LauncherHotkeyRegistrationStore.state(for: .main) == .failed {
return tr("menu.showShortcutUnavailable")
}
- return "\(tr("menu.showAppList")) \(LauncherHotkey.main.displayString)"
+ return "\(tr("menu.showAppList")) \(LauncherHotkeySettings.effectiveHotkey(for: .main).displayString)"
}
private func observeApplicationMenuChanges() {
@@ -1267,14 +1281,106 @@
// MARK: - Global Hotkeys
private func registerConfiguredHotkeys() {
+ guard !configuredHotkeysSuspendedForRecording else { return }
installHotkeyEventHandlerIfNeeded()
- registerFixedHotkey(.main)
- registerFixedHotkey(.quickSearch)
+ registerEffectiveHotkey(.main)
+ registerEffectiveHotkey(.quickSearch)
}
- private func registerFixedHotkey(_ kind: LauncherHotkeyKind) {
+ func suspendConfiguredHotkeysForRecording() {
+ guard !configuredHotkeysSuspendedForRecording else { return }
+ configuredHotkeysSuspendedForRecording = true
+ unregisterHotkey(for: .main)
+ unregisterHotkey(for: .quickSearch)
+ }
+
+ func resumeConfiguredHotkeysAfterRecording() {
+ guard configuredHotkeysSuspendedForRecording else { return }
+ configuredHotkeysSuspendedForRecording = false
+ registerConfiguredHotkeys()
+ }
+
+ private func registerEffectiveHotkey(_ kind: LauncherHotkeyKind) {
unregisterHotkey(for: kind)
- let hotkey = kind.hotkey
+ let hotkey = LauncherHotkeySettings.effectiveHotkey(for: kind)
+ registerAndStoreHotkey(hotkey, for: kind, markFailure: true)
+ }
+
+ @discardableResult
+ func applyCustomHotkey(_ hotkey: LauncherHotkey, for kind: LauncherHotkeyKind) -> LauncherHotkeyCustomizationResult {
+ guard ProEntitlementPolicy.isUnlocked(.customHotkeys) else {
+ return .locked
+ }
+ if let error = LauncherHotkeySettings.validationError(for: hotkey, kind: kind) {
+ return .invalid(error)
+ }
+ return activateHotkey(hotkey, for: kind, persistCustom: true)
+ }
+
+ @discardableResult
+ func restoreDefaultHotkey(for kind: LauncherHotkeyKind) -> LauncherHotkeyCustomizationResult {
+ guard ProEntitlementPolicy.isUnlocked(.customHotkeys) else {
+ return .locked
+ }
+ return activateHotkey(LauncherHotkeySettings.defaultHotkey(for: kind), for: kind, persistCustom: false)
+ }
+
+ private func activateHotkey(
+ _ hotkey: LauncherHotkey,
+ for kind: LauncherHotkeyKind,
+ persistCustom: Bool
+ ) -> LauncherHotkeyCustomizationResult {
+ installHotkeyEventHandlerIfNeeded()
+
+ if LauncherHotkeySettings.effectiveHotkey(for: kind) == hotkey,
+ hotkeyRef(for: kind) != nil {
+ if persistCustom {
+ LauncherHotkeySettings.save(hotkey, for: kind)
+ LauncherHotkeyRegistrationStore.setActive(for: kind)
+ return .saved
+ }
+ LauncherHotkeySettings.clearCustomHotkey(for: kind)
+ LauncherHotkeyRegistrationStore.setActive(for: kind)
+ return .restored
+ }
+
+ switch tryRegisterHotkey(hotkey, for: kind, markFailure: false) {
+ case .success(let newRef):
+ if let oldRef = hotkeyRef(for: kind) {
+ UnregisterEventHotKey(oldRef)
+ }
+ setHotkeyRef(newRef, for: kind)
+ if persistCustom {
+ LauncherHotkeySettings.save(hotkey, for: kind)
+ LauncherHotkeyRegistrationStore.setActive(for: kind)
+ return .saved
+ }
+ LauncherHotkeySettings.clearCustomHotkey(for: kind)
+ LauncherHotkeyRegistrationStore.setActive(for: kind)
+ return .restored
+ case .failure(let status):
+ return .registrationFailed(status)
+ }
+ }
+
+ private func registerAndStoreHotkey(
+ _ hotkey: LauncherHotkey,
+ for kind: LauncherHotkeyKind,
+ markFailure: Bool
+ ) {
+ switch tryRegisterHotkey(hotkey, for: kind, markFailure: markFailure) {
+ case .success(let newRef):
+ setHotkeyRef(newRef, for: kind)
+ case .failure:
+ setHotkeyRef(nil, for: kind)
+ }
+ }
+
+ private func tryRegisterHotkey(
+ _ hotkey: LauncherHotkey,
+ for kind: LauncherHotkeyKind,
+ markFailure: Bool
+ ) -> HotkeyRegistrationAttempt {
var hotkeyID = EventHotKeyID()
hotkeyID.signature = OSType(0x41505447) // 'APTG'
@@ -1291,12 +1397,16 @@
)
if status == noErr, let newRef {
- setHotkeyRef(newRef, for: kind)
- LauncherHotkeyRegistrationStore.setActive(for: kind)
+ if markFailure {
+ LauncherHotkeyRegistrationStore.setActive(for: kind)
+ }
+ return .success(newRef)
} else {
- setHotkeyRef(nil, for: kind)
- LauncherHotkeyRegistrationStore.setFailed(status, for: kind)
+ if markFailure {
+ LauncherHotkeyRegistrationStore.setFailed(status, for: kind)
+ }
print("[TagLauncher] Fixed hotkey registration failed for \(kind.rawValue): \(status)")
+ return .failure(status)
}
}
@@ -1306,6 +1416,18 @@
object: nil,
queue: .main
) { [weak self] _ in
+ self?.setupMenuBar()
+ self?.configureApplicationMenuWhenAvailable(retries: 2)
+ }
+ }
+
+ private func observeProEntitlementChanges() {
+ NotificationCenter.default.addObserver(
+ forName: .tagLauncherProEntitlementChanged,
+ object: nil,
+ queue: .main
+ ) { [weak self] _ in
+ self?.registerConfiguredHotkeys()
self?.setupMenuBar()
self?.configureApplicationMenuWhenAvailable(retries: 2)
}
@@ -1818,12 +1940,7 @@
) { [weak self] event in
guard let self, self.isQuickSearchOpen else { return event }
if event.window === self.overlayWindow {
- NotificationCenter.default.post(
- name: .tagLauncherQuickSearchDismissRequested,
- object: nil,
- userInfo: ["source": QuickSearchDismissSource.mouse]
- )
- return nil
+ return event
}
return event
}
@@ -1886,7 +2003,7 @@
}
@objc private func openProStatusFromStatusMenu(_ sender: NSMenuItem) {
- openPreferences(targetTab: SettingsTabTarget.about)
+ openPreferences(targetTab: SettingsTabTarget.pro)
}
private func openPreferences(targetTab: String?) {
@@ -2052,12 +2169,15 @@
// NSHostingView.hitTest may return a SwiftUI-internal wrapper — the
// actual AppKit subview may be nested deeper.
if let container = findTextFieldContainer(in: hit) {
- container.mouseDown(with: event)
+ container.focusTextField()
return
}
if let tf = findNSTextField(in: hit) {
+ let shouldSelectAll = tf.currentEditor() == nil
tf.window?.makeFirstResponder(tf)
- tf.mouseDown(with: event)
+ if shouldSelectAll {
+ tf.selectText(nil)
+ }
return
}
super.mouseDown(with: event)
--
Gitblit v1.9.3