MSX エミュレータ用のゲームコントローラーを作る

# はじめに

以前、『X68000Z』用にゲームコントローラーを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/307d3b45-7ce9-d67a-a002-dd894fe9528c.png)

 - [X68000Z 用のゲームコントローラーとコンバーターを作る (Qiita)](https://qiita.com/ht_deko/items/f7de487904afbbf9f4f0)

これを MSX エミュレータで快適に使えるよう、スケッチを書き替えてみる事にしました。

# ゲームコントローラー

スーパーファミコン用コントローラーの流用です。

## ハードウェア

『X68000Z』用に作ったものと全く同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/31442359-6224-d59d-02c6-d6dc399457b9.png)

## スケッチ

:::note
・スケッチのコンパイルには『[Arduino Joystick Library 2.x](https://github.com/MHeironimus/ArduinoJoystickLibrary/tree/version-2.0)』が必要です。
・スケッチのコンパイルには『MsTimer2』(ライブラリの追加で検索してください) が必要です。
::: 

```cpp:JOY_DINPUT_MSX.ino
#include <Keyboard.h>
#include <Joystick.h>
#include <MsTimer2.h>

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 2, 0, 
                   true, true, false, false, false, false, 
                   false, false, false, false, false);
    
/* PINS */
const int PIN_UP    = A0;
const int PIN_DOWN  = A3;
const int PIN_LEFT  = A2;
const int PIN_RIGHT = A1;
const int PIN_A     =  7;
const int PIN_B     =  8;
const int PIN_X     =  9;
const int PIN_Y     = 10;
const int PIN_L     =  3;
const int PIN_R     =  4;
const int PIN_SEL   =  5;
const int PIN_START =  6;

static bool pressState = false;

void setup() {
  pinMode(PIN_UP   , INPUT_PULLUP);
  pinMode(PIN_DOWN , INPUT_PULLUP);
  pinMode(PIN_LEFT , INPUT_PULLUP);
  pinMode(PIN_RIGHT, INPUT_PULLUP);
  pinMode(PIN_A    , INPUT_PULLUP);
  pinMode(PIN_B    , INPUT_PULLUP);
  pinMode(PIN_X    , INPUT_PULLUP);
  pinMode(PIN_Y    , INPUT_PULLUP);
  pinMode(PIN_L    , INPUT_PULLUP);
  pinMode(PIN_R    , INPUT_PULLUP);
  pinMode(PIN_SEL  , INPUT_PULLUP);
  pinMode(PIN_START, INPUT_PULLUP);

  Keyboard.begin();  
  Joystick.begin();

  MsTimer2::set(31, toggleSwitch);
  MsTimer2::start();  
}

void loop() {
  /* Buttons */
  bool state_A     = !digitalRead(PIN_A);
  bool state_B     = !digitalRead(PIN_B);
  bool state_X     = !digitalRead(PIN_X);
  bool state_Y     = !digitalRead(PIN_Y);

  if (!digitalRead(PIN_UP))
    Joystick.setYAxis(0);
  else if (!digitalRead(PIN_DOWN))
    Joystick.setYAxis(1023);
  else
    Joystick.setYAxis(511);
  if (!digitalRead(PIN_LEFT))
    Joystick.setXAxis(0);
  else if (!digitalRead(PIN_RIGHT))
    Joystick.setXAxis(1023);
  else 
    Joystick.setXAxis(511);
  
  if (state_X) { 
    Joystick.setButton(1, pressState);
  } else {  
    Joystick.setButton(1, state_A);
  }
  if (state_Y) { 
    Joystick.setButton(0, pressState);
  } else { 
    Joystick.setButton(0, state_B);
  }  

  if (!digitalRead(PIN_L)) {
    Keyboard.press(KEY_ESC);
    delay(100);
    Keyboard.releaseAll();
    delay(100);
  }

  if (!digitalRead(PIN_R)) {
    Keyboard.press(KEY_RETURN);
    delay(100);
    Keyboard.releaseAll();
    delay(100);
  }

  if (!digitalRead(PIN_SEL)) {
    Keyboard.press(KEY_F1);
    delay(100);
    Keyboard.releaseAll();
    delay(100);
  }
  
  if (!digitalRead(PIN_START)) {
    Keyboard.press(KEY_F5);
    delay(100);
    Keyboard.releaseAll();
    delay(100);
  }
}

void toggleSwitch() {
  pressState = !pressState;
}
```

連射ボタン付きの 2 ボタンコントローラーとして認識されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/ef6c00d6-881b-c978-6079-304ec177a204.png)

方向キー+２ボタン以外の機能は HID キーボードとして振る舞う事で実現しています。

| ボタン | 機能 |
|:---:|:---|
| 十字キー | 移動 (X 軸 / Y 軸)|
| A | A ボタン |
| B | B ボタン |
| X | A ボタン連射 |
| Y | B ボタン連射 |
| L | 〔ESC〕 |
| R | 〔RETURN〕 |
| SELECT | 〔F1〕 |
| START | 〔F5〕 |


# おわりに

KONAMI のゲームが捗りますね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/8884c2e3-8391-40d1-c3af-771d9f0d01e7.png)

**「Destroy Them All」**