macosswiftuiswiftui-menu

How to remap macOS default keyboard shortcuts in a SwiftUI native app


I'm building a multiplatform app with SwiftUI for iOS, iPadOS and macOS. The macOS app will be a native app, rather than using Catalyst.

The app has a number of different data types which can be added, the principal of which is an Event type. I want to add these as a submenu in the File menu, with the new event action, the most commonly used, available as ⌘N.

That keyboard shortcut is currently mapped to the New Window built-in menu action. I'd like to keep that action but instead, remap its keyboard shortcut to ⌘⇧N.

I can't see how to do that, however.

Currently I have a command set defined as below (with an environment object that handles the display of, and navigation to, the relevant panels):

struct NewItemCommands: Commands {
    @EnvironmentObject private var appNavigation: AppNavigation

    var body: some Commands {
        CommandGroup(before: .newItem) {
            Menu("New") {
                Button("Event", action: appNavigation.newEvent)
                    .keyboardShortcut("N")
                Button("Genre", action: appNavigation.newGenre)
                Button("Publication", action: appNavigation.newPublication)
                Button("Venue", action: appNavigation.newVenue)
            }
            .disabled(appNavigation.isShowingModal)
        }
    }
}

This gives me the submenu I want, with the correct shortcut assigned to New > Event. However, the New Window's default shortcut remains but never gets responded to:

Example of menu, as modified by the above code

Is there a way to remap that shortcut for New Window - or a way to create a new command with identical functionality that I can use to replace the default, with my own shortcut assigned?


Solution

  • You can use CommandGroup(replacing:) instead of CommandGroup(before:). Pass in .newItem to replace the "new window" menu item, then add your own implementation of it, with keyboardShortcut(...).

    .commands {
        CommandGroup(replacing: .newItem) {
            Menu("New") {
                Button("Event", action: {...})
                    .keyboardShortcut("N")
                Button("Genre", action: {...})
                Button("Publication", action: {...})
                Button("Venue", action: {...})
            }
            Button("New Window") {
                // get this with @Environment(\.openWindow) var openWindow
                // and give your WindowGroup some id
                openWindow(id: "Some ID")
            }.keyboardShortcut("N", modifiers: [.command, .shift])
        }
    }