Windowsにはゲーム用のコントローラとしてジョイスティック(ゲームパッドとも呼ばれます)を使用することが出来ます。
ジョイスティックを使用することでPCに不慣れな人でも、直感的な操作で入力を行う事が可能です。ジョイスティックを制御するプログラムを書くにはDirectXを使用することが多いのですが、残念ながらC#(というか.Net Framework)を使用したジョイスティック制御プログラムの情報は少ないです。
そこで今回は、VisualStudio 2010で、C#からDirectXのDirectInputの機能を使用して、ジョイスティックを利用できるようにします。
開発環境
確認に使用した環境は以下の通りです。OS:
Windows7 x64
IDE:
VisualStidio 2010 Professional
DirectX SDK:
DirectX SDK(Jun 2010)
ジョイスティック(ゲームパッド);
今回は手元に有った,エレコム製のスーファミ風コントローラを利用

ELECOM i-revo推奨レトロ風USBゲームパッド ホワイト JC-U1608TWH
作業手順
大まかな作業の流れは以下の通りです。DirectX SDKをインストールする VisualStudioでプロジェクトを作成する DirectInputのDLLを参照設定する プログラムを作成する |
DirectX SDKをインストールする
まずは、以下のURLよりDirectXのSDKをダウンロードし、インストールします。(DirectX Runteimeではないので注意してください)
Download: DirectX SDK – (June 2010) – Microsoft Download Center – Download Details
64bit環境で開発している場合、SDKのインストールでエラーが出る場合があります。
この際は、以下の記事を参考にしてください。
→ DirectX SDKインストール時に”S1023エラー”が出る時の対処法
VisualStudioでプロジェクトを作成する
SDKがインストールできたら、Visual Studio2010でプロジェクトを作成します。Windowsフォームアプリケーションを指定します。。
また、.Net Frameworkのバージョンが4.0になっていたら3.5にしてください。
(詳細は後述しますが、4.0だと実行時にエラーが発生します)

DirectInputのDLLを参照設定する
プロジェクトの参照設定を右クリックして、参照の追加を選択します。
一覧より、以下のコンポーネントを追加してください。
Microsoft.DirectX Microsoft.DirectX.DirectInput |

もし、参照設定の画面にMicrosoft.DirectXが表示されない場合はファイルから以下のDLLを直接指定します。これらは、フォルダ名からも分かるようにDirectXのマネージドコード用DLLです。
C:\Windows\Microsoft.NET\DirectX for Managed Code\1.0.2902.0\Microsoft.DirectX.dll C:\Windows\Microsoft.NET\DirectX for Managed Code\1.0.2902.0\Microsoft.DirectX.DirectInput.dll |
設定後、参照設定の中に項目が追加されればOKです。

プログラムを作成する
次にプログラムを作成します。今回はWinFormsによるGUI画面で、以下のレイアウトにしました。

