OpenRCFでゲームパッドを使う方法

本稿では，OpenRCFでゲームパッドを使う方法を解説していきます．

OpenRCFは下記のサイトからダウンロードできます．
https://mase.openrcf.site/

## ゲームパッドの入力方式

ゲームパッドには「X Input」と「Direct Input」の２つの方式があります．そして，本稿では「X Input」方式のゲームパッドを前提に説明を進めていきます．

Xbox360のコントローラは「X Input」で，プレイステーション5やNintendo Switchのコントローラは「Direct Input」と言われていますが，Amazonで売られている汎用ゲームパッドでは両者の切り替えができたりします．

Logicoolのゲームパッドでは，裏面に「X Input」と「Direct Input」を切り替えるボタンがありました．

## SharpDX.XInputのインストール

Visual Studio の「ツール」→「NuGetパッケージマネージャー」→「ソリューションのNuGetパッケージの管理」を開きます．
参照に「SharpDX.XInput」と入力し，SharpDX.XInputをインストールします．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310597/b0d1f731-b0ab-280c-c79f-b338c5ce18b3.png)

## ソースコード

まず，MainWindow.xaml.csファイルの冒頭に「using SharpDX.XInput;」を追加します．次に「public partial class MainWindow : Window ～」の上に，以下のGamePadクラスをコピペします．ここではGamePadクラスを別ファイルに分割せずに，MainWindow.xaml.csファイルに書いてしまいます（ソースコードを綺麗に整理するという意味では，別ファイルに分割した方が良いです）．

```ruby:MainWindow.xaml.cs
class GamePad
{
    public bool A, B, X, Y, R, L;
    public byte RT, LT;
    public bool Up, Down, Left, Right;
    public short LeftStickX, LeftStickY, RightStickX, RightStickY;
    public bool LeftStickDown, RightStickDown;

    private Controller controller = null;
    private Gamepad pad;
  
    public void Connect()
    {
        if (controller == null)
        {
            Controller[] controllers = new[] { new Controller(UserIndex.One), new Controller(UserIndex.Two), new Controller(UserIndex.Three), new Controller(UserIndex.Four) };

            for (int i = 0; i < controllers.Length; i++)
            {
                if (controllers[i].IsConnected)
                {
                    controller = controllers[i];
                    Console.WriteLine("GamePad is Connected.");
                    break;
                }
            }
        }
    }

    public void GetState()
    {
        if (controller == null)
        {
            Console.WriteLine("Error : GamePad is not connected.");
        }
        else
        {
            try
            {
                pad = controller.GetState().Gamepad;

                A = (pad.Buttons == GamepadButtonFlags.A);
                B = (pad.Buttons == GamepadButtonFlags.B);
                X = (pad.Buttons == GamepadButtonFlags.X);
                Y = (pad.Buttons == GamepadButtonFlags.Y);

                Up = (pad.Buttons == GamepadButtonFlags.DPadUp);
                Down = (pad.Buttons == GamepadButtonFlags.DPadDown);
                Left = (pad.Buttons == GamepadButtonFlags.DPadLeft);
                Right = (pad.Buttons == GamepadButtonFlags.DPadRight);

                R = (pad.Buttons == GamepadButtonFlags.RightShoulder);
                L = (pad.Buttons == GamepadButtonFlags.LeftShoulder);
                RT = pad.RightTrigger;
                LT = pad.LeftTrigger;

                LeftStickX = pad.LeftThumbX;
                LeftStickY = pad.LeftThumbY;
                LeftStickDown = (pad.Buttons == GamepadButtonFlags.LeftThumb);

                RightStickX = pad.RightThumbX;
                RightStickY = pad.RightThumbY;
                RightStickDown = (pad.Buttons == GamepadButtonFlags.RightThumb);
            }
            catch
            {
                Console.WriteLine("Gamepad is disconnected.");
                controller = null;
            }
        }
    }

    public void ConsoleWriteState()
    {
        Console.WriteLine("A:{0}, B:{1}, X:{2}, Y:{3}", A, B, X, Y);
        Console.WriteLine("R:{0}, L:{1}, RT:{2}, LT:{3}", R, L, RT, LT);
        Console.WriteLine("Up:{0}, Down:{1}, Left:{2}, Right:{3}", Up, Down, Left, Right);
        Console.WriteLine("LeftStickX:{0}, LeftStickY:{1}, LeftStickDown:{2}", LeftStickX, LeftStickY, LeftStickDown);
        Console.WriteLine("RightStickX:{0}, RightStickY:{1}, RightStickDown:{2}", RightStickX, RightStickY, RightStickDown);
    }
}


public partial class MainWindow : Window
{
    GamePad GamePad = new GamePad();
   
    void Setup()
    {   
        GamePad.Connect();
    }

    void Button1_Click(object sender, RoutedEventArgs e)
    {
        GamePad.GetState();
        GamePad.ConsoleWriteState();
    }

    void GamePadKeyEvent()
    {
        GamePad.GetState();

        if (GamePad.A)
        {
            Console.WriteLine("A");
        }
        else if (GamePad.B)
        {
            Console.WriteLine("B");
        }
    }

    void Button2_Click(object sender, RoutedEventArgs e)
    {
        Parallel.RunEndless(GamePadKeyEvent, 50);
    }
}

```
ここではSetup関数にGamePad.Connect()を記述したので，先にゲームパッドをPCに接続している必要があります．ボタン１を押すと各ボタン・ジョイスティックの状態が取得され，コンソールに表示されます．ボタン２を押すとGamePadKeyEvent()という関数が50ms周期で並列処理されるようになります．つまり，ボタン２を押してからは自動でゲームパッドの状態が取得され続けるようになり，if文の中身も実行されます．if文の条件分岐ではA,Bが押されているか否かしか反映させていませんが，他のボタンやジョイスティックの状態も取得できています．それらは以下の変数に格納されているので，必要に応じて活用してください．
```
public bool A, B, X, Y, R, L;
public byte RT, LT;
public bool Up, Down, Left, Right;
public short LeftStickX, LeftStickY, RightStickX, RightStickY;
public bool LeftStickDown, RightStickDown;
```
## 接続できない場合

上記のコードを実行してもゲームパッドに接続できなかった場合，そのゲームパッドは恐らく「Direct Input」方式です．対策としては，

- SharpDX.DirectInputというライブラリを使う．
- Amazonなどで「X Input」のゲームパッドを買う（2000円くらい）．
- 「Direct Input」を「X Input」に変換するソフトを使う．

などが挙げられます．