Swift - Capture keydown from NSViewController Swift - Capture keydown from NSViewController swift swift

Swift - Capture keydown from NSViewController


Xcode 8.2.1 • Swift 3.0.2

import Cocoaclass ViewController: NSViewController {    @IBOutlet var textField: NSTextField!    override func viewDidLoad() {        super.viewDidLoad()        NSEvent.addLocalMonitorForEvents(matching: .flagsChanged) {            self.flagsChanged(with: $0)            return $0        }        NSEvent.addLocalMonitorForEvents(matching: .keyDown) {            self.keyDown(with: $0)            return $0        }    }    override func keyDown(with event: NSEvent) {        switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {        case [.command] where event.characters == "l",             [.command, .shift] where event.characters == "l":            print("command-l or command-shift-l")        default:            break        }        textField.stringValue = "key = " + (event.charactersIgnoringModifiers            ?? "")        textField.stringValue += "\ncharacter = " + (event.characters ?? "")    }    override func flagsChanged(with event: NSEvent) {        switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {        case [.shift]:            print("shift key is pressed")        case [.control]:            print("control key is pressed")        case [.option] :            print("option key is pressed")        case [.command]:            print("Command key is pressed")        case [.control, .shift]:            print("control-shift keys are pressed")        case [.option, .shift]:            print("option-shift keys are pressed")        case [.command, .shift]:            print("command-shift keys are pressed")        case [.control, .option]:            print("control-option keys are pressed")        case [.control, .command]:            print("control-command keys are pressed")        case [.option, .command]:            print("option-command keys are pressed")        case [.shift, .control, .option]:            print("shift-control-option keys are pressed")        case [.shift, .control, .command]:            print("shift-control-command keys are pressed")        case [.control, .option, .command]:            print("control-option-command keys are pressed")        case [.shift, .command, .option]:            print("shift-command-option keys are pressed")        case [.shift, .control, .option, .command]:            print("shift-control-option-command keys are pressed")        default:            print("no modifier keys are pressed")        }    }}

To get rid of the purr sound when pressing the character keys you need to subclass your view, override the method performKeyEquivalent and return true.

import Cocoaclass View: NSView {    override func performKeyEquivalent(with event: NSEvent) -> Bool {        return true    }}

Sample Project


Swift4

Just found a solution for the very same problem, Swift4. The idea behind that: if the pressed key was handled by a custom logic, the handler shall return nil, otherwise the (unhandled) event...

class MyViewController: NSViewController {   override func viewDidLoad() {      super.viewDidLoad()      // ...      NSEvent.addLocalMonitorForEvents(matching: .keyDown) {         if self.myKeyDown(with: $0) {            return nil         } else {            return $0         }      }   }   func myKeyDown(with event: NSEvent) -> Bool {      // handle keyDown only if current window has focus, i.e. is keyWindow      guard let locWindow = self.view.window,         NSApplication.shared.keyWindow === locWindow else { return false }      switch Int( event.keyCode) {      case kVK_Escape:         // do what you want to do at "Escape"         return true      default:          return false      }   }}

And here we are: no Purr / Funk sound when key is pressed...

[Update] Added check of keyWindow. Without this, keyDown() is fired even if another view/window contains the first responder...


I was trying to find an answer for swift 3, here is what worked for me:

Swift 3

import Cocoa// We subclass an NSViewclass MainView: NSView {    // Allow view to receive keypress (remove the purr sound)    override var acceptsFirstResponder : Bool {        return true    }    // Override the NSView keydown func to read keycode of pressed key    override func keyDown(with theEvent: NSEvent) {        Swift.print(theEvent.keyCode)    }}