Search code examples
swiftmacoscocoanstextviewnsviewcontroller

recognizing key event in entire window


i am working on a transliteration app that gets some text from an NSTextView and transliterate it and puts it in another NSTextView, what i want to do is, as the user is typing the sentence when he types a word and presses space i want the space key to trigger an action which i specify to break the sentence into an array of individual words. in order to do that i have tried overriding the keyDown function in the viewController class:

override func keyDown(theEvent: NSEvent) {
    if (theEvent.keyCode == 49){
        print("pressed space")
    }
}

which does not work , it works when i subclass NSTextView class and override keyDown function in it but my textView stops inputing text. how can i set a key event for space key that works ? any other suggestion for breaking a sentence into word array by pressing space?

thanks


Solution

  • Step 1 is to set your View Controller to be a delegate of NSTextField. If you use nibs or storyboard it will look like this:

    enter image description here

    Basically ctrl drag to view controller and set delegate.

    Then you can react on text changed in your view controller:

    import Cocoa
    
    class ViewController: NSViewController {
    
    
    override func controlTextDidChange(obj: NSNotification) {
    
        guard let textField = obj.object as? NSTextField else { return }
    
        if textField.stringValue.characters.last == " " {
            print(textField.stringValue.componentsSeparatedByString(" "))
        }
    
    }
    }
    

    It will print out array of words which were separated by space:

    ["a", ""]

    ["a", "boy", ""]

    ["a", "boy", "came", ""]

    ["a", "boy", "came", "to", ""]

    ["a", "boy", "came", "to", "school", ""]

    You may need to remove last item from the array:

         override func controlTextDidChange(obj: NSNotification) {
    
        guard let textField = obj.object as? NSTextField else { return }
    
        if textField.stringValue.characters.last == " " {
            print(textField.stringValue.componentsSeparatedByString(" ").filter { $0 != "" })
        }
    
    }
    

    For NSTextView the logic is similar. Ctrl drag from text view to set view controller as delegate: enter image description here

    Then use the following code:

      func textDidChange(obj: NSNotification) {
    
        guard let textView = obj.object as? NSTextView else { return }
        guard let stringValue = textView.textContainer?.textView?.string else { return }
    
        if stringValue.characters.last == " " {
            print(stringValue.componentsSeparatedByString(" ").filter { $0 != "" })
        }
    
    }
    

    It will work fine:

    enter image description here