ブラウザの WebHID を p5.js Web Editor上で利用する：デバイスは DualShock 4

## はじめに
以前も試して記事を書いたり、試した内容を X・YouTube に投稿していた「DualShock 4 をブラウザの API で扱う」という話です。

それを、自分がよく使っている環境の「p5.js Web Editor」で行います。

### デモ動画
先に、動作している時の様子を掲載します。
内容はとりあえずのお試しで、シンプルなボタン押下の取得と、ボタン押下時の画面描画の変更です。

https://x.com/youtoy/status/1808154911026434369

上記では、ボタン押下時に p5.js のキャンバスの色が変わっているのが確認できるかと思います。

## WebHID で DualShock 4 を扱う（p5.js Web Editor上で実装）
それでは、環境として p5.js Web Editor を用いて、DualShock 4 を扱う WebHID を使ったプログラムを実装してみます。

WebHID で行う内容は、シンプルに「デバイスとの接続」と「Button 0 の押下」に絞って試しています。以下が実装した内容です。

```javascript
function setup() {
  createCanvas(600, 500);
  background(220);
}

function draw() {}

function mouseClicked() {
  interactWithDevice();
}

async function interactWithDevice() {
  const requestParams = {
    filters: [{ vendorId: 0x054c }],
  };

  try {
    const devices = await navigator.hid.requestDevice(requestParams);
    if (devices.length === 0) {
      console.log("デバイスが選択されませんでした");
      return;
    }

    const device = devices[0];
    await device.open();
    console.log("Opened device: " + device.productName);

    device.addEventListener("inputreport", (event) => {
      const { data } = event;

      const temp = new Uint8Array(data.buffer);

      const button0Pressed = (temp[4] >> 5) & 1;
      if (button0Pressed) {
        background(100, 120, 220);
        // console.log("Button 0 pressed");
      } else {
        background(220);
        // console.log("Button 0 not pressed");
      }
    });
  } catch (error) {
    console.error("An error occurred:", error);
  }
}
```

デバイスを利用するにあたり、ユーザーのアクションをトリガーにした処理が必要になるようだったので、以下を処理に含めています。

```javascript
function mouseClicked() {
  interactWithDevice();
}
```

また、その際に filters に特定の vendorId を指定し（※ `vendorId: 0x054c` の部分）、ユーザーに選択肢として提示するデバイスのリストを絞りこむようにしています。

そして以下の部分で、ボタン0 の状態を示している部分を読み取っています。

```javascript
      const temp = new Uint8Array(data.buffer);

      const button0Pressed = (temp[4] >> 5) & 1;
      if (button0Pressed) {
        background(100, 120, 220);
      } else {
        background(220);
      }
```

それに関し、データフォーマットは Webを検索すると、以下などのサイトで確認できます。

●DS4-USB - PS4 Developer wiki
　https://www.psdevwiki.com/ps4/DS4-USB

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/324a2cf5-e7b1-a82d-2c2d-ead33b87ec83.png)

## おわりに
今回、WebHID を使って DualShock 4 との接続・ボタン押下の状態の取得を行ってみました。

ボタン押下であれば、同様のことを Gamepad API で行えて、そちらのほうが分かりやすかったりします。WebHID を用いる場合は、可能であれば直接使うのではなくライブラリ等を用いるほうが良いかもしれません。
※ 上で書いていたデータフォーマットを考慮した処理を、ライブラリが請け負ってくれるため

### 余談： 過去に試したゲームコントローラーを使う内容の一部
ゲームコントローラーをブラウザで使う場合、「Gamepad API」か「WebHID API」のいずれかを使った方法が主なものとして挙げられます。
それらに関する内容で、以前記事を書いたり、試作をしてみたりした内容（X・YouTube に動画を投稿していたもの）を、一部ですが以下で紹介してみます。

#### 記事
以下は、過去に記事にしたものの一部です。

- Gamepad API（※ API を直接利用／ライブラリを利用）
   - [Chrome 126 であらためて Gamepad API での振動を試す（関連情報を見てみたり開発者ツールのコンソールで簡易に試したり） - Qiita](https://qiita.com/youtoy/items/529d776b6a27a7344840)
   - [p5.js Web Editor上の処理で DualShock 4 の振動を扱う（Gamepad API を利用） - Qiita](https://qiita.com/youtoy/items/5c8376b634a850b9b996)
   - [p5.js Web Editor上で Gamepad API を使う： DualShock 4 を使ったシンプルな接続確認・ボタン押下判定 - Qiita](https://qiita.com/youtoy/items/997e5720de790e36b98b)
   - [【完走賞ゲット-10】gamecontroller.js を使って DualShock 4 を JavaScript で扱う - Qiita](https://qiita.com/youtoy/items/87c1c37b51ae9ef4ab4d)
- WebHID API
   - [【完走賞ゲット-6】「WebHID DualShock 4 Demo」というサイトを軽く試してみる - Qiita](https://qiita.com/youtoy/items/468454fe968ff3632511)
   - [【小ネタ】ブラウザで PS4用コントローラー「DUALSHOCK 4」を扱う下準備： WebHID API と WebHID-DS4 - Qiita](https://qiita.com/youtoy/items/deabcc7a126186933092)
- Gamepad API と WebHID API
   - [Joy-Con などをブラウザで使える API 2つの情報をまとめて見てみる： Gamepad API と WebHID API - Qiita](https://qiita.com/youtoy/items/109d1564ee2ff4bd463f)

#### DualShock 4 を使った試作の動画
以下は動画です。

<iframe width="560" height="315" src="https://www.youtube.com/embed/zf-ZcdxYhOA?si=fJkbvXFTFUwjzQGk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<iframe width="560" height="315" src="https://www.youtube.com/embed/RurUw4GiHiE?si=QdszVVSZOeVy-mrE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

これらはコントローラーの傾きを取得していますが、それを行うには Gamepad API ではダメで WebHID を使う必要があります。[DualShock 4 の場合、WebHID のラッパーのライブラリがある](https://github.com/TheBITLINK/WebHID-DS4)ので、それを用いると良いです。

#### DualShock 4 以外のデバイスと WebHID との組み合わせ
DualShock 4 以外のデバイスと WebHID の組み合わせも、試したものがあったりもします。

<iframe width="560" height="315" src="https://www.youtube.com/embed/jNVB8PA1VDU?si=B-N7u6VtOEzsFUPq" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

これも Gamepad API ではなく WebHID を使う必要がるものです。
[Joy-Con の場合も、WebHID のラッパーのライブラリがある](https://github.com/tomayac/joy-con-webhid)ので、それを用いると良いです。