I'm building a mac app with status bar icon. I want to enable two-finger tap guesture when tapping on the icon (note: physically, you tap the touchpad). Tried the following code, but even if I use
button.sendAction(on: .any)
, handleTwoFingerTap
is not triggered.
class StatusBar {
var statusBar: NSStatusBar!
var statusBarItem: NSStatusItem!
init() {
statusBar = NSStatusBar()
statusBarItem = statusBar.statusItem(
withLength: NSStatusItem.variableLength
)
if let button = statusBarItem.button {
// code to set up icon is ignored
// Doesn't work
button.sendAction(on: .any)
button.action = #selector(handleTwoFingerTap(_:))
button.target = self
}
}
@objc private func handleTwoFingerTap(_: Any?) {
// this function is not called
}
}
I suspect this is due to the limitation of sendAction
, quote
The only conditions that are actually checked are associated with the NSLeftMouseDownMask, NSLeftMouseUpMask, NSLeftMouseDraggedMask, and NSPeriodicMask bits.
In that case, how to make this work?
This is what works for me after many trials and errors. I use it in my app.
What I did is to handle left click and right click differently. Got a lot of help from this answer Show NSMenu only on NSStatusBarButton right click?. When right click, it will turn the app on and off. When left click, it shows the status menu.
class StatusBar: NSObject, NSMenuDelegate {
var statusBar = NSStatusBar()
var statusItem: NSStatusItem!
var statusMenu: NSMenu!
var button: NSStatusBarButton!
@objc func menuDidClose(_: NSMenu) {
statusItem.menu = nil
}
// Left click to trigger menu
// Right click to turn app on/off
// Solution from https://stackoverflow.com/q/59635971
@objc func statusBarButtonClicked(sender _: NSStatusBarButton) {
switch NSApp.currentEvent!.type {
case .leftMouseUp:
statusItem.menu = statusMenu
statusItem.button?.performClick(nil)
case .rightMouseDown:
Defaults[.appEnabled].toggle()
updateButtonStatus()
default:
return
}
}
override init() {
super.init()
statusItem = statusBar.statusItem(
withLength: NSStatusItem.variableLength
)
setUpStatusButton()
setupMenu()
}
func setUpStatusButton() {
button = statusItem.button
button.toolTip = "Clicknow"
button.image = NSImage(named: "status bar")
button.action = #selector(statusBarButtonClicked(sender:))
button.sendAction(on: [.leftMouseUp, .rightMouseDown])
button.target = self
updateButtonStatus()
}
func updateButtonStatus() {
if Defaults[.appEnabled] {
button.appearsDisabled = false
} else {
button.appearsDisabled = true
}
}
func setupMenu() {
statusMenu = NSMenu()
statusMenu.delegate = self // important
...
}
}