Search code examples
swiftnsbutton

Programatically changing button text and actions when a modifier key is pressed


I would like to change the text of an NSButton when the ⌥ Option key is pressed - similar to the copy dialog when colliding files are detected on OS X which changes "Keep Both" to "Merge" when the option key is held.

In my case, I would like to change a button with text, say, "delete" to "quit" when I hold the option key. Additionally, its functionality should change in accordance with its title, much like the options in the Copy dialog.

Can this be done programatically in Swift?


Solution

  • You can subscribe using addLocalMonitorForEvents(matching:) and detect if option key pressed like this:

    var optionKeyEventMonitor: Any? // property to store reference to the event monitor
    
    // Add the event monitor
    optionKeyEventMonitor = NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) { event in
        if event.modifierFlags.contains(.option) {
            self.button.title = "copy"
            self.button.action = #selector(self.copyButtonClicked(_:))
        } else {
            self.button.title = "delete"
            self.button.action = #selector(self.deleteButtonClicked(_:))
        }  
        return event
    }
    
    @IBAction func copyButtonClicked(_ sender: Any) {
        Swift.print("Copy button was clicked!")
    }
    
    @IBAction func deleteButtonClicked(_ sender: Any) {
        Swift.print("Delete button was clicked!")
    }
    

    Remember to remove the event monitor when you are done:

    deinit {
        if let eventMonitor = optionKeyEventMonitor {
            NSEvent.removeMonitor(eventMonitor)
        }
    }
    

    If you don't want a separate method called depending on the option key state, you can check modifierFlags when button is clicked instead:

    @IBAction func buttonClicked(sender: NSButton) {
        if NSEvent.modifierFlags().contains(.option) {
            print("option pressed")
        } else {
            print("option not pressed")
        }
    }