夏休みの自由研究:「右スティック」の軸について調べてみる(おまけでボタン番号割り当ても)

※間が開いてしまいましたが感想というかまとめを最後に書きました。

前置き

AIMSの新バージョンで「アナログ入力」にも真面目に対応しよう、ということで折角なんでアナログ2軸×左右スティック分くらいはとれるようにしたいなと思ったわけです。
しかし左スティックはXY軸で決め打ちでいいとしても右スティックがわからない。なんか昔は軸定義がバラバラでなかなか悲惨だったと聞くので、ここらで真面目に調べてみるかと思いました。ちょうどこんなゲームをつくることになった流れでゲームパッドをいくつか買い込んだので、こいつらの状況を調べてみることにします。
軸だけじゃなんなので物理的なボタンの位置と番号割り当ての違いも見てみようかなとか。

方法

各パッドをUSBポートに繋ぎ、コントロールパネルの「デバイスとプリンター」から「ゲーム コントローラーの設定」を呼び出し、対象パッドのプロパティで軸を調べます。とっても簡単。

実験環境

OS
Windows 7(x86)
メモリ
12GB*1
HDD
たくさん
VGA
それなりのGeForce
USB
マザーから延びてケースに出ているUSB2.0ポート
ドライバー類
記載ない限りOSが自動的にインストールする標準ドライバーを使う

被検体

実験に使ったのは以下のゲームパッド。

Logicool Rumble Gamepad F510

有線、振動付き、スイッチ切り替えでDInput、XInputどちらにも認識させられる。最近増えてきてますよね両対応品。
十字キーの扱いはMODEボタンでPOV、XY軸と切り替えることができる。

Logicool Wireless Gamepad F710

F510の無線版といってよさそう。無線で電池駆動な以外の諸元はほぼ同じ。DInput/XInput切り替えも可能。

ELECOM JC-U3613M

エレコムのDInput/XInput両対応パッド。連射設定ができる。
十字キーがPOVに固定。一頃昔の2Dゲームだとアナログスティックでデジタル操作をやるハメに……

iBUFFALO BSGP1204P

SAVIORというブランドのゲームパッド。PS3とPC両対応。PC接続時のみ、十字キーの扱いをPOVとXY軸で切り替えられる。

HORI HORIPAD3 PRO

ご存じホリのPS3用パッド。PS3用ではあるが、PCに挿しても動く。SIXAXISやDUALSHOCK3のように特殊なソフトで「起こす」必要もない。
斜め入力の感度設定や十字キーの傾き変更などユニークな機能満載。
十字キーがPOVに固定。もともとPC用途は想定されてないからしょうがないね。

結果

詰め込み詰め込みでちょっと見づらいですがご了承ください。
今回実験したパッドはすべてXBOX360配列、またはPlayStation配列(押し込める2軸アナログ2本、十字キー、正面4ボタン、LR2組、START/SELECT)の構成のため、XInput(XBOX360)でいう各ボタンの呼称、PS系でいう各ボタンの呼称、そしてその位置にあるボタンを押したときにコントロールパネルで光ったボタン番号、という組み合わせで表記しています。

F510

DInputモードとXInputモードそれぞれにおいて、MODEボタン消灯時(MODE消)とMODEボタン点灯時(MODE点)の2モードでの割り当ての変化を見た。

物理位置(XInput) 右X軸 右Y軸 左X軸 左Y軸 十字
左右
十字
上下
A B X Y LB RB LT RT LS RS BACK START ガイド
物理位置(PS) × L1 R1 L2 R2 L3 R3 SELECT START PS
反応した

