cocoanssavepanel

How to trigger default save action on NSSavePanel with accessoryView


Due to a bug on macOS Sonoma I am looking for a workaround to trigger default action of NSSavePanel in a sandboxed app.

The issue is that the NSSavePanel's accessorryView view doesn't react to enter key press. This works on lower macOS version.

The enter key press calls performKeyEquivalent: in the NSResponder chain.

Can I just call savePanel.performKeyEquivalent in the sandboxed app and call it a day?

import Carbon.HIToolbox.Events
override func performKeyEquivalent(with event: NSEvent) -> Bool {

  if let savePanel, event.type == .keyDown && (event.keyCode == UInt16(kVK_Return) || event.keyCode == UInt16(kVK_ANSI_KeypadEnter)) {
      savePanel.performKeyEquivalent(with: event)
  } else {
      super.performKeyEquivalent(with: event)
  }
}

PS: this workaround is not needed on Ventura and below

enter image description here

Full quick example:

import Carbon.HIToolbox.Events

class CustomView: NSView {
    weak var savePanel: NSSavePanel?
    override func performKeyEquivalent(with event: NSEvent) -> Bool {

      if let savePanel, event.type == .keyDown && (event.keyCode == UInt16(kVK_Return) || event.keyCode == UInt16(kVK_ANSI_KeypadEnter)) {
          savePanel.performKeyEquivalent(with: event)
      } else {
          super.performKeyEquivalent(with: event)
      }
    }
}

class ViewController: NSViewController {

    let savePanel = NSSavePanel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let customView = CustomView()
        customView.addSubview(NSTextField(string: "11111111"))
        customView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            customView.widthAnchor.constraint(equalToConstant: 120),
            customView.heightAnchor.constraint(equalToConstant: 20)
        ])
        customView.savePanel = savePanel
        savePanel.accessoryView = customView
    }
    
    override func viewWillAppear() {
        savePanel.runModal()
    }

}

Solution

  • This was a bug on macOS14. Fixed in macOS15. Provided code works in production app.

    import Carbon.HIToolbox.Events
    override func performKeyEquivalent(with event: NSEvent) -> Bool {
    
      if let savePanel, event.type == .keyDown && (event.keyCode == UInt16(kVK_Return) || event.keyCode == UInt16(kVK_ANSI_KeypadEnter)) {
          savePanel.performKeyEquivalent(with: event)
      } else {
          super.performKeyEquivalent(with: event)
      }
    }