8

I’m having trouble using an arrow key as a .keyboardShortcut in SwiftUI. Sample iOS app:

struct ContentView: View {
    @State var time: Date = Date()
    
    var body: some View {
        VStack {
            Button("Press Me") {
                time = Date()
            }
            .keyboardShortcut(KeyEquivalent.rightArrow, modifiers: [])
        
            Text("\(time)")
        }
    }
}

This puts up a button that, when pressed, changes the time displayed in the text. I should be able to use the right arrow key on the keyboard and get it to work as well, but it doesn’t. If I change the keyboardShortcut line to, say, this:

.keyboardShortcut(KeyEquivalent(“a”), modifiers: [])

everything works as expected. You can press the “a” key and the time changes. If you hold down the command key, you get the system-provided HUD that shows the “a" shortcut. Change it to .rightAarrow and it shows the HUD but there’s an enclosed “?” for the shortcut, and the shortcut doesn’t fire when the arrow key is pressed.

(I’m aware I could do this using UIKit. Trying to understand why the SwiftUI version doesn’t work.)

davextreme
  • 995
  • 9
  • 23

2 Answers2

6

I am attempting to accomplish the same objective in my MacOS SwiftUI app. Using your code as an example, I inserted the .keyboardShortcut(KeyEquivalent.rightArrow, modifiers: []) after my Button{} and it works fine. I then pasted your entire code into my ContentView and again it works fine. I do not know why it works in my MacOS app but not in your iOS app.

KeithB
  • 417
  • 2
  • 12
2

Copying my answer from this post. I wasn't able to use SwiftUI's commands to get this to work on iOS/iPadOS. However I found some luck using view controllers, and if you're using SwiftUI views then this will work with a hosting controller.

In your view controller, add the code below. The important bit is setting wantsPriorityOverSystemBehavior to true:

override var keyCommands: [UIKeyCommand]? {
    let upArrow = UIKeyCommand(input: UIKeyCommand.inputUpArrow, modifierFlags: [], action: #selector(test))
    upArrow.wantsPriorityOverSystemBehavior = true

    return [upArrow]
}

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