7

I’m new to iOS development. Following a tutorial I have created a simple calculator using SwiftUI.

I have a keyboard attached to my iPad, and I would like to be able to enter values using the keyboard.

How can I capture and handle hardware keyboard events in a SwiftUI app (with no text field) ?  I have tried to use the keyCommands on the SceneDelegate (UIResponder) as shown here, but that doesn’t work for me. As soon as I press any key on my iPad, I get “Connection to deamon was invalidated” in the XCode trace view.

 class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    override var canBecomeFirstResponder: Bool {
        return true;
    }
    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "a", modifierFlags: [], action: #selector(test)),
            UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
        ]
    }

    @objc func test(_ sender: UIKeyCommand) {
        print("test was pressed")
    }

Thanks

4

2 回答 2

8

它需要覆盖托管视图控制器,并且一切正常。使用 Xcode 11.2 / iOS 13.2 测试

这是示例代码

class KeyTestController<Content>: UIHostingController<Content> where Content: View {

    override func becomeFirstResponder() -> Bool {
        true
    }

    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "1", modifierFlags: [], action: #selector(test)),
            UIKeyCommand(input: "0", modifierFlags: [], action: #selector(test)),
            UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
        ]
    }

    @objc func test(_ sender: UIKeyCommand) {
        print(">>> test was pressed")
    }

}

SceneDelegate下面的某个地方

window.rootViewController = KeyTestController(rootView: contentView)
于 2020-01-18T06:40:49.260 回答
1

如果您使用的是 SwiftUI 生命周期,@Asperi 还会rootViewController在这篇文章中展示如何访问 -使用 iOS 14 时的托管控制器 @main

总之,HostingWindowFinder跟踪可变版本rootViewController并提供对它的访问。

struct ContentView: View {

    var body: some View {
      Text("Demo Root Controller access")
        .withHostingWindow { window in
            window?.rootViewController = KeyController(rootView: ContentView())
        }
    }
}

extension View {
    func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View {
        self.background(HostingWindowFinder(callback: callback))
    }
}

struct HostingWindowFinder: UIViewRepresentable {
    var callback: (UIWindow?) -> ()

    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        DispatchQueue.main.async { [weak view] in
            self.callback(view?.window)
        }
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
    }
}

如果您只想监控原始键盘输入的使用pressesBegan(...)- WWDC 2019 Talk

class KeyController<Content>: UIHostingController<Content> where Content: View {

    override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        for press in presses {
            guard let key = press.key else { continue }
            print(key)
        }
    }
}

非常感谢@Asperi!❤️

于 2021-11-06T02:57:08.130 回答