コントローラを使う

DirectX の LPDIRECTINPUT8 でコントローラ(Joystick)を使って図形を動かします。
マウスやキーボードと違い、デバイスを列挙して操作するデバイスを選択しなければなりません。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. #include と #define と #pragma です。
    DirectInput を使うときは dinput.h を取り込んで、dinput8.lib と dxguid.lib をリンクして下さい。
    Direct X9 でも DIRECTINPUT8 が使われています。
    g_pDInput が DirectInput の Object で、g_pDIDev がコントローラのデバイスです。
    g_bActive はウインドウのアクティブ状態を示すフラグです。
    Pos, WPos は図形を描画する座標と直前に描画した座標です。
    g_diDevCaps は列挙したデバイスからジョイスティックの能力を調べる領域です。
        /*******************************************/
        /*★ Direct Input  Controller    前田 稔 ★*/
        /*******************************************/
        #define     NAME    "DirectX8 Input Controller"
        #include    <windows.h>
        #include    <dinput.h>
        #pragma     comment(lib,"dinput8.lib")
        #pragma     comment(lib,"dxguid.lib")
        #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } }
    
        //DirectInput Object
        LPDIRECTINPUT8        g_pDInput = NULL;     // DirectInput
        LPDIRECTINPUTDEVICE8  g_pDIDev  = NULL;     // DirectInput デバイス
    
        //Global Area
        HWND                  g_hWnd;
        HINSTANCE             g_Inst;
        bool                  g_bActive = FALSE;    // ウインドウのアクティブ状態
        POINT                 Pos,WPos;
        DIDEVCAPS             g_diDevCaps;          // ジョイスティックの能力
        
  2. WinMain() ではウインドウを生成して DirectInput の初期化を行います。
    WinMain() 関数はキーボードの時と同じです。
  3. DirectInput の初期化を行う関数です。
    g_pDInput に DirectInput の Object を作成します。
    コントローラのデバイスを列挙して使用するデバイスを選択して g_pDIDev に設定します。
    列挙したデバイスは EnumJoysticksCallback() に渡されます。
    コントローラのデータ・フォーマットを設定します。
    コントローラの協調モードを設定します。
    コールバック関数を使って各軸のモードを設定します。
    Acquire() で入力の制御を開始します。
        // DirectInput 初期化
        HRESULT  InitDInput(void)
        {   HRESULT hr;
    
            // DirectInputの作成
            hr = DirectInput8Create(g_Inst, DIRECTINPUT_VERSION, 
                                    IID_IDirectInput8, (void**)&g_pDInput, NULL);
            if (FAILED(hr)) 
            {   MessageBox(NULL,"DirectInput8オブジェクトの作成に失敗","Direct Input Error",MB_OK);
                return hr;
            }
            // デバイスを列挙して作成
            hr = g_pDInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback,
                                        NULL, DIEDFL_ATTACHEDONLY);
            if (FAILED(hr) || g_pDIDev==NULL)
            {   MessageBox(NULL,"DirectInputDevice8オブジェクトの作成に失敗","Direct Input Error",MB_OK);
                return hr;
            }
            // データ形式を設定
            hr = g_pDIDev->SetDataFormat(&c_dfDIJoystick2);
            if (FAILED(hr))
            {   MessageBox(NULL,"c_dfDIJoystick2形式の設定に失敗","Direct Input Error",MB_OK);
                return hr;
            }
            // 協調モードを設定(フォアグラウンド&非排他モード)
            hr = g_pDIDev->SetCooperativeLevel(g_hWnd,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
            if (FAILED(hr))
            {   MessageBox(NULL,"フォアグラウンド&非排他モードの設定に失敗","Direct Input Error",MB_OK);
                return hr;
            }
            // コールバック関数を使って各軸のモードを設定
            hr = g_pDIDev->EnumObjects(EnumAxesCallback, NULL, DIDFT_AXIS);
            if (FAILED(hr))
            {   MessageBox(NULL,"軸モードの設定に失敗","Direct Input Error",MB_OK);
                return hr;
            }
            // 入力制御開始
            g_pDIDev->Acquire();
            return S_OK;
        }
        
  4. ジョイスティックを列挙する CALLBACK 関数です。
    使用するデバイスが見つかれば g_pDIDev に設定して、DIENUM_STOP をリターンします。
        // ジョイスティックを列挙する関数
        BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
        {   HRESULT hr;
    
            // 列挙されたジョイスティックへのインターフェイスを取得する。
            hr = g_pDInput->CreateDevice(pdidInstance->guidInstance, &g_pDIDev, NULL);
            if (FAILED(hr))     return DIENUM_CONTINUE;
            // ジョイスティックの能力を調べる
            g_diDevCaps.dwSize = sizeof(DIDEVCAPS);
            hr = g_pDIDev->GetCapabilities(&g_diDevCaps);
            if (FAILED(hr))
            {   // ジョイスティック能力の取得に失敗
                SAFE_RELEASE(g_pDIDev);
                return DIENUM_CONTINUE;
            }
            return DIENUM_STOP;
        }
        
  5. ジョイスティックの軸を列挙する CALLBACK 関数です。
    最小値を -1000 に、最大値を +1000 に設定します。
        // ジョイスティックの軸を列挙する関数
        BOOL CALLBACK EnumAxesCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
        {   HRESULT hr;
    
            // 軸の値の範囲を設定(-1000~1000)
            DIPROPRANGE diprg;
            ZeroMemory(&diprg, sizeof(diprg));
            diprg.diph.dwSize       = sizeof(diprg); 
            diprg.diph.dwHeaderSize = sizeof(diprg.diph); 
            diprg.diph.dwObj        = lpddoi->dwType;
            diprg.diph.dwHow        = DIPH_BYID;
            diprg.lMin  = -1000;
            diprg.lMax  = +1000;
            hr = g_pDIDev->SetProperty(DIPROP_RANGE, &diprg.diph);
            if (FAILED(hr))     return DIENUM_STOP;
            return DIENUM_CONTINUE;
        }
        
  6. コントローラを調べる KeyCheck() 関数です。
    △ボタン(○ボタン)でプログラムを終了します。
    dims.lX, dims.lY がコントローラの上下左右ボタンで、最小値(最大値)が設定されます。
        // Controller 入力
        void  KeyCheck()
        {   DIJOYSTATE2 dijs;
            HRESULT     hr;
    
            hr= g_pDIDev->GetDeviceState(sizeof(DIJOYSTATE2), &dijs);
            if (SUCCEEDED(hr))
            {   if (dijs.rgbButtons[0] & 0x80)  PostMessage(g_hWnd,WM_CLOSE,0,0);   //△ボタン
                if (dijs.rgbButtons[1] & 0x80)  PostMessage(g_hWnd,WM_CLOSE,0,0);   //○ボタン
                if (dijs.lX)    Pos.x+= dijs.lX/1000;
                if (dijs.lY)    Pos.y+= dijs.lY/1000;
            }
            else if (hr==DIERR_INPUTLOST)  g_pDIDev->Acquire();
        }
        
  7. Pos の座標に図形(円)を描画する Draw(void) 関数はキーボードの時と同じです。
  8. 入力制御を終了して領域を開放する Cleanup() 関数もキーボードの時と同じです。
  9. ウインドウの CALLBACK 関数もキーボードの時と同じです。

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

前田稔(Maeda Minoru)の超初心者のプログラム入門

超初心者のプログラム入門(DirectX9 game program)

超初心者のプログラム入門(DirectX10 game program)