How to capture or monitor all kind of keyboard event from NSViewController?

import Cocoa

class MyView: NSView {

override init(frame frameRect: NSRect) {
    super.init(frame: frameRect)
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

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

override var acceptsFirstResponder: Bool {
    return true
}

override func keyUp(with event: NSEvent) {
    print("keyUp: keyCode=\(event.keyCode)")
}

// the 'CMD + q' combination will quit the app
// the 'CMD + t' combination will open a font setting window
// the 'CMD + Space' combination will toggle the spotlight search
// the 'CTRL + Space' combination will toggle the input method switching
// why this can't capture the key board event like 'CMD + Space' or 'CMD + t' or 'CMD + q'?
// or how capture those combinations regardless of the system-wide shortcuts?
override func keyDown(with event: NSEvent) {
    print("keyDown: keyCode=\(event.keyCode)")
    if event.modifierFlags.contains(.command) {
        if event.keyCode == 49 {
            print("keyDown: CMD + Space") // if the 'CMD' and 'Space' keys were pressed both, this line is not print
        } else {
            print("keyDown: CMD + others") // here, like 'CMD' and 'j' keys were pressed both, this line is print
        }
    } else if event.modifierFlags.contains(.control) {
        if event.keyCode == 49 {
            print("keyDown: CTRL + Space") // if the 'CTRL' and 'Space' keys were pressed both, this line is not print
        } else {
            print("keyDown: CTRL + others") // here, like 'CTRL' and 'j' keys were pressed both, this line is print
        }
    } else {
        print("keyDown: CMD or CTRL is not pressed")
    }
}

override func flagsChanged(with event: NSEvent) {
    print(#function, event.keyCode)
}

}

class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() }

override func viewWillAppear() {
    super.viewWillAppear()
    let myview = MyView(frame: view.bounds)
    view.addSubview(myview)
}

}

Answered by DTS Engineer in 795461022

In macOS, there are some system-preserved shortcuts (key combinations). You have mentioned some good examples: CMD + q is preserved for quitting an app, and CMD + Space is preserved to toggle the spotlight search.

When a user inputs a shortcut of the kind, the system processes it directly; it doesn't pass the event to apps, and so your app can't capture the input.

The only thing that allows an app to detect this kind of input is Event Tap (see CGEventTapCreate), but when using the API:

  • Your app needs to be added to the list of Privacy & Security > Input Monitoring.
  • You still can't change how the system processes the event.

I am curious why your app needs to monitor the system-preserved shortcuts, and may have more to say if you can share more details of your use case, but most likely, you will eventually need to avoid doing that.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

In macOS, there are some system-preserved shortcuts (key combinations). You have mentioned some good examples: CMD + q is preserved for quitting an app, and CMD + Space is preserved to toggle the spotlight search.

When a user inputs a shortcut of the kind, the system processes it directly; it doesn't pass the event to apps, and so your app can't capture the input.

The only thing that allows an app to detect this kind of input is Event Tap (see CGEventTapCreate), but when using the API:

  • Your app needs to be added to the list of Privacy & Security > Input Monitoring.
  • You still can't change how the system processes the event.

I am curious why your app needs to monitor the system-preserved shortcuts, and may have more to say if you can share more details of your use case, but most likely, you will eventually need to avoid doing that.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

Hi, ziqiao

thanks for your reply.

I am developing a vnc client on macOS, so I need to monitor the keyboard events if needed.

When the app connected to a vnc server with a new window, there's a toolbar item at the window's toolbar, which I called it 'Input toolbar item'. If this input toolbar item was toggled, the app should capture all kind of input events including keyboard, trackpad and mouse events and send those events to the vnc server via the RFB protocol. For example, when I pressed 'CMD + Space' keys within the vnc window, I need to send them to the vnc server rather than toggle the spotlight search on the host machine.

Any suggestions for this?

Thanks,

That sounds like a reasonable use case to use Event Tap, but the API doesn't prevent macOS from toggling the Spotlight search bar, and I unfortunately don't see any way to achieve that...

I guess you can file a feedback report with your use case to see what the team has to say. If you do so, please post your report ID here for folks to track.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

How to capture or monitor all kind of keyboard event from NSViewController?
 
 
Q