High-Definition マウスの動きを活用する
標準のコンピューター マウスは 400 ドット/インチ (DPI) のデータを返しますが、高解像度マウスは 800 DPI 以上のデータを生成します。 これにより、高精細マウスからの入力は、標準マウスの入力よりもはるかに正確になります。 ただし、標準のWM_MOUSEMOVE メッセージでは、高精細データを取得できません。 一般に、ゲームは高解像度のマウス デバイスの恩恵を受けますが、WM_MOUSEMOVEを使用してマウス データを取得するゲームは、フィルター処理されていないマウスの解像度全体にアクセスできません。
多くの企業が、Microsoft や Logitech などの高精細マウス デバイスを製造しています。 高解像度マウス デバイスの人気が高まる中、開発者は、これらのデバイスによって生成された情報を最適に使用する方法を理解することが重要です。 この記事では、一人称シューティング ゲームのようなゲームでの高解像度マウス入力のパフォーマンスを最適化する最適な方法に焦点を当てます。
マウス移動データの取得
マウス データを取得する 3 つの主要な方法を次に示します。
- WM_MOUSEMOVE
- WM_INPUT
- DirectInput の
各方法には、データの使用方法に応じて長所と短所があります。
WM_MOUSEMOVE
マウスの移動データを読み取る最も簡単な方法は、WM_MOUSEMOVEメッセージを介して行う方法です。 WM_MOUSEMOVE メッセージからマウスの移動データを読み取る方法の例を次に示します。
case WM_MOUSEMOVE:
{
int xPosAbsolute = GET_X_PARAM(lParam);
int yPosAbsolute = GET_Y_PARAM(lParam);
// ...
break;
}
WM_MOUSEMOVEからのデータに対する主な欠点は、画面の解像度に制限されていることです。 つまり、マウスを少し移動しても、ポインターが次のピクセルに移動するのに十分ではない場合、WM_MOUSEMOVEメッセージは生成されません。 したがって、このメソッドを使用してマウスの動きを読み取ります。これは、高精細入力の利点を否定します。
ただし、WM_MOUSEMOVEする利点は、Windows が生のマウス データにポインターアクセラレーション (弾道とも呼ばれます) を適用することで、マウス ポインターが顧客の期待どおりに動作することです。 これにより、WM_MOUSEMOVEポインター制御 (WM_INPUTまたは DirectInput 経由) の推奨されるオプションになります。これは、ユーザーにとってより自然な動作になるためです。 WM_MOUSEMOVEはマウスポインターを動かすのに最適ですが、高精細度が失われるので、一人称カメラを動かすのにそれほど良くはありません。
WM_MOUSEMOVEの詳細については、「WM_MOUSEMOVE」を参照してください。
WM_INPUT
マウス データを取得する2つ目の方法は、WM_INPUTメッセージを読み取ることです。 メッセージWM_INPUT処理はWM_MOUSEMOVEメッセージの処理よりも複雑ですが、WM_INPUTメッセージはヒューマン インターフェイス デバイス (HID) スタックから直接読み取られ、高解像度の結果が反映されます。
WM_INPUTメッセージからマウス移動データを読み取るには、まずデバイスを登録する必要があります。この例を次のコードに示します。
// you can #include <hidusage.h> for these defines
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02)
#endif
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = hWnd;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));
次のコードは、アプリケーションの WinProc ハンドラー WM_INPUTメッセージを処理します。
case WM_INPUT:
{
UINT dwSize = sizeof(RAWINPUT);
static BYTE lpb[sizeof(RAWINPUT)];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
int xPosRelative = raw->data.mouse.lLastX;
int yPosRelative = raw->data.mouse.lLastY;
}
break;
}
WM_INPUTを使用する利点は、ゲームが可能な限り低いレベルでマウスから生データを受け取るということです。
欠点は、WM_INPUTのデータに速度変化が適用されていないことです。そのため、このデータでカーソルを動かす場合は、Windowsと同様にカーソルを動作させるために追加の労力が必要です。 ポインターの弾道の適用の詳細については、「windows XP のポインターの弾道をする」を参照してください。
WM_INPUTの詳細については、「未加工入力について」を参照してください。
DirectInput
DirectInput は、システム上の入力デバイスを抽象化する API 呼び出しのセットです。 内部的には、DirectInput は、WM_INPUTデータを読み取る 2 番目のスレッドを作成します。DirectInput API を使用すると、単にWM_INPUTを直接読み取るよりもオーバーヘッドが増えます。 DirectInput は DirectInput ジョイスティックからデータを読み取る場合にのみ役立ちます。ただし、Windows のコントローラーのみをサポートする必要がある場合は、代わりに XInput を使用してください。 全体的に、DirectInput を使用しても、マウスまたはキーボード デバイスからデータを読み取る場合に利点はなく、これらのシナリオでは DirectInput を使用しないことをお勧めします。
次のコードに示すように、DirectInputの使用の複雑さを、前述のメソッドと比較します。 DirectInput マウスを作成するには、次の一連の呼び出しが必要です。
LPDIRECTINPUT8 pDI;
LPDIRECTINPUTDEVICE8 pMouse;
hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&pDI, NULL);
if(FAILED(hr))
return hr;
hr = pDI->CreateDevice(GUID_SysMouse, &pMouse, NULL);
if(FAILED(hr))
return hr;
hr = pMouse->SetDataFormat(&c_dfDIMouse2);
if(FAILED(hr))
return hr;
hr = pMouse->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
if(FAILED(hr))
return hr;
if(!bImmediate)
{
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 16; // Arbitrary buffer size
if(FAILED(hr = pMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
return hr;
}
pMouse->Acquire();
DirectInput マウス デバイスは、各フレームを読み取ることができます。
DIMOUSESTATE2 dims2;
ZeroMemory(&dims2, sizeof(dims2));
hr = pMouse->GetDeviceState(sizeof(DIMOUSESTATE2), &dims2);
if(FAILED(hr))
{
hr = pMouse->Acquire();
while(hr == DIERR_INPUTLOST)
hr = pMouse->Acquire();
return S_OK;
}
int xPosRelative = dims2.lX;
int yPosRelative = dims2.lY;
概要
全体として、高解像度のマウス移動データを受け取る最善の方法はWM_INPUTです。 ユーザーがマウス ポインターを動かしているだけの場合は、ポインターの弾道を実行する必要がないように、WM_MOUSEMOVEの使用を検討してください。 これらのウィンドウ メッセージは、マウスが高解像度のマウスでない場合でもうまく機能します。 高解像度をサポートすることで、Windows ゲームはユーザーにより正確な制御を提供できます。