Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2020 SwiftUI & UI FrameworksSystem Services

WWDC20 · 12 min · SwiftUI & UI Frameworks / System Services

Support hardware keyboards in your app

When people use hardware keyboards with your app, they’re not only getting a more tactile and familiar typing experience — they can quickly navigate or use keyboard shortcuts, too. Discover how you can best support hardware keyboards for your iPadOS and Mac Catalyst apps: We’ll demystify the responder chain and show you best practices for implementing custom keyboard shortcuts. Learn how easy it is to get up and running with common system keyboard shortcuts, use modifier flags with gesture recognizers, and leverage the raw keyboard event API to respond to key down and key up events.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 8 snippets

PlayerViewController swift · at 0:01 ↗
class PlayerViewController: UIViewController {

    override var canBecomeFirstResponder: Bool {
        return true 
    }

    override func viewDidAppear(_ animated: Bool) {
        becomeFirstResponder()
    }

    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(title: NSLocalizedString("PLAY_PAUSE", comment: "…"),
                        action: #selector(playPause),
                         input: " ")
        ]
    }
}
SongListTableViewController swift · at 0:02 ↗
class SongListTableViewController: UITableViewController {

    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    override func viewDidAppear(_ animated: Bool) {
        becomeFirstResponder()
    }
    
    /* UIResponderStandardEditActions */

    override func selectAll(_ sender: Any?) {  }

    override func copy(_ sender: Any?) {  }

    override func paste(_ sender: Any?) {  }

}
UIKeyCommand swift · at 0:03 ↗
class UIKeyCommand : UICommand {
    ...
}

override func buildMenu(with builder: UIMenuBuilder) {
    builder.replaceChildren(ofMenu: .file) { children in
        return [ UIKeyCommand() ] + children
    }
}
Extending selection with keyboard swift · at 0:04 ↗
optional func tableView(_ tableView: UITableView,
       shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool

optional func tableView(_ tableView: UITableView,
       didBeginMultipleSelectionInteractionAt indexPath: IndexPath)
recognizedDragGesture swift · at 0:05 ↗
func recognizedDragGesture(_ panGesture: UIPanGestureRecognizer) {

    if panGesture.modifierFlags.contains(.command) {
        snapToGrid = true
    } else if panGesture.modifierFlags.contains(.shift) {
        constrainAspectRatio = true
    }
    
    ...
}
Responding to raw keyboard events swift · at 0:06 ↗
class UIResponder: NSObject {
    func pressesBegan(_ presses: Set<UIPress>,
                     with event: UIPressesEvent)
    
    func pressesEnded(_ presses: Set<UIPress>,
                     with event: UIPressesEvent)
}
CanvasViewController swift · at 0:07 ↗
class CanvasViewController: UIViewController {
     
     override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
         for press in presses {
             guard let key = press.key else { continue }
             switch key.keyCode {
             case .keyboardUpArrow: startMoveUp()
             case .keyboardDownArrow: startMoveDown()
                 
             }
     }
     }

     override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
         stopMoving()
     }

}
CanvasViewController modifier flags swift · at 0:08 ↗
class CanvasViewController: UIViewController {

    override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
        var selectWhileMoving = false
        for press in presses {
            guard let key = press.key else { continue }
            if key.modifierFlags.contains(.shift) {
                selectWhileMoving = true
            }
                
            switch key.keyCode {
            case .keyboardUpArrow: startMoveUp()
                    
            }
        }
    }
}

Resources