Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create an NSMenu containing an NSMenuItem which only appears while holding a keyboard modifier key?

I'd like to create an NSMenu containing an NSMenuItem which is hidden by default, and only appears while the user is holding a keyboard modifier key.

Basically, I'm looking for the same behaviour as the 'Library' option in the Finder's 'Go' Menu:

Without holding Option (⌥): enter image description here

While holding Option (⌥): enter image description here


I already tried installing a key listener using [NSEvent addGlobalMonitorForEventsMatchingMask: handler:] to hide and unhide the NSMenuItem programmatically by setting it's hidden property. This kind of worked, but the problem is that the hiding/unhiding wouldn't work while the NSMenu was open. Apparently an NSMenu completely takes over the event processing loop while it's open, preventing the key listener from working.
I could probably use a CGEventTap to still receive events while the NSMenu is open, but that seems like complete overkill.

Another thing I discovered which does a similar thing to what I want is the 'alternate' mechanism of NSMenu. But I could only get it to switch out NSMenuItems, not hide/unhide them.

Any help would be greatly appreciated. Thanks!

like image 363
Noah Nuebling Avatar asked Oct 17 '25 01:10

Noah Nuebling


1 Answers

I found a solution that behaves perfectly!

  1. On the NSMenuItem you want hidable, set the alternate property to YES, and set the keyEquivalentModifierMask property to the keyboard modifiers which you want to unhide the item.

  2. In your NSMenu, right before the NSMenuItem which you want to be hideable, insert another NSMenuItem that has height 0.

    In Objc, you can create an NSMenuItem with height 0 like this:

    NSMenuItem *i = [[NSMenuItem alloc] init];
    i.view = [[NSView alloc] initWithFrame:NSZeroRect]; 
    i.hidden = YES;
    

The hideable NSMenuItem will now be 'alternate' to the zero-height NSMenuItem preceding it. The zero-height item will display by default, but while you hold the keyboard modifier(s) you specified, the zero-height item will be swapped out with the hideable item. Because the zero-height item is invisible, this has the effect of unhiding the hideable item.


like image 142
Noah Nuebling Avatar answered Oct 20 '25 14:10

Noah Nuebling



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!