More than 1 year has passed since last update.

【完走賞ゲット-10】gamecontroller.js を使って DualShock 4 を JavaScript で扱う

Last updated at Posted at 2022-12-09


こちらは、完走賞ゲットのため小ネタを毎日投稿しようとチャレンジする Advent Calendar 2022 の 10日目の記事です。

12月に試していくつか記事を書いてみたりもした「WebHID」関連の調べものをしていて、そこからたどり着いた Gamepad API関連のライブラリ「gamecontroller.js」に関する話です。

これを、以下の記事でも扱っていた「DualShock 4」で試します。

●【完走賞ゲット-6】「WebHID DualShock 4 Demo」というサイトを軽く試してみる - Qiita

gamecontroller.js を試す

DualShock 4 を PC と USB接続して試していきます。


まずは、Node.js版を試します。インストールは、 npm i gamecontroller.js で。


●gamecontroller.js/example-3-buttons-and-joysticks.html at master · alvaromontoro/gamecontroller.js · GitHub

これは、Node.js を使わないやり方のほうが楽なのでは?、と思い、これはスキップして次に進むことにしました。

HTMLファイルで CDN のファイルを読み込んで使う



●gamecontroller.js/example-3-buttons-and-joysticks.html at master · alvaromontoro/gamecontroller.js · GitHub

(CSS の読み込みをコメントアウトして、gamecontroller.js を CDN から読み込むようにしました)

