admin管理员组

文章数量:1426227

I'm building a mac app with status bar icon. I want to handle right-click event on the icon.

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?

I'm building a mac app with status bar icon. I want to handle right-click event on the icon.

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?

Share Improve this question edited 3 hours ago laike9m asked Dec 13, 2024 at 7:18 laike9mlaike9m 19.5k23 gold badges116 silver badges154 bronze badges 6
  • This doesn't make sense to me. How do you "tap" on the status bar with "two fingers" no less? MacBook screens are not touch screens. – Sweeper Commented Dec 13, 2024 at 9:18
  • Does two-finger tap on a trackpad do the same as right-click with a mouse? – Willeke Commented Dec 14, 2024 at 6:09
  • @Sweeper I meat tap the touch pad not screen. – laike9m Commented Dec 16, 2024 at 22:27
  • @Willeke it's different. PopClip has this feature, if tap with two fingers it will toggle app's status (on/off), if right or left click, it opens the menu. – laike9m Commented Dec 16, 2024 at 22:28
  • Turn PopClip On and Off: "As a short-cut, you can also toggle PopClip on and off by secondary clicking (Right-click or Control-click) the PopClip icon in the menu bar.". Mac Trackpad gestures: "Secondary click (right-click): Click or tap with two fingers.". – Willeke Commented Dec 17, 2024 at 6:29
 |  Show 1 more comment

2 Answers 2

Reset to default 0

Be sure to keep a strong reference to the StatusBar, this may be the reason why the selector is not called

private var statusBar: StatusBar = StatusBar()

I used this code to manually display the custom menu, it worked correctly on macOS 14 and 15

statusBarItem.button?.target = self
statusBarItem.button?.sendAction(on: [.leftMouseDown, .rightMouseDown])
statusBarItem.button?.action = #selector(handleStatusBarClick)

Be sure to make sure the statusbar does not have a menu installed

One possible problem: it is better to use the system statusbar

statusBar = NSStatusBar.system

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/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
    ...
  }
}

本文标签: swiftHow do I capture the right click event on status barStack Overflow