You need to enable JavaScript to run this app. SwiftUI macOS菜单栏应用如何通过键盘快捷键唤起NSPopover
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI macOS菜单栏应用如何通过键盘快捷键唤起NSPopover

你当前用SwiftUI Commands 配置的快捷键仅在应用处于激活状态时才会响应,要实现用户在任意操作场景下都能触发快捷键打开Popover,需要使用全局键盘事件监听方案,具体修改步骤如下:

步骤1:新增全局快捷键监听逻辑

首先在AppDelegate中添加全局事件监听、权限校验相关代码,完整修改后的AppDelegate核心代码如下:

import CoreGraphics
import AppKit

class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
    var popover = NSPopover.init()
    var statusBarItem: NSStatusItem?
    var contentView: ContentView!
    // 存储全局监听对象
    private var hotKeyMonitor: Any?

    override class func awakeFromNib() {}
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        print("Application launched")
        NSApplication.shared.activate(ignoringOtherApps: true)
        
        contentView = ContentView()
        popover.animates = false
        popover.behavior = .transient
        
        let contentVc = NSViewController()
        contentVc.view = NSHostingView(rootView: contentView.environmentObject(self))
        popover.contentViewController = contentVc

        statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        let itemImage = NSImage(named: "statusBarIcon")
        itemImage?.isTemplate = true
        statusBarItem?.button?.image = itemImage
        statusBarItem?.button?.action = #selector(AppDelegate.togglePopover(_:))
        
        // 新增:校验辅助功能权限,注册全局快捷键监听
        let accessCheckOptions: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true]
        let isAccessGranted = AXIsProcessTrustedWithOptions(accessCheckOptions)
        if isAccessGranted {
            registerGlobalHotKey()
        }
    }
    
    // 新增:注册全局快捷键
    private func registerGlobalHotKey() {
        hotKeyMonitor = NSEvent.addGlobalMonitorForEvents(matching: .keyDown) { [weak self] event in
            guard let self = self else { return }
            // 这里可以替换为你想要的任意字母,比如改为"k"就是Command+K触发
            guard event.modifierFlags.contains(.command),
                  event.characters == "p",
                  // 避免和应用内快捷键冲突:应用激活且Popover已打开时不触发
                  !(NSApplication.shared.isActive && self.popover.isShown)
            else { return }
            self.togglePopover(nil)
        }
    }
    
    // 新增:退出时移除监听
    func applicationWillTerminate(_ notification: Notification) {
        if let monitor = hotKeyMonitor {
            NSEvent.removeMonitor(monitor)
        }
    }
    
    @objc func showPopover(_ sender: AnyObject?) {
        if let button = statusBarItem?.button {
            NSApplication.shared.activate(ignoringOtherApps: true)
            popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
        }
    }

    @objc func closePopover(_ sender: AnyObject?) {
        popover.performClose(sender)
    }

    @objc func togglePopover(_ sender: AnyObject?) {
        if popover.isShown {
            closePopover(sender)
        } else {
            showPopover(sender)
        }
    }
}

注意事项

  • 第一次启动应用时会弹出辅助功能权限申请提示,用户需要在「系统设置>安全性与隐私>隐私>辅助功能」中勾选你的应用,权限生效后全局快捷键才可正常使用
  • 你可以自行修改registerGlobalHotKey方法中event.characters == "p"的取值,替换为你想要绑定的任意字母,注意避开系统全局占用的快捷键即可
  • 原有MenuBarPopoverCommands中配置的编辑类快捷键不受影响,仅在Popover打开、应用激活时正常响应

内容的提问来源于stack exchange,提问作者Rohan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 03:54:03