PS4専用DIVAコントローラを任天堂Switchでも使える様にArduino Leonardoで変換器を作る

#はじめに
　HORIさんから発売された「初音ミクProject DIVA Future Tone DX専用ゲームコントローラー」を同ゲームの任天堂Switch版でもある「MEGA39's」でも使う場合、市販のコントローラー変換機だと入力トラブルがある様なので、Arduino LeonardoとUSBホストシールドで自作してみました。

#用意するもの
・**Arduino Leonardo**　（以下、Leonardo。互換機では試していません。ATmega32u4チップが乗っていれば大丈夫なはず？）<font color="Red">※Arduino UNOだと、このやり方では動きません。</font>
・**USBホストシールド2.0 for Arduino**
　　※安い互換品はハンダ付けの必要あり。[サインマート製](https://www.amazon.co.jp/SainSmart-USB%E3%83%9B%E3%82%B9%E3%83%88%E3%82%B7%E3%83%BC%E3%83%AB%E3%83%89-Mega2560-Duemilanove-ADK%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%A7%E3%81%8D/dp/B006J4G000/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=USB%E3%83%9B%E3%82%B9%E3%83%88%E3%82%B7%E3%83%BC%E3%83%AB%E3%83%89&qid=1587376984&sr=8-3)は少々高いですが、ハンダ付けの必要がないので
　　　ハンダごてを持っていない・ハンダ付け作業が不安な方にはオススメです。
・**PC**（Arduino IDEが動作するもの）
・**USBケーブル type A - micro** 　(PC・任天堂スイッチと Leonardo の接続用。データ転送出来る物）
・**「初音ミク Project DIVA Future Tone DX」専用コントローラー**（以下、DIVAコン。）
 
#Arduino IDEのインストール

※PCはWindows10、Arduino IDEはインストーラー版を元に書いています。

[Arduinoの公式サイト](https://www.arduino.cc/)の **SOFTWARE > DOWNLOADS** から、自分の環境にあったIDEをインストールします。
<font color="Red">※Arduino IDEは1.8.12を使用して下さい。1.8.13ではArduinoSTLでコンパイルエラーが発生し、ネットに上がっているボード情報のダウングレードで対処しても正しく動作しません。1.8.12のダウンロードは、DownloadページのPrevious Releasesから出来ます。</font>

※寄付はお好みで。ダウンロードだけしたい場合は、**JUST DOWNLOAD** を押してください。

#Switch Control Library と USB Host Library Rev.2.0、ArduinoSTL のインストール
###Switch Control Libraryのダウンロード
　有志の方が製作した、ATmega32u4チップの乗ったArduinoを任天堂Switch用コントローラー化するライブラリを使わさせて貰います。
[GitHubの公開ページ](https://github.com/celclow/SwitchControlLibrary)で**clone or download**（ページ右側、緑色のプルダウン）から**Download ZIP**を選び、ダウンロードします。
（ファイル名：**SwitchControlLibrary-master.zip** ）※Singn in,Sign upは無視して可。

###USB Host Library Rev.2.0のダウンロード
　同様に、GitHubから[USBホストシールド用のライブラリ](https://github.com/felis/USB_Host_Shield_2.0)をダウンロードします。
（ファイル名：**USB_Host_Shield_2.0-master.zip** ）


###Switch Control Library と USB Host Library Rev.2.0 のインストール
　Arduino IDEを起動し、メニューバーから**[スケッチ]-[ライブラリをインクルード]-[.ZIP形式のライブラリをインストール...]**を選び、先ほどダウンロードした２つのファイルをインストールします。

###Arduino STL のインストール
　次に、メニューバーから**[スケッチ]-[ライブラリをインクルード]-[ライブラリを管理...]**を選び、ライブラリマネージャで「ArduinoSTL」を検索してインストールします。終わったら、またメニューバーから[スケッチ]-[ライブラリをインクルード]を選び、インストールした３つが表示されているか確認し、良ければ IDE を終了します。

#Switch Control Libraryの変更
　Switch Control Library を使いやすくします。
「\Users\ **ユーザー名** \Documents\Arduino\libraries\SwitchControlLibrary-master\src」内にある **SwitchControlLibrary.h** を編集で開き、下から4行目の`void MoveRightStick(uint8_t rx, uint8_t ry);`の下に、以下のコードを追加します。

```cpp:追加するコード
	void Mega39s(uint16_t button, uint8_t hat, uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry);
```

<details><summary>追加後の SwitchControlLibrary.h 全コード</summary><div>

```cpp:追加後のSwitchControlLibrary.h
#include <ArduinoSTL.h>
#include <list>

#include "CustomHID.h"

enum class Button : uint16_t
{
	Y = 0x0001,
	B = 0x0002,
	A = 0x0004,
	X = 0x0008,
	L = 0x0010,
	R = 0x0020,
	ZL = 0x0040,
	ZR = 0x0080,
	MINUS = 0x0100,
	PLUS = 0x0200,
	LCLICK = 0x0400,
	RCLICK = 0x0800,
	HOME = 0x1000,
	CAPTURE = 0x2000
};

enum class Hat : uint8_t
{
	TOP = 0x00,
	TOP_RIGHT = 0x01,
	RIGHT = 0x02,
	BOTTOM_RIGHT = 0x03,
	BOTTOM = 0x04,
	BOTTOM_LEFT = 0x05,
	LEFT = 0x06,
	TOP_LEFT = 0x07,
	CENTER = 0x08
};

enum class Stick : uint8_t
{
	MIN = 0,
	CENTER = 128,
	MAX = 255
};

typedef struct
{
	uint16_t Button;
	uint8_t Hat;
	uint8_t LX;
	uint8_t LY;
	uint8_t RX;
	uint8_t RY;
	uint8_t VendorSpec;
} USB_JoystickReport_Input_t;

class SwitchControlLibrary_
{
  private:
	USB_JoystickReport_Input_t _joystickInputData;
	void SendReport();

  public:
	SwitchControlLibrary_();

	void PressButtonY();
	void ReleaseButtonY();
	void PressButtonB();
	void ReleaseButtonB();
	void PressButtonA();
	void ReleaseButtonA();
	void PressButtonX();
	void ReleaseButtonX();
	void PressButtonL();
	void ReleaseButtonL();
	void PressButtonR();
	void ReleaseButtonR();
	void PressButtonZL();
	void ReleaseButtonZL();
	void PressButtonZR();
	void ReleaseButtonZR();
	void PressButtonMinus();
	void ReleaseButtonMinus();
	void PressButtonPlus();
	void ReleaseButtonPlus();
	void PressButtonLClick();
	void ReleaseButtonLClick();
	void PressButtonRClick();
	void ReleaseButtonRClick();
	void PressButtonHome();
	void ReleaseButtonHome();
	void PressButtonCapture();
	void ReleaseButtonCapture();
	void MoveHat(uint8_t hat);
	void MoveLeftStick(uint8_t lx, uint8_t ly);
	void MoveRightStick(uint8_t rx, uint8_t ry);
	void Mega39s(uint16_t button, uint8_t hat, uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry);
};

SwitchControlLibrary_ &SwitchControlLibrary();
```
</div></details>



また、同フォルダ内にある **SwitchControlLibrary.cpp** の最後の`#endif`の上に、以下のコードを追加します。

```cpp:追加するコード

void SwitchControlLibrary_::Mega39s(uint16_t button, uint8_t hat, uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry)
{
    _joystickInputData.Button = button;
	_joystickInputData.Hat = hat;
	_joystickInputData.LX = lx;
    _joystickInputData.LY = ly;
	_joystickInputData.RX = rx;
    _joystickInputData.RY = ry;
    SendReport();
}
```

<details><summary>追加後の SwitchControlLibrary.cpp 全コード</summary><div>

```cpp:追加後のSwitchControlLibrary.cpp
#include "SwitchControlLibrary.h"

#if defined(_USING_HID)

static const uint8_t _hidReportDescriptor[] PROGMEM = {
    0x05, 0x01,       //   USAGE_PAGE (Generic Desktop)
    0x09, 0x05,       //   USAGE (Game Pad)
    0xa1, 0x01,       //   COLLECTION (Application)
    0x15, 0x00,       //   LOGICAL_MINIMUM (0)
    0x25, 0x01,       //   LOGICAL_MAXIMUM (1)
    0x35, 0x00,       //   PHYSICAL_MINIMUM (0)
    0x45, 0x01,       //   PHYSICAL_MAXIMUM (1)
    0x75, 0x01,       //   REPORT_SIZE (1)
    0x95, 0x10,       //   REPORT_COUNT (16)
    0x05, 0x09,       //   USAGE_PAGE (Button)
    0x19, 0x01,       //   USAGE_MINIMUM (1)
    0x29, 0x10,       //   USAGE_MAXIMUM (16)
    0x81, 0x02,       //   INPUT (Data,Var,Abs)
    0x05, 0x01,       //   USAGE_PAGE (Generic Desktop)
    0x25, 0x07,       //   LOGICAL_MAXIMUM (7)
    0x46, 0x3b, 0x01, //   PHYSICAL_MAXIMUM (315)
    0x75, 0x04,       //   REPORT_SIZE (4)
    0x95, 0x01,       //   REPORT_COUNT (1)
    0x65, 0x14,       //   UNIT (20)
    0x09, 0x39,       //   USAGE (Hat Switch)
    0x81, 0x42,       //   INPUT (Data,Var,Abs)
    0x65, 0x00,       //   UNIT (0)
    0x95, 0x01,       //   REPORT_COUNT (1)
    0x81, 0x01,       //   INPUT (Cnst,Arr,Abs)
    0x26, 0xff, 0x00, //   LOGICAL_MAXIMUM (255)
    0x46, 0xff, 0x00, //   PHYSICAL_MAXIMUM (255)
    0x09, 0x30,       //   USAGE (X)
    0x09, 0x31,       //   USAGE (Y)
    0x09, 0x32,       //   USAGE (Z)
    0x09, 0x35,       //   USAGE (Rz)
    0x75, 0x08,       //   REPORT_SIZE (8)
    0x95, 0x04,       //   REPORT_COUNT (4)
    0x81, 0x02,       //   INPUT (Data,Var,Abs)
    0x06, 0x00, 0xff, //   USAGE_PAGE (Vendor Defined 65280)
    0x09, 0x20,       //   USAGE (32)
    0x95, 0x01,       //   REPORT_COUNT (1)
    0x81, 0x02,       //   INPUT (Data,Var,Abs)
    0x0a, 0x21, 0x26, //   USAGE (9761)
    0x95, 0x08,       //   REPORT_COUNT (8)
    0x91, 0x02,       //   OUTPUT (Data,Var,Abs)
    0xc0              // END_COLLECTION
};

SwitchControlLibrary_::SwitchControlLibrary_()
{
    static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
    CustomHID().AppendDescriptor(&node);

    memset(&_joystickInputData, 0, sizeof(USB_JoystickReport_Input_t));
    _joystickInputData.LX = (uint8_t)Stick::CENTER;
    _joystickInputData.LY = (uint16_t)Stick::CENTER;
    _joystickInputData.RX = (uint16_t)Stick::CENTER;
    _joystickInputData.RY = (uint16_t)Stick::CENTER;
    _joystickInputData.Hat = (uint16_t)Hat::CENTER;
}

void SwitchControlLibrary_::SendReport()
{
    CustomHID().SendReport(&_joystickInputData, sizeof(USB_JoystickReport_Input_t));
}

void SwitchControlLibrary_::PressButtonY()
{
    _joystickInputData.Button |= (uint16_t)Button::Y;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonY()
{
    _joystickInputData.Button &= ((uint16_t)Button::Y ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonB()
{
    _joystickInputData.Button |= (uint16_t)Button::B;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonB()
{
    _joystickInputData.Button &= ((uint16_t)Button::B ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonA()
{
    _joystickInputData.Button |= (uint16_t)Button::A;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonA()
{
    _joystickInputData.Button &= ((uint16_t)Button::A ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonX()
{
    _joystickInputData.Button |= (uint16_t)Button::X;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonX()
{
    _joystickInputData.Button &= ((uint16_t)Button::X ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonL()
{
    _joystickInputData.Button |= (uint16_t)Button::L;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonL()
{
    _joystickInputData.Button &= ((uint16_t)Button::L ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonR()
{
    _joystickInputData.Button |= (uint16_t)Button::R;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonR()
{
    _joystickInputData.Button &= ((uint16_t)Button::R ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonZL()
{
    _joystickInputData.Button |= (uint16_t)Button::ZL;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonZL()
{
    _joystickInputData.Button &= ((uint16_t)Button::ZL ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonZR()
{
    _joystickInputData.Button |= (uint16_t)Button::ZR;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonZR()
{
    _joystickInputData.Button &= ((uint16_t)Button::ZR ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonMinus()
{
    _joystickInputData.Button |= (uint16_t)Button::MINUS;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonMinus()
{
    _joystickInputData.Button &= ((uint16_t)Button::MINUS ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonPlus()
{
    _joystickInputData.Button |= (uint16_t)Button::PLUS;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonPlus()
{
    _joystickInputData.Button &= ((uint16_t)Button::PLUS ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonLClick()
{
    _joystickInputData.Button |= (uint16_t)Button::LCLICK;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonLClick()
{
    _joystickInputData.Button &= ((uint16_t)Button::LCLICK ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonRClick()
{
    _joystickInputData.Button |= (uint16_t)Button::RCLICK;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonRClick()
{
    _joystickInputData.Button &= ((uint16_t)Button::RCLICK ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonHome()
{
    _joystickInputData.Button |= (uint16_t)Button::HOME;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonHome()
{
    _joystickInputData.Button &= ((uint16_t)Button::HOME ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::PressButtonCapture()
{
    _joystickInputData.Button |= (uint16_t)Button::CAPTURE;
    SendReport();
}

void SwitchControlLibrary_::ReleaseButtonCapture()
{
    _joystickInputData.Button &= ((uint16_t)Button::CAPTURE ^ 0xffff);
    SendReport();
}

void SwitchControlLibrary_::MoveHat(uint8_t hat)
{
    _joystickInputData.Hat = hat;
    SendReport();
}

void SwitchControlLibrary_::MoveLeftStick(uint8_t lx, uint8_t ly)
{
    _joystickInputData.LX = lx;
    _joystickInputData.LY = ly;
    SendReport();
}

void SwitchControlLibrary_::MoveRightStick(uint8_t rx, uint8_t ry)
{
    _joystickInputData.RX = rx;
    _joystickInputData.RY = ry;
    SendReport();
}

SwitchControlLibrary_ &SwitchControlLibrary()
{
    static SwitchControlLibrary_ obj;
    return obj;
}
void SwitchControlLibrary_::Mega39s(uint16_t button, uint8_t hat, uint8_t lx, uint8_t ly, uint8_t rx, uint8_t ry)
{
    _joystickInputData.Button = button;
    _joystickInputData.Hat = hat;
    _joystickInputData.LX = lx;
    _joystickInputData.LY = ly;
    _joystickInputData.RX = rx;
    _joystickInputData.RY = ry;
    SendReport();
}
#endif
```
</div></details>


#USB Host Library Rev.2.0の変更
　そのままではUSBホストシールドがDIVAコンを認識出来ないので、出来るようにします。
「\Users\ **ユーザー名** \Documents\Arduino\libraries\USB_Host_Shield_2.0-master」内の**PS4USB.h**をデスクトップなどにコピーし、**PS4DIVA.h**にリネームして編集で開き

```cpp:PS4DIVA.h変更前
#define PS4_VID         0x054C // Sony Corporation
#define PS4_PID         0x05C4 // PS4 Controller
```
の部分を

```cpp:PS4DIVA.h変更後
#define PS4_VID         0x0f0d // Sony Corporation
#define PS4_PID         0x013c // PS4 Controller
```
に書き換えます。　また、**”PS4USB”**となっている部分を全て**”PS4DIVA”**に書き換えて保存し、ファイルを元のフォルダに移動させます。

<details><summary>PS4DIVA.h全コード</summary><div>

```cpp:PS4DIVA.h
/* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. All rights reserved.

 This software may be distributed and modified under the terms of the GNU
 General Public License version 2 (GPL2) as published by the Free Software
 Foundation and appearing in the file GPL2.TXT included in the packaging of
 this file. Please note that GPL2 Section 2[b] requires that all works based
 on this software must also be made publicly available under the terms of
 the GPL2 ("Copyleft").

 Contact information
 -------------------

 Kristian Lauszus, TKJ Electronics
 Web      :  http://www.tkjelectronics.com
 e-mail   :  kristianl@tkjelectronics.com
 */

#ifndef _ps4usb_h_
#define _ps4usb_h_

#include "hiduniversal.h"
#include "PS4Parser.h"

#define PS4_VID         0x0f0d // Sony Corporation
#define PS4_PID         0x013c // PS4 Controller
#define PS4_PID_SLIM    0x09CC // PS4 Slim Controller

/**
 * This class implements support for the PS4 controller via USB.
 * It uses the HIDUniversal class for all the USB communication.
 */
class PS4DIVA : public HIDUniversal, public PS4Parser {
public:
        /**
         * Constructor for the PS4USB class.
         * @param  p   Pointer to the USB class instance.
         */
        PS4DIVA(USB *p) :
        HIDUniversal(p) {
                PS4Parser::Reset();
        };

        /**
         * Used to check if a PS4 controller is connected.
         * @return Returns true if it is connected.
         */
        bool connected() {
                return HIDUniversal::isReady() && HIDUniversal::VID == PS4_VID && (HIDUniversal::PID == PS4_PID || HIDUniversal::PID == PS4_PID_SLIM);
        };

        /**
         * Used to call your own function when the device is successfully initialized.
         * @param funcOnInit Function to call.
         */
        void attachOnInit(void (*funcOnInit)(void)) {
                pFuncOnInit = funcOnInit;
        };

protected:
        /** @name HIDUniversal implementation */
        /**
         * Used to parse USB HID data.
         * @param hid       Pointer to the HID class.
         * @param is_rpt_id Only used for Hubs.
         * @param len       The length of the incoming data.
         * @param buf       Pointer to the data buffer.
         */
        virtual void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
                if (HIDUniversal::VID == PS4_VID && (HIDUniversal::PID == PS4_PID || HIDUniversal::PID == PS4_PID_SLIM))
                        PS4Parser::Parse(len, buf);
        };

        /**
         * Called when a device is successfully initialized.
         * Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
         * This is useful for instance if you want to set the LEDs in a specific way.
         */
        virtual uint8_t OnInitSuccessful() {
                if (HIDUniversal::VID == PS4_VID && (HIDUniversal::PID == PS4_PID || HIDUniversal::PID == PS4_PID_SLIM)) {
                        PS4Parser::Reset();
                        if (pFuncOnInit)
                                pFuncOnInit(); // Call the user function
                        else
                                setLed(Blue);
                };
                return 0;
        };
        /**@}*/

        /** @name PS4Parser implementation */
        virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv
                uint8_t buf[32];
                memset(buf, 0, sizeof(buf));

                buf[0] = 0x05; // Report ID
                buf[1]= 0xFF;

                buf[4] = output->smallRumble; // Small Rumble
                buf[5] = output->bigRumble; // Big rumble

                buf[6] = output->r; // Red
                buf[7] = output->g; // Green
                buf[8] = output->b; // Blue

                buf[9] = output->flashOn; // Time to flash bright (255 = 2.5 seconds)
                buf[10] = output->flashOff; // Time to flash dark (255 = 2.5 seconds)

                output->reportChanged = false;

                // The PS4 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed

                pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, sizeof(buf), buf);
        };
        /**@}*/

        /** @name USBDeviceConfig implementation */
        /**
         * Used by the USB core to check what this driver support.
         * @param  vid The device's VID.
         * @param  pid The device's PID.
         * @return     Returns true if the device's VID and PID matches this driver.
         */
        virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
                return (vid == PS4_VID && (pid == PS4_PID || HIDUniversal::PID == PS4_PID_SLIM));
        };
        /**@}*/

private:
        void (*pFuncOnInit)(void); // Pointer to function called in onInit()
};
#endif
```
</div></details>

#boards.txtの編集
任天堂 Switch が、Leonardo をコントローラーとして認識出来るようにします。
「Arduino IDE のインストールフォルダ\hardware\arduino\avr\」内の**boards.txt**編集で開き

```cpp:boards.txt変更前
leonardo.vid.1=0x2341
leonardo.pid.1=0x8036

（中略）

leonardo.build.vid=0x2341
leonardo.build.pid=0x8036
```
を

```cpp:boards.txt変更後
leonardo.vid.1=0x0f0d
leonardo.pid.1=0x0092

（中略）

leonardo.build.vid=0x0f0d
leonardo.build.pid=0x0092
```
に変更します。保存できない場合、ファイルをデスクトップなどに移動後、編集して元のフォルダに戻してください。
これで下準備は終わりました。
#Leonardoへのプログラムの書き込み
　まず、LeonardoにUSBホストシールドを取り付けます。次に、DIVAコンをUSBホストシールド接続し、LeonardoとPCをUSBケーブルtypeA - micro を使って繋ぎます。**DIVAコンは、「ARCADE MODE」にしておきます。**
　　![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502004/29707073-238e-e9bc-4ff0-202d763646de.jpeg)




　Arduino IDEを起動し、メニューバーから**[ファイル]-[新規ファイル]**を選びます。
空のスケッチが別ウィンドウで開くので、書かれているコードを全て消し、以下のコードをコピペします。

```cpp
#include <PS4DIVA.h>
#include <SwitchControlLibrary.h>

#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

USB Usb;
PS4DIVA PS4(&Usb);

uint16_t Current_Input_Button = 0;
uint8_t Current_Input_Hat = 0x08;
byte Lx = 0x80;
byte Ly = 0x80;
byte Rx = 0x80;
byte Ry = 0x80;

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

void loop() {
  while (1) {
    Current_Input_Hat = 0x08;
    Current_Input_Button = 0x00;

    Usb.Task();
    if (PS4.connected()) {
      
      /* Analog Stick */
      Lx = PS4.getAnalogHat(LeftHatX);
      Ly = PS4.getAnalogHat(LeftHatY);
      Rx = PS4.getAnalogHat(RightHatX);
      Ry = PS4.getAnalogHat(RightHatY);
      
      /* Hat */
      if (PS4.getButtonPress(UP) && PS4.getButtonPress(RIGHT)) {
        Current_Input_Hat = 0x01;
      }
      else if (PS4.getButtonPress(RIGHT) && PS4.getButtonPress(DOWN)) {
        Current_Input_Hat = 0x03;
      }
      else if (PS4.getButtonPress(DOWN) && PS4.getButtonPress(LEFT)) {
        Current_Input_Hat = 0x05;
      }
      else if (PS4.getButtonPress(LEFT) && PS4.getButtonPress(UP)) {
        Current_Input_Hat = 0x07;
      }
      else if (PS4.getButtonPress(UP)) {
        Current_Input_Hat = 0x00;
      }
      else if (PS4.getButtonPress(RIGHT)) {
        Current_Input_Hat = 0x02;
      }
      else if (PS4.getButtonPress(DOWN)) {
        Current_Input_Hat = 0x04;
      }
      else if (PS4.getButtonPress(LEFT)) {
        Current_Input_Hat = 0x06;
      }
      
      /* Buttons */
      if (PS4.getButtonPress(PS)) {
        bitSet(Current_Input_Button, 12);
      }
      if (PS4.getButtonPress(TRIANGLE)) {
        bitSet(Current_Input_Button, 3);
      }
      if (PS4.getButtonPress(CIRCLE)) {
        bitSet(Current_Input_Button, 2);
      }
      if (PS4.getButtonPress(CROSS)) {
        bitSet(Current_Input_Button, 1);
      }
      if (PS4.getButtonPress(SQUARE)) {
        bitSet(Current_Input_Button, 0);
      }
      if (PS4.getButtonPress(L1)) {
        bitSet(Current_Input_Button, 4);
      }
      if (PS4.getButtonPress(L2)) {
        bitSet(Current_Input_Button, 6);
      }
      if (PS4.getButtonPress(L3)) {
        bitSet(Current_Input_Button, 10);
      }
      if (PS4.getButtonPress(R1)) {
        bitSet(Current_Input_Button, 5);
      }
      if (PS4.getButtonPress(R2)) {
        bitSet(Current_Input_Button, 7);
      }
      if (PS4.getButtonPress(R3)) {
        bitSet(Current_Input_Button, 11);
      }
      if (PS4.getButtonPress(SHARE)) {
        bitSet(Current_Input_Button, 13);
      }
      if (PS4.getButtonPress(OPTIONS)) {
        bitSet(Current_Input_Button, 9);
      }
      if (PS4.getButtonPress(TOUCHPAD)) {
        bitSet(Current_Input_Button, 8);
      }
    }
    SwitchControlLibrary().Mega39s(Current_Input_Button, Current_Input_Hat, Lx, Ly, Rx, Ry);
  }
}
```
コピペしたら、メニューバーの**[ツール]-[ボード]**で、**「Arduino Leonardo」**を選び、同じくメニューバーの**[ツール]-[シリアルポート]**で、**「COMxx（Arduino Leonardo)」**を選びます。(xxは環境により異なる数字が入ります）
　次に、ツールバーの **➡** アイコンを押します。スケッチの保存を促されるので、適当な名前で保存します。

　スケッチのコンパイルと書き込みが完了するまで待ちます。

　無事に完了したら、[ここなど](https://html5gamepad.com/)で動作確認を行います（「 No gamepad detected.」と表示させる場合は、1度LeonardoをPCに繋ぎなおしてください。それでもダメな場合はどこか間違えています）。DIVAコンのボタンを押したりタッチスライダーを触ったりして反応がある様なら、PCからLeonardoを外して任天堂Switchに繋ぎます。

#実際に遊んでみる
　数日間遊んでみましたが、特に入力不具合や遅延を感じること無く快適に使えています。これで一つのDIVAコンでPS4、任天堂Switch両方で遊べるようになりました。

#最後に
　有志の方がライブラリを公開して下さっているおかげで、かなり簡単に作ることが出来ました。この場を借りて感謝いたします。