Swift - Захват ключа от NSViewController

Я хотел бы захватить ключевые события в своем маленьком приложении.

Что я сделал:

class ViewController : NSViewController {
...
  override func keyDown(theEvent: NSEvent) {
        if theEvent.keyCode == 124 {
            println("abc")
        } else {
            println("abcd")
        }
    }

    override var acceptsFirstResponder: Bool {
        return true
    }

    override func becomeFirstResponder() -> Bool {
        return true
    }

    override func resignFirstResponder() -> Bool {
        return true
    }

...
}

Что происходит:

При нажатии клавиши звуковой эффект Funk воспроизводится.

Я видел много сообщений о том, как это делегат, принадлежащий NSView и NSViewController не имеет доступа. Но функция keydown override auto завершается в классе типа NSViewController, заставляя меня считать, что это неправильно.

Ответы

Ответ 1

Xcode 8.2.1 • Swift 3.0.2

import Cocoa

class 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")
        }
    }
}

Чтобы избавиться от мурлычащего звука при нажатии символьных клавиш, вам необходимо подклассифицировать ваше представление, переопределить метод executeKeyEquivalent и вернуть true.

import Cocoa

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

Пример проекта

Ответ 2

Я пытался найти ответ для быстрого 3, вот что сработало для меня:

Swift 3

import Cocoa

// We subclass an NSVIEW

class MainView: NSView {

// Allow view to receive keypress (remove the purr sound)
override var acceptsFirstResponder : Bool {
    return true
}

override func draw(_ dirtyRect: NSRect) {

    super.draw(dirtyRect)
}

// Override the NSView keydown func to read keycode of pressed key
override func keyDown(with theEvent: NSEvent) 
    {

    Swift.print(theEvent.keyCode)
    return

    }

}

Ответ 3

Мне удалось заставить его работать из подкласса NSWindowController

class MyWindowController: NSWindowController {

    override func keyDown(theEvent: NSEvent) {
        print("keyCode is \(theEvent.keyCode)")
    }
}

UPDATE:

import Cocoa

protocol WindowControllerDelegate {
    func keyDown(aEvent: NSEvent)
}

class WindowController: NSWindowController {

    var delegate: WindowControllerDelegate?

    override func windowDidLoad() {
        super.windowDidLoad()
        delegate = window?.contentViewController as! ViewController
    }
    override func keyDown(theEvent: NSEvent) {
        delegate?.keyDown(theEvent)
    }

}

и ViewController:

class ViewController: NSViewController, WindowControllerDelegate {

    @IBOutlet weak var textField: NSTextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: AnyObject? {
        didSet {
        // Update the view, if already loaded.
        }
    }
    override func keyDown(theEvent: NSEvent) {
        textField.stringValue = "key = " + (theEvent.charactersIgnoringModifiers
            ?? "")
        textField.stringValue += "\ncharacter = " + (theEvent.characters ?? "")
        textField.stringValue += "\nmodifier = " + theEvent.modifierFlags.rawValue.description
    }

}