Files
SnipMC/Sources/KeyCaptureRepresentable.swift
T

55 lines
1.7 KiB
Swift

import AppKit
import Carbon.HIToolbox
import SwiftUI
/// Invisible NSView overlay that becomes first responder while recording
/// and reports the next key combo (key code + modifiers) it sees.
final class KeyCaptureView: NSView {
var onCapture: ((UInt32, UInt32) -> Void)?
var onCancel: (() -> Void)?
override var acceptsFirstResponder: Bool { true }
override func keyDown(with event: NSEvent) {
if Int(event.keyCode) == kVK_Escape {
onCancel?()
return
}
var modifiers: UInt32 = 0
if event.modifierFlags.contains(.control) { modifiers |= UInt32(controlKey) }
if event.modifierFlags.contains(.option) { modifiers |= UInt32(optionKey) }
if event.modifierFlags.contains(.shift) { modifiers |= UInt32(shiftKey) }
if event.modifierFlags.contains(.command) { modifiers |= UInt32(cmdKey) }
// Require at least one modifier so plain letters still work normally elsewhere.
guard modifiers != 0 else { return }
onCapture?(UInt32(event.keyCode), modifiers)
}
}
struct KeyCaptureRepresentable: NSViewRepresentable {
@Binding var isRecording: Bool
let onCapture: (UInt32, UInt32) -> Void
func makeNSView(context: Context) -> KeyCaptureView {
let view = KeyCaptureView()
view.onCapture = { keyCode, modifiers in
onCapture(keyCode, modifiers)
isRecording = false
}
view.onCancel = {
isRecording = false
}
return view
}
func updateNSView(_ nsView: KeyCaptureView, context: Context) {
if isRecording {
DispatchQueue.main.async {
nsView.window?.makeFirstResponder(nsView)
}
}
}
}