t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Arduino LOENARDOでPS4コントローラをマクロキーボードとして使う

今回は、PS4のDualShockコントローラーをマクロキーボードとして使うことに成功したのでご紹介。
絵面はこんな感じ。
f:id:t-hom:20201028201735p:plain

このコントローラーは本来Bluetoothに対応しているが、有線のほうがコードがシンプルになる気がしたのであえて有線で使っている。

マクロキーボードとは

キーボードショートカット等の複数キーの連続入力を一つのキーに割り当てることができるキーボードのこと。
在宅勤務を開始してすぐの頃に9キー登録できるタイプを購入して、Outlookのメールを読むときに重宝している。
例えば次のメールに移動したり、前のメールに移動したり、メールを削除したりといったOutlookに最初から用意されたキーボードショートカットを各マクロキーに割り当てて使用している。
thom.hateblo.jp

パソコン側からみた振る舞いは普通のキーボードなので特にセキュリティ的なリスクはなく、普通のキーボードを繋いでるのと同じ。
ただ会社で使ってると目立つので周辺機器持ち込みOKなユルい職場か、在宅勤務が主な活躍場所となると思われる。

今回作ったものと経緯

既存のマクロキーボードでも十分実用的なんだけど、使っているうちにさらに便利にしたくなってきた。
より誤入力しにくく、操作しやすい形状が良い。さらに卓上だけでなく手にホールドして使いたい。

そこでたどり着いた答えがゲームパッド。
今回作ったのは、単にゲームパッドをマクロキーボードとして使うための変換デバイスである。
専用のマクロ登録ツールなどは存在しないので、マクロは直接Arduino IDEでハードコーディングして基盤に書き込む形である。

もともと自作キーボードとかでArduinoが使われていたのを知っていたので、ゲームパッドを分解して埋め込んだらなんとかなるのではないかと考えていたら、別解としてゲームパッド信号をプログラムで処理してキーコードに変換する手段が見つかったのが今回作成した経緯。

活躍の場は更に絞られ、会社のオフィスで使うのは多分無理。。
真面目にメール閲覧してても遊んでる絵面にしか見えない。在宅専用デバイスである。

ただ今回の事例を応用すれば普通のキーボードをつないでマクロキーボードにすることもできるかと思う。

材料

主な材料

Arduino LEONARDO

UNOはKeyboardライブラリやMouseライブラリに対応しておらず、入力デバイスとして使用することができないのでLEONARDOを選択する。
互換品やNano等、小さい製品も使用できるかもしれないが試してないのでなんとも。


その他

  • USBケーブル 片側micro/片側TypeA を2本(Arduino用とPS4コントローラーのデータ通信用)
  • ハンダ

スキル

真似するだけなら、スキルというほどのスキルは要らない。
ハンダ付けをしたことがない方はYouTubeとかのハンダ付け動画を見よう見まねでやれば良い。
はじめてだと動画の見本のようにはうまくいかず、どちらかといえば「失敗例」に近い仕上がりになるだろう。
まぁつながればなんでも動くので、趣味でやってる分には気にしなくて良い。

Arduinoについては、IDEのインストール、マイコンへの書き込み、ライブラリのインストール、シリアルモニターへの出力ができるようになってれば十分。
入門書とか入門記事でオンボードLEDをチカチカさせられるくらいの経験でもなんとかなる。

作業

USB Host Shieldのハンダジャンパー

ジャンパーというのは、離れた電気回路間をつなぐ電線や端子・ピンのことを指すらしい。
つなぐかつながないかで回路の挙動を変更したりする、一種のスイッチのように使われることも多い。

ハンダジャンパーは下図を見ていただけると早いと思う。青丸の箇所が繋がる前のハンダジャンパー。赤丸が繋げたあと。単にハンダで2接点を繋いだだけ。
f:id:t-hom:20201028211735p:plain

青丸の位置はつなげないので注意。赤丸の部分だけジャンパーさせておく。

ピン曲がりの微修正

前評判どおり、USB Host Shieldは品質が今一つで、とどいた商品の足が曲がっているのでこれをArduinoに挿せる程度には微修正しておく。強い力をかけると折れるリスクがあるので、すこしづつ。

USB Host ShieldをArduinoに接続

ピン曲がりのため微修正したとしても苦労はする。うまくピンを指矯正しながら少しづつ差し込んでいくイメージ。
6ピン(3x2)が最後まで刺さったらOK。他のピンは最後までささらず、2~3ミリくらい接合部からピンが見えるけど、それでOK。

なお、UNOとLEONARDOはピン配置が違うのでそのままでは使えないという記事があったけど、Rev.3というバージョンから共通化されてるらしく、手持ちのLEONARDOではそのまま使えた。

コーディング

