DirectXでのパッド入力について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sadora3
記事: 175
登録日時: 11年前

DirectXでのパッド入力について

#1

投稿記事 by sadora3 » 7年前

以下のようなプログラムを組み、複数のパッドを用いて、押されたボタンがどの番号なのかを確認するプログラムを作りました。
しかし、テスト結果を見て、パッドによりボタンの番号の振り方が違うことが分かりました。
そこで、質問なのですが、どうやったらボタンの番号を統一できるのでしょうか?
例えば、PS2のコントローラーの▲に当たる場所のボタンを押したとき、全てのパッドが0番を返してくれるようにしたいということです。

もしくは、DirectXでのパッド入力より、パッド入力が出来る他のライブラリなどをお借りした方がいいのでしょうか?
もし、お借りした方がいい場合、どのライブラリをお借りすればよろしいのでしょうか?

あと、もう一つ質問があるのですが、このパッドクラスはWinMain関数の最後で、ちゃんとデストラクタを実行してくれますよね?

↓追記
OS:Windows10
コンパイラ:VisualStudio2010
言語:C++
ライブラリ:DirectX SDK (June 2010)

Main.cpp

コード:

//インクルード
#include"d3dx9.h"
#include"Monitoring.h"
#include"Pad.h"

#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
#pragma comment (lib, "dxguid.lib")
#pragma comment (lib, "winmm.lib")
#pragma comment (lib, "dinput8.lib")

//定数定義
#define SCREEN_WIDTH (800)
#define SCREEN_HEIGHT (600)
#define CLASS_NAME "AppClass"
#define WINDOW_NAME "DirectX"

//グローバル変数
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
int g_nCountFPS = 0;

//プロトタイプ宣言
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HRESULT Init(HINSTANCE hInstance, HWND hWnd, BOOL bWindow);
void Uninit();
void Update();
void Draw();

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
	WNDCLASSEX wcex = {	sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0, 0, hInstance, NULL, LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, CLASS_NAME, NULL	};
	HWND hWnd;
	MSG msg;

	RegisterClassEx(&wcex);

	hWnd = CreateWindowEx(0, CLASS_NAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, (SCREEN_WIDTH + GetSystemMetrics(SM_CXDLGFRAME) * 2), (SCREEN_HEIGHT + GetSystemMetrics(SM_CXDLGFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION)), NULL, NULL, hInstance, NULL);

	if(FAILED(Init(hInstance, hWnd, TRUE))){	return -1;	}

	DWORD dwExecLastTime;
	DWORD dwFPSLastTime;
	DWORD dwCurrentTime;
	DWORD dwFrameCount;

	timeBeginPeriod(1);
	dwExecLastTime = dwFPSLastTime = timeGetTime();
	dwCurrentTime = dwFrameCount = 0;

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	while(1){
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0){
			if(msg.message == WM_QUIT){
				break;
			}else{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}else{
			dwCurrentTime = timeGetTime();
			if((dwCurrentTime - dwFPSLastTime) >= 500){
				g_nCountFPS = (dwFrameCount * 1000) / (dwCurrentTime - dwFPSLastTime);
				dwFPSLastTime = dwCurrentTime;
				dwFrameCount = 0;
			}
			if((dwCurrentTime - dwExecLastTime) >= (1000/60)){
				dwExecLastTime = dwCurrentTime;
				Update();
				Draw();
				dwFrameCount++;
			}
		}
	}

	UnregisterClass(CLASS_NAME, wcex.hInstance);
	Uninit();
	timeEndPeriod(1);
	return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
	switch(uMsg){
	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	case WM_KEYDOWN:
		switch(wParam){
		case VK_ESCAPE:
			DestroyWindow(hWnd);
			break;
		}
		break;

	case WM_CLOSE:
		DestroyWindow(hWnd);
		break;

	default:
		break;
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

HRESULT Init(HINSTANCE hInstance, HWND hWnd, BOOL bWindow){
	D3DPRESENT_PARAMETERS d3dpp;
	D3DDISPLAYMODE d3ddm;

	g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if(g_pD3D == NULL){
		return E_FAIL;
	}

	if(FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm))){
		return E_FAIL;
	}

	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferWidth = SCREEN_WIDTH;
	d3dpp.BackBufferHeight = SCREEN_HEIGHT;
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.BackBufferCount = 1;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed = bWindow;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	if(bWindow){
		d3dpp.FullScreen_RefreshRateInHz = 0;
		d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	}else{
		d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	}

	if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice))){
		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice))){
			if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice))){
				return E_FAIL;
			}
		}
	}

	g_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	g_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	g_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
	g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	g_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	g_pD3DDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	g_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

	MONITORING::Init(g_pD3DDevice);
	PAD::Init(hInstance, hWnd);

	return S_OK;
}

