APL ボタン クリック時イベント

# 本記事のゴール
ボタンを押したら発話する

# 前提
[APL 画像表示](https://qiita.com/Teach/items/0ed966181009b96dc7b1)

APL v1.7

# やること
[TouchWrapper](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-touchwrapper.html)を使用してタッチイベントを発火する。

#### TouchWrapperとは
子要素がタッチされたときに `onPress` のコマンドを送信するコンポーネント

## ボタンを配置
![スクリーンショット 2021-08-01 12.14.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/b3093153-8fcc-509c-cfae-86fbfee20ae4.png)

素材はこれ
![StartButton](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/bad9d928-77b7-c399-c316-49eb6329cda9.png)

![スクリーンショット 2021-08-01 12.15.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/beefdb5e-61dc-f48d-b61b-a82d446d0ed0.png)


```.json
        "items": [
            {
                "items": [
                    {
                        "type": "TouchWrapper",
                        "items": [
                            {
                                "source": "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/bad9d928-77b7-c399-c316-49eb6329cda9.png",
                                "type": "Image",
                                "width": "241",
                                "height": "65"
                            }
                        ]
                    }
                ],
                "alignItems": "center",
                "justifyContent": "center",
                "type": "Container"
            }
        ]
```

## ボタンタッチを検知してサーバーに送信


[SendEvent](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-standard-commands.html#sendevent-command)

onPress されたら SendEventコマンドを実行することにより、サーバーにボタンがタッチされたことを通知する。

書き方はサンプルが非常に参考になる。

```.json
{
  "type": "TouchWrapper",
  "id": "idForTheTouchWrapper",
...
  "onPress": [
    {
      "type": "SendEvent",
      "arguments": [
        "textWasPressed",
        "このデータをスキルに送信する"
      ],
      "components": [
        "idForTheTextComponent"
      ]
    }
  ],
...
}
```

argumentsに関してはボタンを検知するだけなら不要なので書かない。(デフォルト[])
componentsもとりあえず不要。
また、サーバーにどのボタンが押されたのかを伝えるために TouchWrapper に固有のIDをつける。

![スクリーンショット 2021-08-22 23.30.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/8caa537b-6490-c163-249d-4d14410048d3.png)

```.json
                        "type": "TouchWrapper",
                        "id": "startButton",
                        "onPress": [
                            {
                                "type": "SendEvent"
                            }
                        ]
```

onPressの部分はAPLの部分に直書きする。(長いから)

## Handlerを書く

[Alexaから送信されたリクエストを処理する](https://developer.amazon.com/ja-JP/docs/alexa/custom-skills/handle-requests-sent-by-alexa.html)
にhandlerの書き方が書かれている。

```.js

// (1)
const isButtonPress = (requestEnvelope, componentId) => {
    const source = requestEnvelope.request.source
    return Alexa.getRequestType(requestEnvelope) === 'Alexa.Presentation.APL.UserEvent'
        && source.handler === 'Press'
        && source.id === componentId;
};

// (2)
const StartButtonHandler = {
    canHandle(handlerInput) { // (2.1)
        return isButtonPress(handlerInput.requestEnvelope, 'startButton');
    },
    handle(handlerInput) { // (2.2)
        const speakOutput = 'ボタンが押されました';
        return handlerInput.responseBuilder
            .speak(speakOutput)
            .getResponse();
    }
}
...

// (3)
exports.handler = Alexa.SkillBuilders.custom()
    .addRequestHandlers(
        LaunchRequestHandler,
        HelloWorldIntentHandler,
        StartButtonHandler,
...
```

(2) Handlerの書き方の構造は、第一引数(2.1)に「実行するかどうか」、第二引数(2.2)に「実行する処理」を書く。
今回の「実行するかどうか」は「idがstartButtonのTouchWrapperからSendEventが送られてきたら」である。
では、どのようにデータが送られてくるのか。
SendEventのドキュメントには以下のように書かれている

> スキルにAlexa.Presentation.APL.UserEventリクエストを送信します

[UserEventリクエスト](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/apl-interface.html#userevent-request)

[UserEventリクエストを処理する](https://developer.amazon.com/ja-JP/docs/alexa/alexa-presentation-language/use-apl-with-ask-sdk.html#handle-a-userevent-request)

このあたりにやり方が書いてある。

で、実際にくるデータは以下のような感じ

```.json

    "event": {
        "header": {
            "namespace": "Alexa.Presentation.APL",
            "name": "UserEvent",
            "messageId": "messageId",
            "dialogRequestId": "b63a281e-36f3-47c1-bf27-3140e53ff84b"
        },
        "payload": {
            "presentationToken": "amzn1.as-tt.v1.ThirdPartySdkSpeechlet#TID#amzn1.ask.skill.ce32fc86-b796-4238-9496-537069c1ccec::",
            "arguments": [],
            "source": {
                "type": "TouchWrapper",
                "handler": "Press",
                "id": "startButton"
            },
            "components": {},
            "dialogRequestId": "b63a281e-36f3-47c1-bf27-3140e53ff84b"
        }
    },
    "context": [
...
}
```

`handlerInput.requestEnvelope.request`で上記リクエストの`payload`がとってこれる。
あとは`source.handler`でタッチイベントかどうか、`source.id`で何がタッチされたのかどうかを判断している。(1)

(3) HandlerはaddRequestHandlersに登録する必要があるため、これを忘れないようにする。

他ドキュメント
[Processing-Request](https://ask-sdk-for-nodejs.readthedocs.io/ja/latest/Processing-Request.html)
[getRequestType](https://ask-sdk-for-nodejs.readthedocs.io/ja/latest/ASK-SDK-Utilities.html?highlight=getRequestType#available-methods)


# 参考
https://qiita.com/Mount/items/6593efb1f4fc71f479a2