Bryan Potts
Bryan Potts

Reputation: 921

How do I listen for a keydown event in Swift5?

I am trying to catch a KeyDown event in a SwiftUI View deep in my MacOS app. However, I'm having trouble even getting one to fire in the AppDelegate.

Here is what I am trying now:

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    var window: NSWindow!
    var settings = UserSettings()

    func keyDown(theEvent: NSEvent) {
        if (theEvent.keyCode == 1){
            print("test")
        }
    }

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView().environmentObject(settings)

        // Create the window and set the content view. 
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        window.center()
        window.setFrameAutosaveName("Main Window")
        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }
}

How else can I approach this?

Upvotes: 0

Views: 1365

Answers (1)

user3441734
user3441734

Reputation: 17572

You can "install" your own handler (see window.trackEvents ...)

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    var window: NSWindow!

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView()

        // Create the window and set the content view. 
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        window.center()
        window.setFrameAutosaveName("Main Window")
        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)
        window.trackEvents(matching: .keyDown, timeout: .infinity, mode: RunLoop.Mode.default) { (event, _) in
            print(event)
        }
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }


}

here is some printing example

Optional(NSEvent: type=KeyDown loc=(116.223,179.594) time=38176.8 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="h" unmodchars="h" repeat=0 keyCode=4)
Optional(NSEvent: type=KeyDown loc=(116.223,179.594) time=38178.2 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="j" unmodchars="j" repeat=0 keyCode=38)
Optional(NSEvent: type=KeyDown loc=(116.223,179.594) time=38178.9 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="h" unmodchars="h" repeat=0 keyCode=4)
Optional(NSEvent: type=KeyDown loc=(116.223,179.594) time=38179.4 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="g" unmodchars="g" repeat=0 keyCode=5)
Optional(NSEvent: type=KeyDown loc=(116.223,179.594) time=38179.9 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="h" unmodchars="h" repeat=0 keyCode=4)
Optional(NSEvent: type=KeyDown loc=(108.574,-175.18) time=38184.5 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="m" unmodchars="m" repeat=0 keyCode=46)
Optional(NSEvent: type=KeyDown loc=(108.574,-175.18) time=38184.8 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="," unmodchars="," repeat=0 keyCode=43)
Optional(NSEvent: type=KeyDown loc=(108.574,-175.18) time=38185.1 flags=0x100 win=0x11b830710 winNum=2404 ctxt=0x0 chars="." unmodchars="." repeat=0 keyCode=47)

BE WORRY!! This is the simplest example, in real application your handler must handle ALL keyDown events!! As done in this example, the default actions (menu ... etc.) will not react. You even have to stop the app from your Xcode (or terminal), or force to quit it from system menu

Upvotes: 2

Related Questions