void Update(){
	PAD::Update();

	for(int i = 0; i < 100; i++){
		if(PAD::Push(i)){
			MONITORING::SetStr("InputButton:%d\n", i);
		}
	}

}

void Draw(){
	g_pD3DDevice->Clear(0, NULL, (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER), D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0);

	if(SUCCEEDED(g_pD3DDevice->BeginScene())){
		MONITORING::SetStr("LX:%d\n", PAD::PositionX());
		MONITORING::SetStr("LY:%d\n", PAD::PositionY());
		MONITORING::SetStr("RX:%d\n", PAD::PositionRX());
		MONITORING::SetStr("RY:%d\n", PAD::PositionRY());
		MONITORING::SetStr("RgdwPOV:%d\n", PAD::RgdwPOV(0));

		MONITORING::Draw();

		g_pD3DDevice->EndScene();
	}

	g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}

void Uninit(){


	if(g_pD3DDevice != NULL){
		g_pD3DDevice->Release();
		g_pD3DDevice = NULL;
	}

	if(g_pD3D != NULL){
		g_pD3D->Release();
		g_pD3D = NULL;
	}
}
Pad.cpp

コード:

#include"Pad.h"

LPDIRECTINPUT8 PAD::pDInput;
DIJOYSTATE PAD::joyState[MAX_CONTROLER];
DIJOYSTATE PAD::joyStatePrev[MAX_CONTROLER];
LPDIRECTINPUTDEVICE8 PAD::pDIDevJoypad[MAX_CONTROLER];
int PAD::nJoypadNum;
BYTE PAD::joyStateTrigger[MAX_CONTROLER][32];

void PAD::Init(HINSTANCE hInst, HWND hWnd){
	pDInput = NULL;
	nJoypadNum = 0;

	if(!pDInput){
		DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&pDInput, NULL);
	}

	int nLoop;

	for(nLoop = 0; nLoop < MAX_CONTROLER; nLoop++)
		pDIDevJoypad[nLoop] = NULL;

	if(FAILED(pDInput->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoyCallback, NULL, DIEDFL_ATTACHEDONLY)))
		return ;

	for(nLoop = 0; nLoop < MAX_CONTROLER; nLoop++){
		if(pDIDevJoypad[nLoop] == NULL)
			continue;

		if(FAILED(pDIDevJoypad[nLoop]->SetDataFormat(&c_dfDIJoystick)))
			return ;

		if(FAILED(pDIDevJoypad[nLoop]->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND)))
			return ;

		pDIDevJoypad[nLoop]->Acquire();
	}

	return ;
}

PAD::~PAD(){
	for(int nLoop = 0; nLoop < MAX_CONTROLER; nLoop++){
		if(pDIDevJoypad[nLoop]){
			pDIDevJoypad[nLoop]->Release();
			pDIDevJoypad[nLoop] = NULL;
		}
	}

	if(pDInput){
		pDInput->Release();
		pDInput = NULL;
	}
}

