10

In many macOS apps, if you open a menu from the main menubar, you can press the option key to change some of the items.

For example in Safari, I can open the File menu, and there is a "Close Tab" item. Pressing option changes it to "Close Other Tabs".

Is there a way to do this with SwiftUI?

I know how to create basic menus, but I don't see a way to detect the option key.

I think in AppKit you use NSMenuItem's isAlternate property.

struct MyApp: App {

    var body: some Scene {
        WindowGroup { 
            ...
        }.commands {
            CommandGroup(replacing: .newItem) {
                Button { newFolder() } label: { Text("New Folder") }
                   .keyboardShortcut("n")
                ...
            }        
        }

Update to Question

I've tried a few more things, and run into two problems.

  1. I can connect a custom object to the end of the NSResponder chain, and the system will call its flagsChanged method when the user presses the option key. However, it will not call this method when a menu is open.
  2. Even if I find a way to observe the option key while the menu is open, changing state used to build a CommandMenu causes the menu to disappear, not rebuild and stay open.
var body: some Commands {
   // If the `isOptionDown` property changes when this menu is open,
   // SwiftUI doesn't change the menu, it simply closes it.
   // That's not how macOS apps usually behave.
   CommandGroup(replacing: .pasteboard) {
      Button(...)
      if optionKeyWatcher.isOptionDown {
          Button(...)
      } else {
          Button(...)
      }
2

1 Answer 1

1

Since macOS 15.0, this is now possible using modifierKeyAlternate(_:_:):

// File > Save
Button("Save", ...) // ⌘ S
    .keyboardShortcut("s")
    .modifierKeyAlternate(.option) {
        Button("Save All", ...) // ⌥⌘ S
    }

Source: https://developer.apple.com/documentation/swiftui/view/modifierkeyalternate(_:_:)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.