import AppKit final class PttKeyCaptureSheet: NSViewController { var onComplete: ((UInt16?) -> Void)? private let currentKeyCode: UInt16 private var capturedKeyCode: UInt16? private let instructionLabel = NSTextField(labelWithString: "Press the key you want to use for push-to-talk…") private let captureView = KeyCaptureView() init(currentKeyCode: UInt16) { self.currentKeyCode = currentKeyCode super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError() } override func loadView() { view = NSView(frame: NSRect(x: 0, y: 0, width: 320, height: 140)) } override func viewDidLoad() { super.viewDidLoad() buildUI() } private func buildUI() { let titleLabel = NSTextField(labelWithString: "Set Push-to-Talk Key") titleLabel.font = .boldSystemFont(ofSize: 13) instructionLabel.textColor = .secondaryLabelColor instructionLabel.lineBreakMode = .byWordWrapping instructionLabel.setAccessibilityLabel("Waiting for key press") captureView.setAccessibilityLabel("Key capture area — press any key") captureView.setAccessibilityRole(.textArea) captureView.onKeyPressed = { [weak self] keyCode in self?.capturedKeyCode = keyCode self?.instructionLabel.stringValue = "Key captured: \(keyCodeName(keyCode)). Click Set to confirm." } let cancelButton = NSButton(title: "Cancel", target: self, action: #selector(cancelClicked)) cancelButton.bezelStyle = .rounded let setButton = NSButton(title: "Set", target: self, action: #selector(setClicked)) setButton.bezelStyle = .rounded; setButton.keyEquivalent = "\r" setButton.setAccessibilityLabel("Set captured key as PTT key") let buttonRow = NSStackView(views: [NSView(), cancelButton, setButton]) buttonRow.orientation = .horizontal; buttonRow.spacing = 8 captureView.translatesAutoresizingMaskIntoConstraints = false captureView.wantsLayer = true captureView.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor captureView.layer?.cornerRadius = 4 let stack = NSStackView(views: [titleLabel, instructionLabel, captureView, buttonRow]) stack.orientation = .vertical; stack.spacing = 10 stack.edgeInsets = NSEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) stack.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stack) NSLayoutConstraint.activate([ stack.topAnchor.constraint(equalTo: view.topAnchor), stack.leadingAnchor.constraint(equalTo: view.leadingAnchor), stack.trailingAnchor.constraint(equalTo: view.trailingAnchor), stack.bottomAnchor.constraint(equalTo: view.bottomAnchor), captureView.heightAnchor.constraint(equalToConstant: 28), ]) } override func viewDidAppear() { super.viewDidAppear() view.window?.makeFirstResponder(captureView) } @objc private func setClicked() { let key = capturedKeyCode dismiss(nil) onComplete?(key) } @objc private func cancelClicked() { dismiss(nil) onComplete?(nil) } } // MARK: - Key capture view private final class KeyCaptureView: NSView { var onKeyPressed: ((UInt16) -> Void)? override var acceptsFirstResponder: Bool { true } override func keyDown(with event: NSEvent) { onKeyPressed?(event.keyCode) } override func drawFocusRingMask() { NSBezierPath(roundedRect: bounds, xRadius: 4, yRadius: 4).fill() } override var focusRingMaskBounds: NSRect { bounds } } private func keyCodeName(_ keyCode: UInt16) -> String { let map: [UInt16: String] = [ 0x60: "F5", 0x61: "F6", 0x62: "F7", 0x63: "F3", 0x64: "F8", 0x65: "F9", 0x67: "F11", 0x69: "F13", 0x6A: "F16", 0x6B: "F14", 0x6D: "F10", 0x6F: "F12", 0x71: "F15", 0x72: "Help", 0x73: "Home", 0x74: "PgUp", 0x75: "Del", 0x76: "F4", 0x77: "End", 0x78: "F2", 0x79: "PgDn", 0x7A: "F1", ] return map[keyCode] ?? "Key\(keyCode)" }