SwiftUI使用键盘快捷键调用NSPopover



我正在用SwiftUI为macOS Big Sur构建一个菜单栏应用程序,但我不知道如何用键盘快捷键打开popover(该应用程序的主窗口,因为它是一个菜单条应用程序(。我希望用户能够通过按Command+[a letter]来查看窗口,而不管他们在电脑上做什么(当然,只要应用程序是打开的(。以下是控制弹出窗口的主要功能和代码:

@main
struct MenuBarPopoverApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
Settings{
EmptyView()
}
.commands {
MenuBarPopoverCommands(appDelegate: appDelegate)
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
var popover = NSPopover.init()
var statusBarItem: NSStatusItem?
var contentView: ContentView!
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(_:))
}

@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)
}
}
}

还有MenuBarPopoverCommands(应用程序的主要部分是文本编辑器,所以我有很多与之相关的键盘快捷键(:

struct MenuBarPopoverCommands: Commands {

let appDelegate: AppDelegate

init(appDelegate: AppDelegate) {
self.appDelegate = appDelegate
}

var body: some Commands {
CommandMenu("Edit") {
Section {
Button("Cut") {
appDelegate.contentView.editCut()
}.keyboardShortcut(KeyEquivalent("x"), modifiers: .command)

Button("Copy") {
appDelegate.contentView.editCopy()
}.keyboardShortcut(KeyEquivalent("c"), modifiers: .command)

Button("Paste") {
appDelegate.contentView.editPaste()
}.keyboardShortcut(KeyEquivalent("v"), modifiers: .command)

Button("Undo") {
appDelegate.contentView.undo()
}.keyboardShortcut(KeyEquivalent("z"), modifiers: .command)

Button("Redo") {
appDelegate.contentView.redo()
}.keyboardShortcut(KeyEquivalent("z"), modifiers: [.command, .shift])

Button("Bold") {
appDelegate.contentView.bold()
}.keyboardShortcut(KeyEquivalent("b"), modifiers: .command)

Button("Italic") {
appDelegate.contentView.italic()
}.keyboardShortcut(KeyEquivalent("i"), modifiers: .command)

Button("Select All") {
appDelegate.contentView.editSelectAll()
}.keyboardShortcut(KeyEquivalent("a"), modifiers: .command)
}
}
}
}

Swift 5解决方案在https://stackoverflow.com/a/58225397/3984522.然而,有一个很好的包,它做的工作https://github.com/soffes/HotKey在几行代码中:


import SwiftUI
import HotKey
@main
struct MenuBarPopoverApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
Settings{
EmptyView()
}
.commands {
MenuBarPopoverCommands(appDelegate: appDelegate)
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
var popover = NSPopover.init()
var statusBarItem: NSStatusItem?
var contentView: ContentView!
let hotKey = HotKey(key: .x, modifiers: [.control, .shift])  // Global hotkey

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(systemSymbolName: "eye", accessibilityDescription: "eye")
itemImage?.isTemplate = true
statusBarItem?.button?.image = itemImage
statusBarItem?.button?.action = #selector(AppDelegate.togglePopover(_:))

hotKey.keyUpHandler = {                                 // Global hotkey handler
self.togglePopover()
}
}

@objc func showPopover(_ sender: AnyObject? = nil) {
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? = nil) {
popover.performClose(sender)
}

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

最新更新