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とはお別れ。多分。