DirectInputライブラリ構築 仕上げ編

最初に基盤を作り、続いてフォースフィードバックに対応させた。
今回はボタン押下状態の取得をより簡単に行えるようにし、
各設定の簡単な部分を変更できるようにする。


・その前に・・・
  エフェクト(FFB)が再生されている途中でMagnitude等を変更する場合のコードを少し変更。
  GetEffectStatusで簡単に再生中かどうかが取得できるので、
  これを使って判定する。

	DWORD dwFlag;

	m_veclpdiEffect[i][nCnt]->GetEffectStatus ( &dwFlag );

	if ( dwFlag & DIEGES_PLAYING )
		m_veclpdiEffect[i][nCnt]->Stop ( );

	m_veclpdiEffect[i][nCnt]->SetParameters ( &diEffect, DIEP_TYPESPECIFICPARAMS );

	if ( dwFlag & DIEGES_PLAYING )
		m_veclpdiEffect[i][nCnt]->Start ( 1, 0 );


  これでエフェクトが再生中でも正常にMagnitude等が変更できる。




・ボタンの押下状態を手軽に取得
  今回採用したのはDIJOYSTATEであるからして、
  X/Y/Z軸やPOV等については直接取得して参照するだけで十分。
  ボタンが BYTE rgbButtons[32] なので、いちいち 0x80 でANDするのはめんどくさい。
  そこで、まず定数を用意して・・・

	enum {
		DXJOY_BTN1 = 0x00000001,
		DXJOY_BTN2 = 0x00000002,
		DXJOY_BTN3 = 0x00000004,
		DXJOY_BTN4 = 0x00000008,
		DXJOY_BTN5 = 0x00000010,
		DXJOY_BTN6 = 0x00000020,
		DXJOY_BTN7 = 0x00000040,
		DXJOY_BTN8 = 0x00000080,
		DXJOY_BTN9 = 0x00000100,
		DXJOY_BTN10 = 0x00000200,
		DXJOY_BTN11 = 0x00000400,
		DXJOY_BTN12 = 0x00000800,
		DXJOY_BTN13 = 0x00001000,
		DXJOY_BTN14 = 0x00002000,
		DXJOY_BTN15 = 0x00004000,
		DXJOY_BTN16 = 0x00008000,
		DXJOY_BTN17 = 0x00010000,
		DXJOY_BTN18 = 0x00020000,
		DXJOY_BTN19 = 0x00040000,
		DXJOY_BTN20 = 0x00080000,
		DXJOY_BTN21 = 0x00100000,
		DXJOY_BTN22 = 0x00200000,
		DXJOY_BTN23 = 0x00400000,
		DXJOY_BTN24 = 0x00800000,
		DXJOY_BTN25 = 0x01000000,
		DXJOY_BTN26 = 0x02000000,
		DXJOY_BTN27 = 0x04000000,
		DXJOY_BTN28 = 0x08000000,
		DXJOY_BTN29 = 0x10000000,
		DXJOY_BTN30 = 0x20000000,
		DXJOY_BTN31 = 0x40000000,
		DXJOY_BTN32 = 0x80000000

	};


  その後、次のような関数を定義した。

	DWORD CDxJoyStick::GetButtonState ( BYTE rgbButtons[32] )
	{
		DWORD dwAns = 0;

		for ( unsigned int i = 0; i < 32; i++ ) {
			if ( rgbButtons[i] & 0x80 ) {
				dwAns |= ( 1 << i );
			}
		}

		return dwAns;

	}


  内容は、ボタン1〜32について1ビット目〜32ビット目までを
   ・押されていれば1
   ・押されていなければ0
  という状態で返す、というもの。
  引数に rgbButtons をとるので、事前に DIJOYSTATE で取得しておく必要がある。
  (というか独自の構造体を定義した方がいいかもしれない(^o^;))

  実際の使用はこんな感じで。

	DWORD dwState;

	dwState = g_joy.GetButtonState ( diState.rgbButtons );
	if ( dwState & DXJOY_BTN1 ) {
		// ボタン1が押されたときの処理

	}


  これでだいぶ楽チンになった(ハズ)。