void PAD::Update(){
	int nLoop;

	for(nLoop = 0; nLoop < MAX_CONTROLER; nLoop++){
		joyStatePrev[nLoop] = joyState[nLoop];

		if(pDIDevJoypad[nLoop]){
			if(FAILED(pDIDevJoypad[nLoop]->GetDeviceState(sizeof(DIJOYSTATE), &joyState[nLoop])))
				pDIDevJoypad[nLoop]->Acquire();
		}

		for(int i = 0; i < 32; i++){
			if(joyState[nLoop].rgbButtons[i] & 0x80 && !(joyStatePrev[nLoop].rgbButtons[i] & 0x80)){
				joyStateTrigger[nLoop][i] = 0x80;
			} else {
				joyStateTrigger[nLoop][i] = 0x00;
			}
		}
	}
}

BOOL CALLBACK PAD::EnumJoyCallback(const DIDEVICEINSTANCE* lpddi, VOID* pvRef){
	DIDEVCAPS	diDevCaps;

	if(FAILED(pDInput->CreateDevice(lpddi->guidInstance, &pDIDevJoypad[nJoypadNum], NULL)))
		return DIENUM_CONTINUE;

	diDevCaps.dwSize = sizeof(DIDEVCAPS);
	if(FAILED(pDIDevJoypad[nJoypadNum]->GetCapabilities(&diDevCaps))){
		if(pDIDevJoypad[nJoypadNum])
			pDIDevJoypad[nJoypadNum]->Release();
		pDIDevJoypad[nJoypadNum] = NULL;
		return DIENUM_CONTINUE;
	}

	nJoypadNum++;
	if(nJoypadNum == MAX_CONTROLER)
		return DIENUM_STOP;
	else
		return DIENUM_CONTINUE;
}

bool PAD::Push(int button){
	return (joyState[0].rgbButtons[button] & 0x80) ? true : false;
}

bool PAD::Tri(int button){
	return (joyStateTrigger[0][button] & 0x80) ? true : false;
}

LONG PAD::PositionX(){
	return joyState[0].lX;
}

LONG PAD::PositionY(){
	return joyState[0].lY;
}

LONG PAD::PositionRX(){
	return joyState[0].lRx;
}

LONG PAD::PositionRY(){
	return joyState[0].lRy;
}

LONG PAD::Slider(int number){
	return joyState[0].rglSlider[number];
}

DWORD PAD::RgdwPOV(int number){
	return joyState[0].rgdwPOV[number];
}
Pad.h

コード:

#pragma once

#define DIRECTINPUT_VERSION (0x0800)
#include"dinput.h"

#define MAX_CONTROLER (2)

class PAD{
private:
	static LPDIRECTINPUT8 pDInput;
	static DIJOYSTATE joyState[MAX_CONTROLER];
	static DIJOYSTATE joyStatePrev[MAX_CONTROLER];
	static LPDIRECTINPUTDEVICE8 pDIDevJoypad[MAX_CONTROLER];
	static int nJoypadNum;
	static BYTE joyStateTrigger[MAX_CONTROLER][32];

	static BOOL CALLBACK EnumJoyCallback(const DIDEVICEINSTANCE* lpddi, VOID* pvRef);
public:
	~PAD();
	static void Init(HINSTANCE hInst, HWND hWnd);
	static void Update();

	static bool Push(int button);
	static bool Tri(int button);
	static LONG PositionX();
	static LONG PositionY();
	static LONG PositionRX();
	static LONG PositionRY();
	static LONG Slider(int number);
	static DWORD RgdwPOV(int number);
};
●テスト結果
※ボタン配置はPS2コントローラーのもの
・パッド1(Logicool)
△:3
〇:1
×:0
□:2
L1:4
L2:反応なし
R1:5
R2:反応なし
L3:8
R3:9
スタート:6
セレクト:7
--------------------------
十字ボタン↑:0
十字ボタン→:9000
十字ボタン↓:18000
十字ボタン←:27000
左スティック:反応あり
右スティック:反応あり

・パッド2(ELECOM)
△:1
〇:3
×:2
□:0
L1:4
L2:6
R1:5
R2:7
L3:8
R3:9
スタート:10
セレクト:11
--------------------------
十字ボタン↑:0
十字ボタン→:9000
十字ボタン↓:18000
十字ボタン←:27000
左スティック:反応あり
右スティック:反応なし(常に値が0)