最近のゲーム用ジョイスティックはアナログスティックや、スライダ、POVハット、フォースフィードバックなど色々な機能がありますが、今回はサンプルなのでシンプルに十字キーとボタンの押下状態を取れるだけのプログラムとします。
他の入出力デバイスと同様に、ジョイスティックを使用するには、1:初期設定と,2:データの取得という2ステップが必要です。
まずは、初期設定です。
元にお約束として、以下のusing定義を追加します。
using Microsoft.DirectX.DirectInput; |
ここでエラーが出る場合は、参照設定が行えているか再確認してください。
次にデバイスの初期化を行います。
Device joystick = null; private void button1_Click( object sender, EventArgs e ) { DeviceList devList; // ゲームコントローラのデバイス一覧を取得 devList = Manager.GetDevices( DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly ); // 全てのコントローラを列挙 foreach( DeviceInstance dev in devList ) { joystick = new Device( dev.InstanceGuid ); joystick.SetCooperativeLevel( this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive ); // 最初に見つかったジョイスティックを操作対象とする break; } joystick.SetDataFormat(DeviceDataFormat.Joystick); // デバイスに対するアクセス権をとる joystick.Acquire(); txtLog.AppendText( "名称: " + joystick.DeviceInformation.ProductName + Environment.NewLine ); // コントローラの軸の数 txtLog.AppendText( "軸の数: " + joystick.Caps.NumberAxes + Environment.NewLine ); // コントローラに有るボタンの数 txtLog.AppendText( "ボタンの数: " + joystick.Caps.NumberButtons + Environment.NewLine ); // PoV hatの数 txtLog.AppendText( "PoVハットの数: " + joystick.Caps.NumberPointOfViews + Environment.NewLine ); } |
PCに接続されているジョイスティックのデバイスはMicrosoft.DirectX.DirectInput名前空間に有るManagerクラスのGetDevices()メソッドを使用します。戻り値でデバイス一覧が手に入るので、この値をforeachで繰り返します。今回は最初に検出したデバイスを使用します。
生成されたDeviceオブジェクトに対して、SetCooperativeLevel()で、このデバイスに対する権限を取得します。
今回は2つの指定が行われており、それぞれ以下の意味を持っています。
CooperativeLevelFlags.Background ウィンドウがアクティブでなくても(=裏に隠れていても)、ジョイスティックの状態を取得可能にします。 CooperativeLevelFlags.NonExclusive ジョイスティックに対して、排他的ではないアクセスを行います。 これを指定すると、同一のデバイスにアクセスしているほかのアプリの動作を妨げません。 |
その後、Acquire()でアクセス権の取得を行い、アクセス出来るようになったら各種情報を取得します。
NumberAxesで返される軸の数は、例えば十字キーなら上下/左右の2軸となります。
PoVハットというのは、8方向のスイッチで、よくフライトシミュレーター用のジョイスティックの先っちょについているモノです。”POV”はPoint Of Viewの略でこの装置が主にゲームの視点操作に使われていることが由来となっています。
初期化が終わったら、キー入力状態の取得です。
今回はTimerコントロールを利用して、一定時間周期でポーリングする方式で作成しました。
private void timer1_Tick( object sender, EventArgs e ) { // デバイス未決定時は何もしない if ( joystick == null ) { return; } try { // コントローラの状態をポーリングで取得 joystick.Poll(); JoystickState state = joystick.CurrentJoystickState; //----------------------- //十字キーの状態を出力 //----------------------- txtState.Text = "X=" + state.X + " Y=" + state.Y; //----------------------- // ボタンの状態を出力 //----------------------- int count = 0; StringBuilder tmpBuff = new StringBuilder(); foreach ( byte button in state.GetButtons() ) { if ( count++ >= joystick.Caps.NumberButtons ) { break; // ボタンの数分だけ状態を取得したら終了 } tmpBuff.Append( button.ToString() + ", " ); } txtButton.Text = tmpBuff.ToString(); } catch ( Exception ex ) { txtLog.AppendText( ex.Message + Environment.NewLine ); } } |
ボタンの状態は、初期化処理で取得したDeviceオブジェクトから取得します。
十字キーの状態はCurrentJoystickStateプロパティから、ボタンはGetButtons()メソッドの戻り値から判断できます。
今回は説明しませんが、他の入力スイッチやフォースフィードバック機能についても、対応するプロパティ/メソッドがあります。詳細はクラス仕様を確認して下さい。
十字キーの状態はCurrentJoystickStateのX,Yから取得でき、値は0から65535でとなります。デジタル式のOn/Off十字キーなら0,32768,65535のどれかの値が返されます。
ボタンに関しては、ジョイスティックによってボタンの数が異なるため、配列として値が返されます。返される配列のサイズは128ですが、有効な値が入っているのは配列内の最初のjoystick.Caps.NumberButtons個分のみです。取得した値が0だったらボタンが押されておらず、128だったら押されていると判定できます。
あと、おまけ機能として、コントロールパネルの画面を表示させるボタンを追加します。
private void button2_Click( object sender, EventArgs e ) { // デバイス未決定時は何もしない if ( joystick == null ) { return; } // コントロールパネルを開く joystick.RunControlPanel(); } |
RunControlPanel()メソッドをコールする事で、コントロールパネルのウィンドウを表示できます。

実行結果は以下の通りです。

プログラムの実行時、以下のようにFileLoadExceptionが出る場合は、.NetrFrameworkのバージョンを4.0から3.5に落としてください。


iBUFFALO USBゲームパッド 8ボタン スーパーファミコン風 グレー BSGP801GY
関連記事
[…] [C#]DirectInputでジョイスティック(ゲームパッド)を使用するWindowsにはゲーム用のコントローラとしてジョイスティック(ゲームパッドとも呼ばれます)を使用することが出…nanoappli.com […]
txtKogとtxtButtonが名前空間にありませんというエラーが出ます