まずツール→ライブラリを管理から、USB Host Shield と検索してUSB Host Shield Library 2.0をインストールする。
次に以下のコードを貼り付け。
まだ私もサンプルを改造しながら試してるだけなので、不要なコードも色々残っている。
それでもまぁ一つ達成して熱があるうちに記事にしてしまわないと、あとで面倒になるので書いてしまう。

#include <Keyboard.h>
#include <PS4USB.h>

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

USB Usb;
PS4USB PS4(&Usb);

bool printAngle, printTouch;
uint8_t oldL2Value, oldR2Value;

void setup() {
  if (Usb.Init() == -1) {
    while (1); // Halt
  } 
}

void loop() {
  Usb.Task();

  if (PS4.connected()) {
    if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) {
      
    }

    if (PS4.getAnalogButton(L2) || PS4.getAnalogButton(R2)) { // These are the only analog buttons on the PS4 controller
      
    }
    if (PS4.getAnalogButton(L2) != oldL2Value || PS4.getAnalogButton(R2) != oldR2Value) // Only write value if it's different
      PS4.setRumbleOn(PS4.getAnalogButton(L2), PS4.getAnalogButton(R2));
    oldL2Value = PS4.getAnalogButton(L2);
    oldR2Value = PS4.getAnalogButton(R2);

    if (PS4.getButtonClick(PS)) {
      
    }
    if (PS4.getButtonClick(TRIANGLE)) {
      
    }
    if (PS4.getButtonClick(CIRCLE)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press(KEY_LEFT_SHIFT);
      Keyboard.press('1');
      delay(100);
      Keyboard.releaseAll();
    }
    if (PS4.getButtonClick(CROSS)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press('d');
      delay(100);
      Keyboard.releaseAll();
    }
    if (PS4.getButtonClick(SQUARE)) {
      
    }

    if (PS4.getButtonClick(UP)) {
      Keyboard.press(KEY_PAGE_UP);
      delay(100);
      Keyboard.releaseAll();
    } if (PS4.getButtonClick(RIGHT)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press('>');
      delay(100);
      Keyboard.releaseAll();
    } if (PS4.getButtonClick(DOWN)) {
      Keyboard.press(KEY_PAGE_DOWN);
      delay(100);
      Keyboard.releaseAll();
    } if (PS4.getButtonClick(LEFT)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press('<');
      delay(100);
      Keyboard.releaseAll();
    }

    if (PS4.getButtonClick(L1)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press(KEY_PAGE_UP);
      delay(100);
      Keyboard.releaseAll();
    }
    if (PS4.getButtonClick(L3)) {
      
    }
    if (PS4.getButtonClick(R1)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press(KEY_PAGE_DOWN);
      delay(100);
      Keyboard.releaseAll();
    }
    if (PS4.getButtonClick(R3)) {
      
    }
 
    if (PS4.getButtonClick(SHARE))
      
    if (PS4.getButtonClick(OPTIONS)) {
    }
    if (PS4.getButtonClick(TOUCHPAD)) {
    }
  }
}


キーボードマクロの設定は、if (PS4.getButtonClick(●●)){ }の部分。
以下に例として抜き出した。

    if (PS4.getButtonClick(CROSS)) {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press('d');
      delay(100);
      Keyboard.releaseAll();
    }

これは"Ctrl+d"のショートカットを×ボタンに割り当てている部分。
キーボードインプットについてはArduinoのKeyboardライブラリについて検索すればいくつか事例が見つかると思う。


ちなみにもともとのコードはファイル→スケッチ例メニューから以下を探すと新規コードウインドウで出てくるので、コントローラーのバイブ機能とかLED制御とかはそちらを参照すると良い。

f:id:t-hom:20201028215449p:plain
スケッチ例のコードは押したキーがシリアルモニターに表示されるようになっており、IDEのツールからシリアルモニターを起動しておかないと動かないので注意。PS4のほかに、JoystickのサンプルスケッチでPC用のゲームパッドが使えるといった記事があったけどLogicoolの手持ちのゲームパッドでは動かなかった。やはり種類も多いので製品ごとに作りが違う為だろうか。
その点有名なPS4コントローラーはサンプルスケッチもズバリ特化してるので間違いない。

Keyboardライブラリの使い方もざっくり知りたければスケッチ例から探すと良い。

使い方

この記事のコードはあくまで私のマクロ設定なので、コードは使いたいキーマクロに合わせて改造する必要がある。
一度Arduinoに書き込んでしまえばあとはどのPCにつないでも同じように動作する。
PS4コントローラーをUSB Host Shield側のUSBに接続し、Arduino側のUSBは普通にPCとつなぐ。
あとはボタン押すとArduino IDEでコーディングした通りのキーがPCに入力される。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。