oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1import Foundation
2
3/// What has the keyboard in a window when Space is pressed.
4public enum KeyboardFocus: Equatable, Sendable {
5 /// Nothing in particular: the window itself, or its root view.
6 case none
7 /// A text field or text view, where Space is a space.
8 case text
9 /// A button, picker or any other control, where Space is the
10 /// control's own activation. Anything not known to be one of the
11 /// other two counts as this: an unrecognised focused thing keeps its
12 /// Space rather than losing it to the microphone.
13 case control
14}
15
16/// Space toggles the microphone during a call, the way it does in most
17/// calling apps — but only when Space means nothing else. The rules are
18/// here, apart from the key monitor that applies them, so they can be
19/// held by tests without a window or a keyboard.
20public enum SpaceToMute {
21 public enum Action: Equatable, Sendable {
22 /// Toggle mute, and consume the key.
23 case toggle
24 /// Consume the key and do nothing: a held Space's key repeats, which
25 /// would otherwise flicker the microphone or beep.
26 case swallow
27 /// Not ours: let the key go on to whatever has focus.
28 case pass
29 }
30
31 /// The virtual key code of the Space bar on every Mac keyboard layout.
32 public static let keyCode: UInt16 = 49
33
34 /// - Parameters:
35 /// - isSpace: the key is the Space bar.
36 /// - isRepeat: the event is the key repeating while held.
37 /// - modified: ⌘, ⌃ or ⌥ (or ⇧) is held. ⇧Space and the rest are
38 /// shortcuts of their own, never the bare Space this is.
39 /// - focus: what has the keyboard.
40 public static func action(
41 isSpace: Bool, isRepeat: Bool, modified: Bool, focus: KeyboardFocus
42 ) -> Action {
43 guard isSpace, !modified, focus == .none else { return .pass }
44 return isRepeat ? .swallow : .toggle
45 }
46}
47
48#if os(macOS)
49 import AppKit
50 import SwiftUI
51
52 extension SpaceToMute {
53 /// What has the keyboard, from AppKit's first responder. A SwiftUI
54 /// TextField edits through the window's field editor, an NSText; a
55 /// SwiftUI Button focused by Full Keyboard Access is a private proxy
56 /// view inside the hosting view, which is why anything unrecognised
57 /// is a control. The window, nothing, or the root view is nobody.
58 public static func focus(of responder: NSResponder?, contentView: NSView?) -> KeyboardFocus {
59 switch responder {
60 case nil: return .none
61 case is NSWindow: return .none
62 case let view as NSView where view === contentView: return .none
63 case is NSText: return .text
64 case let field as NSTextField where field.isEditable: return .text
65 default: return .control
66 }
67 }
68
69 /// The decision for a key event arriving in `window`.
70 @MainActor static func action(for event: NSEvent, in window: NSWindow) -> Action {
71 guard event.type == .keyDown else { return .pass }
72 let modifiers = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
73 .subtracting([.capsLock, .numericPad, .function])
74 return action(
75 isSpace: event.keyCode == keyCode, isRepeat: event.isARepeat, modified: !modifiers.isEmpty,
76 focus: focus(of: window.firstResponder, contentView: window.contentView))
77 }
78 }
79
80 extension View {
81 /// Space toggles `call`'s microphone while this view's window — or the
82 /// mini window standing in for it — is the key window. Apply it to the
83 /// call's own view.
84 func spaceToMute(_ call: Call) -> some View {
85 background(SpaceToMuteMonitor(call: call).frame(width: 0, height: 0).accessibilityHidden(true))
86 }
87 }
88
89 /// Holds a local key monitor for as long as the call's view is in a
90 /// window. Local monitors see every key event the app receives, so the
91 /// monitor checks which window the event is for before anything else.
92 private struct SpaceToMuteMonitor: NSViewRepresentable {
93 let call: Call
94
95 func makeNSView(context: Context) -> MonitorView { MonitorView() }
96 func updateNSView(_ view: MonitorView, context: Context) { view.call = call }
97
98 final class MonitorView: NSView {
99 weak var call: Call?
100 private var monitor: Any?
101
102 override func viewDidMoveToWindow() {
103 super.viewDidMoveToWindow()
104 if let monitor { NSEvent.removeMonitor(monitor) }
105 monitor = nil
106 guard window != nil else { return }
107 monitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
108 // Local monitors run on the main thread, with the event the app
109 // is about to dispatch there.
110 nonisolated(unsafe) let event = event
111 let consumed = MainActor.assumeIsolated { () -> Bool in
112 guard let self, let host = self.window, let call = self.call,
113 let target = event.window, target === host || target is MiniWindowPanel
114 else { return false }
115 switch SpaceToMute.action(for: event, in: target) {
116 case .pass: return false
117 case .swallow: return true
118 case .toggle:
119 call.mute()
120 return true
121 }
122 }
123 return consumed ? nil : event
124 }
125 }
126
127 deinit {
128 if let monitor { NSEvent.removeMonitor(monitor) }
129 }
130 }
131 }
132#endif
133