How to handle keyDown in SwiftUI for macOS

Issue #764

Use a custom KeyAwareView that uses an NSView that checks for keyDown method. In case we can’t handle certain keys, call super.keyDown(with: event)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import SwiftUI
import KeyboardShortcuts

struct KeyAwareView: NSViewRepresentable {
let onEvent: (Event) -> Void

func makeNSView(context: Context) -> NSView {
let view = KeyView()
view.onEvent = onEvent
DispatchQueue.main.async {
view.window?.makeFirstResponder(view)
}
return view
}

func updateNSView(_ nsView: NSView, context: Context) {}
}

extension KeyAwareView {
enum Event {
case upArrow
case downArrow
case leftArrow
case rightArrow
case space
case delete
case cmdC
}
}

private class KeyView: NSView {
var onEvent: (KeyAwareView.Event) -> Void = { _ in }

override var acceptsFirstResponder: Bool { true }
override func keyDown(with event: NSEvent) {
switch Int(event.keyCode) {
case KeyboardShortcuts.Key.delete.rawValue:
onEvent(.delete)
case KeyboardShortcuts.Key.upArrow.rawValue:
onEvent(.upArrow)
case KeyboardShortcuts.Key.downArrow.rawValue:
onEvent(.downArrow)
case KeyboardShortcuts.Key.leftArrow.rawValue:
onEvent(.leftArrow)
case KeyboardShortcuts.Key.rightArrow.rawValue:
onEvent(.rightArrow)
case KeyboardShortcuts.Key.space.rawValue:
onEvent(.space)
case KeyboardShortcuts.Key.c.rawValue where event.modifierFlags.contains(.command):
onEvent(.cmdC)
default:
super.keyDown(with: event)
}
}
}

Then we can place this as a background

1
2
3
4
LazyVStack {

}
.background(KeyAwareView(onEvent: {}))

Updated at 2021-01-29 20:55:39

Comments