はじめに
過去に、以下の記事で書いた内容を少しだけ試していた node-hid の話です。この node-hid は、Joy-Con を HIDデバイスとして扱う際に便利なパッケージです。
●【完走賞ゲット-14】node-hid の hid-showdevicesコマンドで HIDデバイスに関する情報を出力(Node.js、JavaScript) - Qiita
https://qiita.com/youtoy/items/eb7f8418fa926266946f
この時は、コードを書かずに利用できる、コマンドとして扱える仕組みを使っていました。
今回は Node.js のコードを書いて、それで Joy-Con の A・Bボタン押下を検出してみます。
ちなみに、以下のコントローラーを PC で扱って、個人のモノ作り活動に活用しようと思っていて、その準備運動的な感じで手をつけました(なお、過去に WebHID/Gamepad API で Joy-Con を扱ったことは、既にあったりします)。
上記は、おそらくは Joy-Con を HIDデバイスとして扱って、値をとれるだろうと想定してのことです(それをやっていた記事を見かけていて、問題なく実現できそう)。
Joy-Con を HIDデバイスとして扱う
Joy-Con を HIDデバイスとして扱う場合、以下の記事の中で紹介されているような、やりとりされるデータのフォーマットを考慮した処理が必要になります。
●Amusement Creators | SwitchのJoyConをプログラムから使う
https://www.amusement-creators.info/articles/advent_calendar/2019/23_0/
通信時のデータフォーマットの情報が必要だったり、内容によっては機能を有効化する手順をふむ必要があったりしてその手順に関する情報を得るなどという、そういったデバイス固有の情報を得る必要があったりします。
ブラウザの WebHID の場合
ちなみに Node.js ではなく、ブラウザ上での JavaScript で扱う場合(ブラウザの WebHID の API を使う場合)は、以下の記事 1つ目のようにデータフォーマットの仕様に合わせた処理を実装したことがありました。また、以下の 2つ目の記事にあるようなライブラリ(データフォーマットを考慮した処理をラップしてくれているもの)を活用したりする方法があります。
●ブラウザの WebHID を p5.js Web Editor上で利用する:デバイスは DualShock 4 - Qiita
https://qiita.com/youtoy/items/90c1c98829f400969657
●【小ネタ】ブラウザで PS4用コントローラー「DUALSHOCK 4」を扱う下準備: WebHID API と WebHID-DS4 - Qiita
https://qiita.com/youtoy/items/deabcc7a126186933092
メジャーなコントローラーは、ライブラリがでているので、それを探して活用するのがオススメです。
node-hid を使った処理
この後は、サクッと実装の例 + 処理を実行した結果の話を書いて終わります。
node-hid を使った処理は以下の通りです。以下を実行する前には、PC と Joy-Con を Bluetooth でペアリングしておいてください。
const HID = require("node-hid");
const VID = 0x057e; // Nintendo
const PID = 0x2007; // Joy-Con R
const devInfo = HID.devices().find(
(d) => d.vendorId === VID && d.productId === PID
);
if (!devInfo) {
console.error(
"Joy-Con R が見つかりません。Bluetooth ペアリングを確認してください。"
);
process.exit(1);
}
/* --- 出力レポート 0x01(Sub-command)生成ユーティリティ --- */
let pkt = 0;
const RUMBLE_OFF = Buffer.from([0, 1, 0x40, 0x40, 0, 1, 0x40, 0x40]); // 8 byte 固定
function makeSubCmd(id, data = Buffer.alloc(0)) {
const buf = Buffer.alloc(10 + data.length);
buf[0] = 0x01; // Report ID
buf[1] = pkt++ & 0x0f; // Packet counter (0-15)
RUMBLE_OFF.copy(buf, 2);
buf[10] = id; // Sub-command ID
data.copy(buf, 11);
return buf;
}
/* --- 本体 --- */
const joycon = new HID.HID(devInfo.path);
/* 0x03: Set input-report mode → 0x30 (標準フルレポート 60 Hz) */
joycon.write([...makeSubCmd(0x03, Buffer.from([0x30]))]);
console.log("🎮 Joy-Con R 接続完了。A/B 押下を監視中…");
/* 直前の A/B 状態を保持 */
let prev = 0;
joycon.on("data", (buf) => {
if (buf[0] !== 0x30) return;
const buttons = buf[3];
const now = buttons & 0x0c; // 0x08 = A, 0x04 = B
const rising = ~prev & now; // 押下関連のフラグ
if (rising & 0x08) console.log("A ボタン押下");
if (rising & 0x04) console.log("B ボタン押下");
prev = now;
});
joycon.on("error", (err) => console.error("HID エラー:", err));
処理の冒頭部分で ID をハードコーディングしていますが、HIDデバイスをもれなく探すのではなく、Switch の Joy-Con R を探す処理になるよう、とりあえず適当にフィルターをかけています。それ以降は、所定のフォーマットに合わせたバイナリの読み書きの処理などを入れています。
実行結果
上記を実行した結果は以下で、ボタン押下時にコンソールにメッセージが出ており、そのメッセージで A・Bボタンのどちらが押されたかを確認できます。問題なく動作したようです。
無事、A・Bボタンの押下を検出できました。
他のボタンやスティックを扱う検証
他のボタン・スティックを扱う処理も、とりあえず版を実装してみて、動作確認はやってみました(コードの内容は整理中)。その結果は以下のとおりです。
おわりに
今回、node-hid を使って Joy-Con のボタン押下を Node.js で検出するというのを、とりあえず A・Bボタンを対象にやってみました。
この先は、冒頭で少し掲載していた以下のコントローラーを扱う部分へ入っていければと思います。
余談
「人生ゲーム for Nintendo Switch専用ルーレットコントローラー」をポチるか長らく保留してたものの、それをポチる引き金になった記事について、実装が GitHubリポジトリで公開されているという情報をいただきました(GitHubリポジトリのほうの情報公開は気がつけてなかったので、知れてありがたかったです)。
Node.js での実装らしいとのことで、サクッと試せそうです。また、個人的には WebHID で扱いたいと思ったものなので、それもやっていければと思います。
【追記】余談に関するその後
とりあえず、上記の GitHubリポジトリに公開されていたものを使った動作確認ができました。
また、描画まわりを独自の内容に置きかえてみる(まずは p5.js によるシンプルな Canvas描画のものに置きかえ)というのも試せました。