みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Nintendo Switch ProコントローラーをMacに接続してNode.jsでイベントを受け取る 🎮

Nintendo Switch Proコントローラー

Nintendo Switch Proコントローラー、通称プロコン。

www.nintendo.co.jp



世界のアソビ大全用に購入したのですが、複数人でのプレイ時には使用できず、どうしたものかと思っていたのですが、Macに繋いで使うことにしました。




接続方法

1台繋ぐだけなら接続自体は何も難しいことはありません。
Bluetooth環境設定から簡単に接続できます。便利。
複数台繋ぐこともできる気がしますが未検証です。

Bluetooth


ボタンイベントのコールバックを登録する

しかし、接続しただけでは何も起こりません。
ボタンを押した際のコールバックイベントを設定していないからです。
いろいろ迷ったんですが、今回はNode.jsをつかってイベントを設定することに決めました。

npmで探してみると、

www.npmjs.com

ばっちり、求めていたものが見つかりました。
早速こちらのパッケージをつかってコールバックイベントを設定しましょう。

と思ったのですが。

こちらのパッケージ。ジョイコンには対応しているものの、プロコンには対応していない模様。
なので、一旦フォークして、プロコンに対応させることにしました。

github.com

ソースコード

const JoyCon = require("./joy-con");

class ProCon extends JoyCon {
  constructor(path = null) {
    super(path);

    this.side = null;

    this.buttons = {
      dpadUp: false,
      dpadDown: false,
      dpadLeft: false,
      dpadRight: false,
      a: false,
      x: false,
      b: false,
      y: false,
      minus: false,
      plus: false,
      screenshot: false,
      home: false,
      l: false,
      r: false,
      zl: false,
      zr: false,
      analogStickLPress: false,
      analogStickRPress: false,
      analogStickL: 130,
      analogStickR: 130
    };
  }

  _buttonsFromInputReport3F(bytes) {
    return {
      dpadLeft: bytes[3] === 5 || bytes[3] === 6 || bytes[3] === 7,
      dpadDown: bytes[3] === 3 || bytes[3] === 4 || bytes[3] === 5,
      dpadUp: bytes[3] === 0 || bytes[3] === 1 || bytes[3] === 7,
      dpadRight: bytes[3] === 1 || bytes[3] === 2 || bytes[3] === 3,

      a: Boolean(bytes[1] & 0x02),
      x: Boolean(bytes[1] & 0x08),
      b: Boolean(bytes[1] & 0x01),
      y: Boolean(bytes[1] & 0x04),

      minus: Boolean(bytes[2] & 0x01),
      plus: Boolean(bytes[2] & 0x02),
      screenshot: Boolean(bytes[2] & 0x20),
      home: Boolean(bytes[2] & 0x10),

      l: Boolean(bytes[1] & 0x10),
      zl: Boolean(bytes[1] & 0x40),
      r: Boolean(bytes[1] & 0x20),
      zr: Boolean(bytes[1] & 0x80),

      analogStickLPress: Boolean(bytes[2] & 0x04),
      analogStickRPress: Boolean(bytes[2] & 0x08),

      analogStickL: [bytes[5], bytes[7]],
      analogStickR: [bytes[9], bytes[11]]
    };
  }
}

module.exports = ProCon;

コントローラの仕様を確認したわけではなく、流れてくるbytesをclosoleで目視確認しながら、場合分けをしていって実装しました。
単純なON / OFF、つまりBooleanのところは多分あってると思うのですが、アナログスティックの値は微妙なところです。あってるのかな?
なんとなく、角度と傾きが別で入ってきている気がしたのですが、とりあえず角度っぽいものをリターンしておきました。
X軸とY軸の値が別で入っていることに気づいたので修正しました。(追記: 2020.07.06)
あと、加速度の値が入ってきてるのかも、いまいちわかりませんでした。


プルリクエストをつくる

suchipiさんのコードがなかったら、かなり時間が掛かってたと思います。圧倒的感謝。
英語が苦手なのと、会ったことの無い人にプルリクを送るのがはじめてなので、正しい手順なのかわからないですが、感謝の気持ちを込めつつ、思い切って、プルリクエストもつくってみました。プルリクってエンジニアっぽくてどきどきしますね。

github.com