[Alexa]APL1.2 の キーボード連携を試す

# やったこと
APLバージョン1.2でキーボード対応できるようになったらしいので、
Amazon公式のリファレンスを参考にして試してみました。
[キーボード(Amazon公式リファレンス)](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-keyboard.html)

# 本記事の注意点
この記事ではNode.js部分のソースは載せないので、ある程度Alexaスキル開発 & APLを使った画面描写を
理解している方でないと難しめの内容かもしれません。ご了承ください。

# Amazon Echoとキーボードの接続
そもそもAmazon Echoとキーボードの接続ってどうやってやるんだ、という話なのですが、
Amazon EchoのBluetooth設定でBluetoothキーボードを連携すればOKでした。

ちなみに、接続したキーボードはEcho上のブラウザでの検索等でも普通に使用することができます。

# APLの記載
キーボード連携はAPLの機能なので、適当にAPLを描写するスキルを作成してAPLのテンプレート部に
いろいろ記入して試してみました。
最終的に動いたもののAPLテンプレートJSONを以下に掲載しておきます。
※Node.js部分の記載は省略。APLデータ部も省略(APLデータ参照していないので、適当でOKです)。

こちらの例では、Bluetoothキーボードを接続した状態でスキルを呼び出すと、画面表示後、
キーボードで"A"または"S"を押下することで画面上のアイテムを動かすことができます。

``` AplTemplate.json
{
    "type": "APL",
    "version": "1.2",
    "settings": {},
    "theme": "dark",
    "import": [],
    "resources": [],
    "styles": {},
    "onMount": [],
    "graphics": {},
    "commands": {},
    "layouts": {},
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": [
            {
                "type": "Container",
                "alignItems": "center",
                "justifyContent": "center",
                "onMount":[
                    {
                        "type":"SetFocus",
                        "componentId": "keyWrapper"
                    }
                ],
                "items": [
                    {
                        "type": "TouchWrapper",
                        "id":"keyWrapper",
                        "handleKeyDown": [
                            {
                                "when": "${event.keyboard.code == 'KeyA'}",
                                "commands": [
                                    {
                                        "type": "SetValue",
                                        "property": "transform",
                                        "value": [
                                            {
                                                "translateX": "-100"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "when": "${event.keyboard.code == 'KeyS'}",
                                "commands": [
                                    {
                                        "type": "SetValue",
                                        "property": "transform",
                                        "value": [
                                            {
                                                "translateX": "100"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ],
                        "handleKeyUp": [
                            {
                                "when": "${event.keyboard.code == 'KeyA'}",
                                "commands": [
                                    {
                                        "type": "SetValue",
                                        "property": "transform",
                                        "value": [
                                            {
                                                "translateX": "0"
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "when": "${event.keyboard.code == 'KeyS'}",
                                "commands": [
                                    {
                                        "type": "SetValue",
                                        "property": "transform",
                                        "value": [
                                            {
                                                "translateX": "0"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ],
                        "items": [
                            {
                                "type": "Frame",
                                "paddingLeft": "20dp",
                                "paddingTop": "20dp",
                                "paddingRight": "20dp",
                                "paddingBottom": "20dp",
                                "backgroundColor": "#cc2211",
                                "item": [
                                    {
                                        "type": "Text",
                                        "width": "50dp",
                                        "fontSize": "80dp",
                                        "text": "A"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
}
```


## はまったポイント
キーボード連携を実現するにあたり、以下ではまりました。

### 対象コンポーネントにフォーカスをあてる必要あり
キーボード操作のイベントは、操作の時点でフォーカスがあるコンポーネントに渡されるとのことです。
そのため、事前にフォーカスを合わておく必要があります。
そこで、今回の例ではコンテナのonMountで対象のコンポーネントにフォーカスを合わせるようにしています。

なお、onMountではなく、コンポーネントを直接タッチすることでもフォーカスを合わせることができます。

### シミュレータと実機で挙動が異なる
開発者コンソールのシミュレータでも、画面にフォーカスを合わせることでキーボード操作が可能ですが、
シミュレータと実機でAPL標準コマンドに対する挙動が異なっていました(実機 = Echo Show5で確認)。
具体的には上記のJSONでいうと"handleKeyUp"がシミュレータでは反応しましたが実機では反応しませんでした。

私はまだあまり深いところまで検証できていませんが、公開を目指すのであれば実機でのテストは不可欠でしょう。

# 自作Bluetoothキーボードと連携すれば便利！？
コントローラーを使って操作するゲームや早押しクイズなどが作れるかも、と思いました。
キーの数を減らした自作Bluetoothキーボードを作れば、使い勝手がよさそうです。

音声でのやり取りとキーボード操作をバランス良く活用すれば、
スマートスピーカーでしか実現できないようなユーザー体験を提供できるかもしれません。