<!DOCTYPE html>
<html lang="en">
    <title>GameControl Example: Buttons and Joysticks</title>
    <!-- <link rel="stylesheet" href="./examples.css" /> -->
      svg {
        display: block;
        margin: 1rem auto;
        max-width: 500px;
        width: 100%;
      .active {
        fill: yellow;
      path.active {
        fill: red;
    <script src="https://cdn.jsdelivr.net/npm/gamecontroller.js@1.5.0/dist/gamecontroller.min.js"></script>
      <h1>Example: Buttons and Joysticks</h1>
        Connect a gamepad to the computer, and click the buttons or move the different
        joysticks/axes. They will highlight as they are pressed.
      <svg viewBox="0 0 600 300">
        <g fill="#ddd" stroke="#222" stroke-width="3">
          <rect x="150" y="10" width="100" height="100" rx="5" ry="5" id="button-6" />
          <rect x="350" y="10" width="100" height="100" rx="5" ry="5" id="button-7" />
          <rect x="100" y="25" width="100" height="40" rx="5" ry="5" id="button-4" />
          <rect x="400" y="25" width="100" height="40" rx="5" ry="5" id="button-5" />
            d="M135,50 C 45,50 20,180 20,240 20,300 80,330 175,220 175,220 
          425,220 425,220 520,330 580,300 580,240 580,180 555,50 465,50 Z"
          <circle cx="200" cy="200" r="35" />
          <circle cx="400" cy="200" r="35" />
          <circle cx="200" cy="200" r="15" id="button-10" />
          <circle cx="400" cy="200" r="15" id="button-11" />
          <path d="M190,182 210,182 200,168 Z" stroke-width="0" id="axe-0-up" />
          <path d="M190,218 210,218 200,232 Z" stroke-width="0" id="axe-0-down" />
          <path d="M218,190 218,210 232,200 Z" stroke-width="0" id="axe-0-right" />
          <path d="M182,190 182,210 168,200 Z" stroke-width="0" id="axe-0-left" />
          <path d="M390,182 410,182 400,168 Z" stroke-width="0" id="axe-1-up" />
          <path d="M390,218 410,218 400,232 Z" stroke-width="0" id="axe-1-down" />
          <path d="M418,190 418,210 432,200 Z" stroke-width="0" id="axe-1-right" />
          <path d="M382,190 382,210 368,200 Z" stroke-width="0" id="axe-1-left" />

          <circle cx="480" cy="160" r="15" id="button-0" />
          <circle cx="510" cy="130" r="15" id="button-1" />
          <circle cx="450" cy="130" r="15" id="button-2" />
          <circle cx="480" cy="100" r="15" id="button-3" />

          <rect x="105" y="85" width="30" height="90" fill="#aaa" stroke="#aaa" />
          <rect x="75" y="115" width="90" height="30" fill="#aaa" stroke="#aaa" />

          <rect x="245" y="145" width="50" height="18" rx="9" ry="9" id="button-8" />
          <rect x="305" y="145" width="50" height="18" rx="9" ry="9" id="button-9" />

          <circle cx="120" cy="160" r="15" id="button-13" />
          <circle cx="90" cy="130" r="15" id="button-14" />
          <circle cx="150" cy="130" r="15" id="button-15" />
          <circle cx="120" cy="100" r="15" id="button-12" />

          <circle cx="300" cy="90" r="20" id="button-16" />
          <text x="480" y="160">0</text>
          <text x="510" y="130">1</text>
          <text x="450" y="130">2</text>
          <text x="480" y="100">3</text>
          <text x="150" y="40">4</text>
          <text x="450" y="40">5</text>
          <text x="225" y="30">6</text>
          <text x="375" y="30">7</text>
          <text x="270" y="156">8</text>
          <text x="330" y="156">9</text>
          <text x="200" y="200">10</text>
          <text x="400" y="200">11</text>
          <text x="120" y="100">12</text>
          <text x="120" y="160">13</text>
          <text x="90" y="130">14</text>
          <text x="150" y="130">15</text>
          <text x="300" y="90">16</text>
          <text x="270" y="175" font-size="10">SELECT</text>
          <text x="330" y="175" font-size="10">START</text>

      <p class="note">
        This is a 17-button
        <a href="https://w3c.github.io/gamepad/#remapping"
          >standard gamepad layout as defined on the W3C Gamepad API definition</a
        >. <strong>It may not match the gamepad that is connected</strong>, but it can be used to
        see how the buttons/joysticks in that gamepad match the buttons in the standard gamepad.

      <h2>How it works</h2>
      <p>Event handlers can be associated to the buttons using the <code>.on()</code> method:</p>
      <p class="code"><code>gamepad.on(DIRECTION_NAME+AXE_ID, CALLBACK);</code></p>
        Only one action is allowed by button/joystick/axe. If you use several
        <code>.on()</code> with the same direction, the latest call to it will be the one that is
        applied when the joystick is pressed.
      <pre class="code"><code>gameControl.on('connect', function(gamepad) {
  gamepad.on('select', function() {
    // do something
        Some buttons/directions have aliases, so it is easier to associate events to them. For
        example, if we only use the name of the direction ("up", "dowm", "right", or "left"), the
        event handler will be associated to that direction in the first joystick/axe:
      <pre class="code"><code>gamepad.on('up0', function() {
  // do something

gamepad.on('up', function() {
  // do something
      <p class="note">
        Using aliases doesn't mean that you will be able to use more than one action per direction,
        as they are the same.
        The available direction aliases are:
        <li><code>up</code>: equivalent to <code>up0</code>.</li>
        <li><code>down</code>: equivalent to <code>down0</code>.</li>
        <li><code>right</code>: equivalent to <code>right0</code>.</li>
        <li><code>left</code>: equivalent to <code>left0</code>.</li>
        The available button aliases are:
        <li><code>l1</code>: equivalent to <code>button4</code>. Left back button 1</li>
        <li><code>l2</code>: equivalent to <code>button6</code>. Left back button 2</li>
        <li><code>r1</code>: equivalent to <code>button5</code>. Right back button 1</li>
        <li><code>r2</code>: equivalent to <code>button7</code>. Right back button 2</li>
          <code>select</code>: equivalent to <code>button8</code>. (Works for <kbd>Select</kbd>/<kbd
          in some gamepads)
          <code>start</code>: equivalent to <code>button9</code>. (Works for <kbd>Start</kbd>/<kbd
          in some gamepads)
          <code>power</code>: equivalent to <code>button16</code>. It is the power button available
          on some gamepads (e.g. the XBox logo button)
    <script src="../dist/gamecontroller.min.js"></script>
        .on('connect', function(gp) {
          for (let x = 0; x < Math.min(17, gp.buttons); x++) {
            gp.on('button' + x, function() {
              document.querySelector('#button-' + x).classList.toggle('active', true);
          for (let x = 0; x < Math.min(2, gp.axes); x++) {
            const directions = ['up', 'down', 'right', 'left'];
            for (let d = 0; d < directions.length; d++) {
              gp.on(directions[d] + x, function() {
                  .querySelector('#axe-' + x + '-' + directions[d])
                  .classList.toggle('active', true);
        .on('beforeCycle', function() {
          const active = document.querySelectorAll('.active');
          for (let x = 0; x < active.length; x++) {
            active[x].classList.toggle('active', false);

この HTMLファイルをブラウザで開き、DualShock 4 のキーを押してみます。




以下、Gamepad API関連のことをやるのに、便利そうなのでメモ。


Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up