2019年1月9日水曜日

UIResponder.keyCommands を使って iPhone に接続された Bluetooth キーボードのイベントをハンドリングする

概要

iPhone に接続された Bluetooth キーボード (例えば MagicKeyboard2 など) のキータイプのイベントを取得したい場合に使えます

環境

  • macOS 10.14.2
  • Xcode Version 10.1 (10B61)

コード

全体は以下の通りです

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func becomeFirstResponder() -> Bool {
        return true
    }

    override var keyCommands: [UIKeyCommand]? {
        return [
            UIKeyCommand(input: "a", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: "A", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: "1", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: "-", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: "!", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: "\r", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: "\t", modifierFlags: [], action: #selector(selectKey(sender:))),
            UIKeyCommand(input: " ", modifierFlags: [], action: #selector(selectKey(sender:))),
        ]
    }

    @objc func selectKey(sender: UIKeyCommand) {
        print(sender.input ?? "no key")
    }
}

解説

まずキーボードのイベントを取得するために becomeFirstResponder を true に設定します
そして keyCommands で特定のキーボードが押されたときの挙動を定義します
サンプルでは英数字や記号を定義しています
タブやエンターもエスケープシーケンスを使うことで対応できます
エンターは \n ではなく \r で拾えるようです

あとは action で各キーが押されたときにコールされる関数を定義しまう
サンプルではすべて selectKey が呼ばれるようにしていますが関数は分けても大丈夫です

#selector の指定が Swift4 に対応していない古い呼び出し方になっているのでこの辺りは最新の Selector の指定方法に変更してください

最後に

Bluetooth で接続されたキーボードのイベントを取得する方法を紹介しました
iPhone の場合 Bluetooth でいろいろなデバイスと接続することができます
念の為説明しておきますがここで言う Bluetooth は Classic Bluetooth になります
Bluetooth Low Enagy ではないのでご注意ください (BLE の操作は CoreBluetooth を使います)

例えば Bluetooth スピーカーなどに付いているボタンのイベントなども UIResponder を使えば拾うことができます

少し不明だったのは MFI (Made for iPhone) デバイスの対応です
MFI デバイスには専用の API があるっぽかったのでその場合は UIResponder では厳しいかもしれません

参考サイト

0 件のコメント:

コメントを投稿