or ボタン番号
D/MODE消 Z軸 Z回転 X軸 Y軸 POV左右 POV上下 2 3 1 4 5 6 7 8 11 12 9 10 なし
D/MODE点 Z軸 Z回転 POV左右 POV上下 X軸 Y軸 2 3 1 4 5 6 7 8 11 12 9 10 なし
X/MODE消 X回転 Y回転 X軸 Y軸 POV左右 POV上下 1 2 3 4 5 6 Z+ Z- 9 10 7 8 ガイド
X/MODE点 X回転 Y回転 POV左右 POV上下 X軸 Y軸 1 2 3 4 5 6 Z+ Z- 9 10 7 8 ガイド

DInputモードでは右スティックはZ軸とZ回転にアサイン、XInputだとX回転とY回転にアサインされるということで、モードにより右スティックの扱いが違うという結果に。

LTとRTはDInputではデジタルボタンの扱いだが、XInputだとアナログトリガーになる。ただし、DirectInputのAPIからXInputモードの本機を見た場合、両方で同じZ軸を共有しているため、LTとRTの同時押しを認識できない(つねに両方の押し込み量の差がZ軸の値に表れる)XInputのAPIでは両方の押し込み量を個別に取得できるので同時押しでも拾える。DInputのゲームにXInputモードの本機を使う理由は皆無じゃなかろうか?

F710

F510同様、DInputとXInputそれぞれのモードでMODE点灯、消灯各状態での割り当ての変化を見た。

物理位置(XInput) 右X軸 右Y軸 左X軸 左Y軸 十字
左右
十字
上下
A B X Y LB RB LT RT LS RS BACK START ガイド
物理位置(PS) × L1 R1 L2 R2 L3 R3 SELECT START PS
反応した

or ボタン番号
D/MODE消 Z軸 Z回転 X軸 Y軸 POV左右 POV上下 2 3 1 4 5 6 7 8 11 12 9 10 なし
D/MODE点 Z軸 Z回転 POV左右 POV上下 X軸 Y軸 2 3 1 4 5 6 7 8 11 12 9 10 なし
X/MODE消 X回転 Y回転 X軸 Y軸 POV左右 POV上下 1 2 3 4 5 6 Z+ Z- 9 10 7 8 ガイド
X/MODE点 X回転 Y回転 POV左右 POV上下 X軸 Y軸 1 2 3 4 5 6 Z+ Z- 9 10 7 8 ガイド

F510と同じ結果に。F510無線版と言い切ってよさそう。

JC-U3613M

モードとしてはDInputとXInputモードの変更のみ。

物理位置(XInput) 右X軸 右Y軸 左X軸 左Y軸 十字
左右
十字
上下
A B X Y LB RB LT RT LS RS BACK START ガイド
物理位置(PS) × L1 R1 L2 R2 L3 R3 SELECT START PS
反応した

or ボタン番号
DInput Z軸 Z回転 X軸 Y軸 POV左右 POV上下 3 4 1 2 5 6 7 8 9 10 11 12 13
XInput X回転 Y回転 X軸 Y軸 POV左右 POV上下 1 2 3 4 5 6 Z+ Z- 9 10 7 8 ガイド

DInput時の配列をF510/710と比べてみると軸はMODE消灯時のそれと同じであるが、
上面パッドボタンの番号振りがX→Y→A→Bの順で、BACKとSTART、LSRSの順番がF510/710とあべこべ。
XInputオン時はF510/710とまったく同じ配列。

BSGP1204P

MODE赤=MODEボタンが赤色に光っている状態、MODE緑=MODEボタンが緑色に光っている状態。
MODEボタンを押すことで赤と緑交互にモードが切り替わる。

物理位置(XInput) 右X軸 右Y軸 左X軸 左Y軸 十字
左右
十字
上下
A B X Y LB RB LT RT LS RS BACK START ガイド
物理位置(PS) × L1 R1 L2 R2 L3 R3 SELECT START PS
反応した

or ボタン番号
MODE赤 Z軸 Z回転 X軸 Y軸 POV左右 POV上下 3 2 4 1 7 8 5 6 11 12 9 10 なし
MODE緑 なし なし なし なし X軸 Y軸 3 2 4 1 7 8 5 6 11 12 9 10 なし