・パッド3(PS2コントローラ )
△:0
〇:1
×:2
□:3
L1:6
L2:4
R1:7
R2:5
L3:10
R3:11
スタート:8
セレクト:9
--------------------------
十字ボタン↑:0
十字ボタン→:9000
十字ボタン↓:18000
十字ボタン←:27000
左スティック:反応あり
右スティック:反応なし(常に値が0)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: DirectXでのパッド入力について

#2

投稿記事 by みけCAT » 7年前

sadora3 さんが書きました:そこで、質問なのですが、どうやったらボタンの番号を統一できるのでしょうか?
例えば、PS2のコントローラーの▲に当たる場所のボタンを押したとき、全てのパッドが0番を返してくれるようにしたいということです。
私は知りませんが、予想では自動では無理な気がします。
そのためにキーコンフィグがあるのでしょう。
sadora3 さんが書きました:あと、もう一つ質問があるのですが、このパッドクラスはWinMain関数の最後で、ちゃんとデストラクタを実行してくれますよね?
いいえ。
WinMain関数ではPADクラスのインスタンスを生成していないし、グローバルなPADクラスのインスタンスも無さそうなので、当然デストラクタは実行されないはずです。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

sadora3
記事: 175
登録日時: 11年前

Re: DirectXでのパッド入力について

#3

投稿記事 by sadora3 » 7年前

キーコンフィグですか・・・プレイヤーに一手間かけさせてしまうのは、気が引けますが、それしか方法はありませんかね。

デストラクタは実行されてないのですか。
もう一つ追加で質問がございます。
パッドクラスのメンバにUninit関数を持たせ、デストラクタの内容をUninit関数に移し、Uninit関数をWinMain関数で呼び出してあげることでこの問題は解決されるのですが、いちいちUninit関数を呼び出すのが面倒です・・・。
そこで、デストラクタをWinMain関数の最後で呼び出す方法は、何かないでしょうか?
デストラクタ以外でもいいです。何かWinMain関数の最後でデストラクタの内容を、自動で実行できるような方法はございませんか?

追記
やっぱりもう一つ質問がございます。
このデストラクタの内容は、呼び出す必要ってあるのでしょうか・・・。

Tepp
記事: 13
登録日時: 7年前
住所: フォッサマグナ
連絡を取る:

Re: DirectXでのパッド入力について

#4

投稿記事 by Tepp » 7年前

sadora3 さんが書きました:このデストラクタの内容は、呼び出す必要ってあるのでしょうか・・・。
あります。各種Releaseを呼んであげないと、DirectInput8内部で確保しているメモリが解放されません。
sadora3 さんが書きました:デストラクタ以外でもいいです。何かWinMain関数の最後でデストラクタの内容を、自動で実行できるような方法はございませんか?
デストラクタ自体はインスタンスの破棄時に呼ばれるものなので、今回のようにインスタンスがなければ、呼ばれません(呼ぶものがありません)。

UnInit関数が面倒といいますが、今回の場合、それが一番ベターな方法だと思います。
こういう解放の処理は、生成した順番とは逆の順番に破棄するのがお決まりで、
自動的にやる方法だと、その順番が制御できないのです。
オフトピック
個人的にはWinMainの最後じゃなくて、UnInit関数の最初とかで呼びたい
おすすめはしませんが、スマートポインタ的な以下の方法とかもあります。

コード:

class Pad{
public:
	static void Uninit(){ /* 終了処理*/ }
};

/**
 * Pad自動開放のためのクラス
 * 破棄されるときにPad::Uninitを呼ぶ
 */
class PadFinalizer{
public:
	~PadFinalizer()
	{
		Pad::Uninit();
	}
};

int main()
{
	// mainを抜けるとPadFinalizerのデストラクタが呼ばれてPad::Initが走る
	PadFinalizer padFinalizer;
	return 0;
}

sadora3
記事: 175
登録日時: 11年前

Re: DirectXでのパッド入力について

#5

投稿記事 by sadora3 » 7年前

なるほどです。
うーん。やはりUninit関数が最も適していますか・・・。では、Uninit関数に移すとします。
勉強になりました。
回答してくれたお二方、本当にありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る