・各設定の簡単な部分を変更できるようにする
  最後に、協調レベルの設定やFFBのデッドゾーン設定を行えるようにする。


  ・デッドゾーンの設定(コードの一部を抜粋)

	ZeroMemory ( &diProp, sizeof ( DIPROPDWORD ) );
	diProp.diph.dwSize		= sizeof ( DIPROPDWORD );
	diProp.diph.dwHeaderSize	= sizeof ( DIPROPHEADER );
	diProp.diph.dwHow		= DIPH_BYID;
	diProp.diph.dwObj		= vecObj[k].dwType;
	diProp.dwData			= nZone;

	m_vecDevice[i]->SetProperty ( DIPROP_DEADZONE, &diProp.diph );


  DIPROPDWORD の dwData に、0〜10000の値を入れる。
  0=0%、5000=50%、10000=100%。
  例えば30%に設定すると、軸の中心から端っこまでの30%は軸値が0になる。
  (軸の値域自体は変わらない。)


   例:値域-1000〜1000のスティックがある。
     ここで、デッドゾーンを2000(20%)に設定すると・・・
     本来の値域 -200〜200 は、値0として通知され、
     本来の値域 -1000〜-201、201〜1000 が
     -1000〜-1, 1〜1000 として通知される。


  多分そのはず。嘘だったらごめんなさい。このブログを真に受けてはいけない。


  ・協調レベルの設定
  今回は、EnableFFB関数 と SetMode関数 に分けた。
   EnableFFB関数:引数が真だと排他モード、偽だと非排他モードにする。
   SetMode関数:後ほど説明する。

  EnableFFB関数は、普段はどうせ非排他モードで問題内だろうという事で
  FFBを使用するときにだけ排他モードを使えばいいだろうという考えから。
  モード用の変数を適当に保持しておいて、それに変更を加える。

	for ( unsigned int i = 0; i < m_vecDevice.size(); i++ ) {
		if ( nFlag ) { // 排他モード(FFB使用可)
			m_dwMode &= (~DISCL_NONEXCLUSIVE);
			m_dwMode |= DISCL_EXCLUSIVE;

		} else { // 非排他モード(FFB使用不可)
			m_dwMode &= (~DISCL_EXCLUSIVE);
			m_dwMode |= DISCL_NONEXCLUSIVE;

		}
		hr = m_vecDevice[i]->SetCooperativeLevel ( m_hWnd, m_dwMode );

	}


  ~はビット反転。反転させてANDする事で、該当フラグを下げる事になる。


  続いてSetMode。こっちは次の2つについて設定できるようにする。
   ・バックグラウンドアクセス権か、フォアグラウンドアクセス権か
   ・Windowsキーを無効にするか、有効にするか
  ただし、WindowsキーについてはMSDNにこう書かれている。



ただし、デフォルトのアクション マッピング ユーザー インターフェイス (UI) が表示されている間は DISCL_NOWINKEY フラグは無効であり、デフォルトのアクション マッピング UI が存在している間は Windows キーは通常どおり機能する。


  その為、今回はアクションマッピングについては実装してない・使用してないので
  普通にWindowsキーが使えてしまう(^o^;)


  フラグについては、
   1ビット目をアクセス権
   2ビット目をWindowsキーの有効・無効フラグ
  として定義する。
  結構強引な実装でござる(^o^;)

  	enum {
		DXJOY_FOREGROUND, DXJOY_BACKGROUND,
		DXJOY_NOWINKEY, DXJOY_WINKEY = 0
	};

// -------------------------

	if ( nFlag & 1 ) {
		m_dwMode &= (~DISCL_FOREGROUND);
		m_dwMode |= DISCL_BACKGROUND;

	} else {
		m_dwMode &= (~DISCL_BACKGROUND);
		m_dwMode |= DISCL_FOREGROUND;

	}

	if ( nFlag & 2 ) {
		m_dwMode |= DISCL_NOWINKEY;

	} else {
		m_dwMode &= (~DISCL_NOWINKEY);

	}

	for ( unsigned int i = 0; i < m_vecDevice.size(); i++ ) {
		hr = m_vecDevice[i]->SetCooperativeLevel ( m_hWnd, m_dwMode );

	}


  ビット操作についてはさっきと同じ感じで。
  これでしばらくDirectInputとはお別れ。多分。