1

In Swift, is there a function in Cocoa framework to handle the press so that you can register which keyboard key has been hit?

I'd like to get the escape key

UPDATED: i just found that the noise was casued by super.keyDown(with: event) wich is not needed for the thing to work why did u add that line?

Sarah linone
  • 43
  • 1
  • 7

1 Answers1

5

Create a subclass of NSWindow and implement keyDown event:

import Cocoa
import Carbon.HIToolbox

class CustomWindow: NSWindow {

    override func keyDown(with event: NSEvent) {
        switch Int(event.keyCode) {
        case kVK_Escape:
            print("Esc pressed")
        default:
            break
        }
        super.keyDown(with: event)
    }

}

This line:

import Carbon.HIToolbox

Lets you use handy constants for keys, such as kVK_Escape.

Set this class as your main window class in the Interface Builder and you're all set:

enter image description here

enter image description here

P.S. To do the same form NSViewController, in viewDidLoad do:

NSEvent.addLocalMonitorForEvents(matching: .keyDown) {
    self.keyDown(with: $0)
    return $0
}

P.P.S. To mute "bang" sound, don't call super upon Escape key press - move super call to default:

default:
    super.keyDown(with: event)

EDIT:

If you don't want any sound on Escape key press, then the following approach should be used:

Make an NSView subclass and set it to main view of the view controller:

import Cocoa
import Carbon.HIToolbox

class CustomView: NSView {
    override func performKeyEquivalent(with event: NSEvent) -> Bool {
        switch Int(event.keyCode) {
        case kVK_Escape:
            print("Esc pressed")
            return true
        default:
            return super.performKeyEquivalent(with: event)
        }
    }
}
Hexfire
  • 5,945
  • 8
  • 32
  • 42
  • awsome nswer, would it be possible to run the overide function from the main viewcontroler? – Sarah linone Nov 23 '17 at 07:19
  • also, when i hit escape in my app it does that bang sound is there a way to turn that off? – Sarah linone Nov 23 '17 at 07:53
  • 1
    "bang" sound is played because super is called. You can put this line: `super.keyDown(with: event)` to default implementation, thus avoiding it to be called upon Escape key press. – Hexfire Nov 23 '17 at 09:17
  • it seems that my textfield in my app are preventing the function to run it prevents the printing, do you know if there's anyway the setting of my textfield could cause this? I made sure they were all not accepting first responder – Sarah linone Nov 23 '17 at 09:36
  • I updated my answer. Try using View Controller implementation. I tested with textfield, works fine (accepts input and escape is handled). – Hexfire Nov 23 '17 at 09:39
  • even when I make a new project the moment I add a textfield it prevents it from working and does the bang sound even if I don't have the super keydown line code in – Sarah linone Nov 23 '17 at 09:40
  • "Bang sound" is default, normal behavior as designed by macOS when you hit Escape and it is unhandled. – Hexfire Nov 23 '17 at 09:41
  • To mute bang sound from elsewhere, I believe you might need to override keyDown behavior from everywhere, because your textfield obviously handles it to accept input. – Hexfire Nov 23 '17 at 09:45
  • the function with ur update now works fine, but the bang noise is still there even with keydown line in default https://imgur.com/a/mvIFb – Sarah linone Nov 23 '17 at 09:48
  • is there a way to mute it from the textfield with an override function like that one – Sarah linone Nov 23 '17 at 09:49
  • Indeed, it persists on typing. Remove super call completely (add `break` instead). This way input will be normal, but sound will be there on Escape press. To remove it completely, I believe textfield should be subclassed. – Hexfire Nov 23 '17 at 09:52
  • is there an easy way to do that? – Sarah linone Nov 23 '17 at 09:59
  • I tried it again with a new app and the noise appears even when its a new app with nothing on it, no textfield, – Sarah linone Nov 23 '17 at 10:09
  • Beep won't occur if you use `NSWindow` approach, with no super call. However, Escape won't be catched if you make other controls first responder. This way you would need to make ViewController catch keyDown events. That's a tricky task you are trying to nail. :) – Hexfire Nov 23 '17 at 10:17
  • This would require some research, I don't have a solution straight away. Consider asking a new question for this. – Hexfire Nov 23 '17 at 10:18
  • alrighr hexfire, i will do my own research i apreacite the great help you gave me – Sarah linone Nov 23 '17 at 10:24
  • Glad to assist. Don't hesitate to make a new topic, solution is there for sure. – Hexfire Nov 23 '17 at 10:30
  • Post here whenever you come up with one, I'll come back to continue it with you. – Hexfire Nov 23 '17 at 10:41
  • we got to work by using "import Cocoa class CustomView: NSView { override func performKeyEquivalent(with event: NSEvent) -> Bool { return true } } " and linking it to the view – Sarah linone Nov 23 '17 at 22:42
  • Yeah, I came to similar solution yesterday, except that in order for other keys, such as arrows, ctrl, alt, etc work properly, you need to implement that event like this: `override func performKeyEquivalent(with event: NSEvent) -> Bool { switch Int(event.keyCode) { case kVK_Escape: print("Esc pressed") return true default: return super.performKeyEquivalent(with: event) } }` and remove implementation from `NSWindow` and `ViewController`. This way there will be no sound and all keys will work properly. – Hexfire Nov 24 '17 at 05:44
  • what do you think of class EscapeKeyNoiseRemoval: NSView { override func performKeyEquivalent(with event: NSEvent) -> Bool { return event.keyCode == 53 } } same result? – Sarah linone Nov 24 '17 at 06:37
  • @LeoDabus accusing someone of something like this without any proof should be against the rules, too. So I'd either accept an apology, or a proof that I used (or even saw) your answer. As for calling super, that's a reasonable part of your comment and I will surely add this to the answer, referring your name on your permission. – Hexfire Nov 26 '17 at 06:14