ステップ 6 : マウスからのバッファー データの取得
マウスを取得したら、アプリケーションはマウスからデータを取得できます。
Scrawl サンプルでは、通知されたイベントがトリガーとなって取得が行われます。WinMain 関数では、シグナルまたはメッセージが存在することが MsgWaitForMultipleObjects によって示されるまで、アプリケーションはスリープ状態になります。マウスに関連したシグナルが存在する場合は、OnMouseInput 関数が呼び出されます。この関数は、次のプロセスで示すように、バッファー入力を処理する方法を示した例です。
まず、この関数は以前のカーソル位置がクリーンアップされていることを確認します。Scrawl は独自のカーソルを維持し、そのカーソルの描画と消去を完全に管理します。
VOID OnMouseInput(HWND hWnd)
{
/* Invalidate the old cursor so that it will be erased */
InvalidateCursorRect(hWnd);
次に、関数は読み取りループに入り、バッファーの内容全体に対応する処理を行います。取得する項目は一度に 1 つだけなので、データの保持に必要な DIDEVICEOBJECTDATA 構造体はただ 1 つです。
while (!bDone) {
DIDEVICEOBJECTDATA od;
DWORD dwElements = 1; // number of items to be retrieved
注 入力の処理を進めるもう 1 つの方法は、バッファー全体を一度に読み取り、取得した項目 1 つずつに対応する処理を順次ループして行うことです。この場合は、dwElements はバッファーのサイズで、od は同じ数の要素からなる配列です。
アプリケーションは、データをフェッチするために IDirectInputDevice8::GetDeviceData メソッドを呼び出します。2 番目のパラメーターはデータを書き込む先を DirectInput に指定し、3 番目のパラメーターは必要な項目数を指示します。データをバッファーに残す場合、最後のパラメーターは DIGDD_PEEK ですが、この例ではデータが再び必要になることはないので、データは削除されます。
hr = g_pMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),
&od, &dwElements, 0);
次に、アプリケーションはデバイスへのアクセスが失われたかどうかを検査し、失われた場合は可能な限り早期にマウスの再取得を試みます。この手順については、「ステップ 5 : マウスへのアクセスの管理」で説明しました。
if (hr == DIERR_INPUTLOST)
{
SetAcquire();
break;
}
次にアプリケーションは、IDirectInputDevice8::GetDeviceData メソッドの呼び出しが正常に行われたこと、および取得するデータが実際に存在していたことを確認します。IDirectInputDevice8::GetDeviceData を呼び出した後、dwElements 変数は実際に取得した項目の数を示します。
/* Unable to read data or no data available */
if (FAILED(hr) || dwElements == 0)
{
break;
}
ここまで実行が進むと、呼び出しは成功しており、バッファー内にはデータが存在します。次に、アプリケーションは DIDEVICEOBJECTDATA 構造体の dwOfs メンバーを調べて、デバイスのどのオブジェクトが状態の変更を報告したかを判定し、ヘルパー関数を呼び出して適切に対処します。dwData メンバーの値は、デバイス オブジェクトに発生した事象に関する情報を含んでおり、この値がこれらの関数に渡されます。
/* View the element to see what occurred */
switch (od.dwOfs)
{
// Mouse horizontal motion
case DIMOFS_X:
UpdateCursorPosition(od.dwData, 0);
break;
// Mouse vertical motion
case DIMOFS_Y:
UpdateCursorPosition(0, od.dwData);
break;
// DIMOFS_BUTTON1: Right button pressed or released
case DIMOFS_BUTTON1:
// DIMOFS_BUTTON0: Left button pressed or released
case DIMOFS_BUTTON0:
// Is the right button or a swapped left button down?
if((g_bSwapMouseButtons &&
DIMOFS_BUTTON1 == od.dwOfs) ||
(!g_bSwapMouseButtons &&
DIMOFS_BUTTON0 == od.dwOfs))
{
if (od.dwData & 0x80) // Left button pressed, so
// go into button-down mode
{
bDone = TRUE;
OnLeftButtonDown(hWnd);
}
// Is the left button or a swapped right button down?
if((g_bSwapMouseButtons &&
DIMOFS_BUTTON0 == od.dwOfs) ||
(!g_bSwapMouseButtons &&
DIMOFS_BUTTON1 == od.dwOfs))
{
if(!(od.dwData & 0x80)) // button release, so
// check shortcut menu
{
bDone = TRUE;
OnRightButtonUp(hWnd);
}
}
break;
}
最後に、ヘルパー関数の 1 つによってカーソルが動かされた場合は、OnMouseInput サンプル関数によって、カーソルがある画面上の長方形が無効になります。
// Invalidate the new cursor so that it will be drawn
InvalidateCursorRect(hWnd);
}
Scrawl は OnLeftButtonDown 関数でもマウス データを収集します。左ボタンが押されているとき、つまりユーザーが描画を行っているときに、アプリケーションはこの関数でマウスの動きを追跡します。この関数はイベント通知には依存せず、ボタンが解放されるまで DirectInput バッファーを繰り返しポーリングしています。
OnLeftButtonDown 関数内では、保留されているデータがすべて読み取られるまで、描画は行われないことに注意してください。これは、マウスの水平または垂直の動きがそれぞれ別々のイベントとしてレポートされるためです。ただし、両方のイベントはバッファーに同時に格納されます。個々の軸方向の動きにそれぞれ対応して線を直ちに描画したとすると、斜め方向にマウスを動かしたときに直角に 2 本の線が引かれることになります。
また、アプリケーション内で対応する処理を行う前に両軸方向での動きを確実に反映させる方法として、X 軸項目と Y 軸項目のシーケンス番号をチェックする方法があります。番号が同じならば、2 つのイベントは同時に発生しています。詳細については、「タイム スタンプとシーケンス番号」を参照してください。
その他の DirectInput のチュートリアルについては、「DirectInput チュートリアル」を参照してください。