虽然有点晚,但这里提供一种不同的方法,也是通过子类化NSButton
来实现:
import AppKit
public class DelayedMenuButton: NSButton {
public var delayedMenu: NSMenu?
}
extension DelayedMenuButton {
public override func mouseDown(with event: NSEvent) {
guard delayedMenu != nil, isEnabled else {
super.mouseDown(with: event)
return
}
let delayedItem = DispatchWorkItem { [weak self] in
self?.showDelayedMenu()
}
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(NSEvent.doubleClickInterval * 1000)), execute: delayedItem)
let defaultAction = self.action
super.mouseDown(with: event)
self.action = defaultAction
delayedItem.cancel()
}
}
private extension DelayedMenuButton {
func showDelayedMenu() {
guard
let delayedMenu = delayedMenu, delayedMenu.numberOfItems > 0, let window = window, let location = NSApp.currentEvent?.locationInWindow,
let mouseUp = NSEvent.mouseEvent(
with: .leftMouseUp, location: location, modifierFlags: [], timestamp: Date.timeIntervalSinceReferenceDate,
windowNumber: window.windowNumber, context: NSGraphicsContext.current, eventNumber: 0, clickCount: 1, pressure: 0
)
else {
return
}
action = nil
delayedMenu.popUp(positioning: nil, at: .init(x: -4, y: bounds.height + 2), in: self)
window.postEvent(mouseUp, atStart: false)
}
}