MODE緑の時はアナログスティックが2本とも無効になる潔さが際立つ。上面ボタン配列はPSで言うと△→○→×→□の順で時計回りに割り当て。L2R2がボタン番号的に先になっているのも若干目立つ。

HORIPAD3 PRO

物理位置(XInput) 右X軸 右Y軸 左X軸 左Y軸 十字
左右
十字
上下
A B X Y LB RB LT RT LS RS BACK START ガイド
物理位置(PS) × L1 R1 L2 R2 L3 R3 SELECT START PS
反応した

or ボタン番号
Z軸 Z回転 X軸 Y軸 POV左右 POV上下 2 3 1 4 5 6 7 8 11 12 9 10 13

同じPS3対応のBSGP1204Pと比べるとアナログ軸は一致するものの上面ボタンに違いがある。□→×→○→△、XBOX360ならXABYという順で番号が振ってある。L1R1L2R2の並び、L3R3とSELECT/STARTのボタン順はLogicoolパッドのDInputモードのそれと同じ。ただしこちらはガイドボタンに相当するPSボタンもボタン13として使用可能になっている。

まとめ

右スティックについては横=Z軸、縦=Z回転でほぼ間違いなさそうなんですが(XInputパッドをDirectInputで読むのはLT,RTが使い物にならないのでアレとして)、ボタンは見事にバラバラな結果でして、やはりゲームパッドを推奨するならキーコンフィグは最優先で実装すべきといえるでしょう。

あと地味な点ですが、方向ボタン(十字キー)がPOVに固定されてるパッドが増えて来ているのも気になります。デジタル入力を拾う2DゲーなどではPOVの読み取りにも対応しておくのがユーザーにとって優しいんじゃないでしょうか。

*1:PAE有効にして8GBをRAMディスクに使用

.NET用ラバーバンドクラス

C#でツール作るたび毎回毎回ラバーバンドで苦労してる気がしてきたので、クラスにまとめて使い回そうともくろんでみたり。

説明とかめんどくさいのでソース見てください。動作サンプルもつけてます。VisualStudio2012用になってますが自力でソリューション作り直せばVS2010でも.NET 4.5以前でもイケるんじゃないでしょうか(少なくともライブラリの方は)。

ピクチャボックス pictureBox1 をフォーム Form1 に置いてるものとして、
下記のようなコードで動かします。

public partial class Form1 : Form
{
    DNASoftwares.Rubberband rub;

    public Form1()
    {
        InitializeComponent();
        //新しいインスタンスの作成。引数は矩形初期値、ハンドルをつける場所、可動範囲の順
        rub = new DNASoftwares.Rubberband(new Rectangle(100, 100, 250, 250),
            DNASoftwares.Rubberband.HandlePosition.All,
            new Rectangle(Point.Empty, pictureBox1.ClientSize));
        toolStripComboBox1.SelectedIndex = 1;
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        //基本こんな感じで、if(メソッド) コンテナ.Refresh(); とすればいいです。
        //MouseDown イベントでは MouseDownEvent メソッドを呼びます
        if(rub.MouseDownEvent(e)) pictureBox1.Refresh();
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        Cursor c;
        //MouseMove イベントでは MouseMoveEvent メソッドを呼びます
        if (rub.MouseMoveEvent(e, out c)) pictureBox1.Refresh();
        // MouseMoveEvent は ラバーバンド上でのカーソル変更も支援できます。
        pictureBox1.Cursor = c;
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        //MouseUp イベントでは MouseUpEvent メソッドを呼びます
        if(rub.MouseUpEvent(e)) pictureBox1.Refresh();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.FillRectangle(new SolidBrush(this.BackColor),e.ClipRectangle);
        //Paint イベントでは PaintEvent メソッドを呼びます。背景クリア等は各自。
        rub.PaintEvent(e);
    }

// 以下省略