バックグラウンド:
私は、Windows API を使用して開発するほとんどの時間で、マウスとキーボードの入力にそれぞれWM_MOUSEMOVE
とWM_KEYDOWN
/メッセージを使用してきました。WM_KEYUP
ただし、最近、代わりにメッセージを使用RAWINPUT
して入力を処理する入力クラスの実装を開始しました。WM_INPUT
このサイトのおかげで、キーボードの実装は問題なく動作しています
しかし、私は今、マウスの動きを実装することに注意を向けています。私の理解でWM_INPUT
は、マウスを扱うときにクライアント空間の座標ではなく、マウスの動きのデルタを生成します。
問題は、マウス ポインターのクライアント座標とスクリーン スペース座標の両方をクラス内に格納したいことです。理想的には、WM_MOUSEMOVE
メッセージをトラップしたり、可能であればGetCursorPos()
/関数を使用したりする必要なく、これを実行したいと考えています。ScreenToClient()
おそらく不当です)パフォーマンスの問題への恐れ。
私の研究はここRAWINPUT
に私を導き、それによってマウスの詳細について述べています:
返される値は、WM_MOUSEMOVE メッセージから得られるような画面スペースの値ではないことに注意してください。これは取得している生データであるため、値を解釈する必要があります。
これにより、最初の呼び出しを使用してマウスカーソルの初期位置を計算しGetCursorPos()
、メッセージによって検出されたすべてのマウス移動イベントに対してWM_INPUT
、メッセージから取得したデルタWM_INPUT
を初期カーソル位置に追加することで、データを解釈できると考えるようになりました。位置が画面の境界内に留まるようにするための措置を講じます。たとえば、次のようなものです(これは私のクラスからの抜粋が含まれているためコンパイルされないことに注意してください。ただし、現在行っていることの概要を説明するには十分なはずです)
// Somewhere in class header
RECT m_screenMouseBounds;
POINT m_mouseDelta;
POINT m_mouseScreenPosition;
POINT m_mouseScreenPositionGETCURSOR;
RAWMOUSE m_rawMouse;
// ...
// Somewhere during class initialisation
GetCursorPos(&m_mouseScreenPosition); // Get initial mouse cursor position
// Determine maximum and minimum boundaires of current display
m_screenMouseBounds.right = GetSystemMetrics(SM_CXSCREEN);
m_screenMouseBounds.bottom = GetSystemMetrics(SM_CYSCREEN);
m_screenMouseBounds.top = 0;
m_screenMouseBounds.left = 0;
// Prepare the devices for registering
RAWINPUTDEVICE theInputDevices[2];
// 0 = keyboard
theInputDevices[0].usUsagePage = 0x01;
theInputDevices[0].usUsage = 0x06;
theInputDevices[0].dwFlags = RIDEV_NOLEGACY;
theInputDevices[0].hwndTarget = theWindowToHandle;
// 1 = mouse
theInputDevices[1].usUsagePage = 0x01;
theInputDevices[1].usUsage = 0x02;
theInputDevices[1].dwFlags = 0; // RIDEV_NOLEGACY
theInputDevices[1].hwndTarget = theWindowToHandle;
// Register each device with raw input
if(RegisterRawInputDevices(theInputDevices,2,sizeof(RAWINPUTDEVICE))==FALSE)
{
// throw exception
return false;
}
// ...
// In the WM_INPUT processing function with parameters : (WPARAM wParam, LPARAM lParam)
char inputBuffer[sizeof(RAWINPUT)] = {};
UINT inputBufferSize = sizeof(RAWINPUT);
GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, inputBuffer, &inputBufferSize, sizeof(RAWINPUTHEADER));
RAWINPUT* rawData = reinterpret_cast<RAWINPUT*>(inputBuffer);
if(rawData->header.dwType == RIM_TYPEMOUSE)
{
m_rawMouse = rawData->data.mouse;
// Add the movement deltas acquired from the WM_INPUT message
m_mouseDelta.x = m_rawMouse.lLastX;
m_mouseDelta.y = m_rawMouse.lLastY;
// Update the screen position using the delta values (Does not work as expected!)
m_mouseScreenPosition.x += m_mouseDelta.x;
m_mouseScreenPosition.y += m_mouseDelta.y;
// Ensure mouse coords are within the screens boundaries
if (m_mouseScreenPosition.x < m_screenMouseBounds.left)
{
m_mouseScreenPosition.x = m_screenMouseBounds.left;
}
if (m_mouseScreenPosition.x > m_screenMouseBounds.right)
{
m_mouseScreenPosition.x = m_screenMouseBounds.right;
}
if (m_mouseScreenPosition.y < m_screenMouseBounds.top)
{
m_mouseScreenPosition.y = m_screenMouseBounds.top;
}
if (m_mouseScreenPosition.y > m_screenMouseBounds.bottom)
{
m_mouseScreenPosition.y = m_screenMouseBounds.bottom;
}
// Double check to make sure that the screen position coordinates calculated
// above match the screen coordinates as determined by Windows
// using GetCursorPos() (Hint: They don't! :( )
GetCursorPos(&m_mouseScreenPositionGETCURSOR);
TCHAR s[256];
swprintf(s, L"MouseDX: %ld MouseDY: %ld\n", m_mouseDelta.x, m_mouseDelta.y);
OutputDebugString(s);
swprintf(s, L"MouseX(Screen(WM_INPUT)): %ld MouseY(Screen(WM_INPUT)): %ld\n", m_mouseScreenPosition.x, m_mouseScreenPosition.y);
OutputDebugString(s);
swprintf(s, L"MouseX(Screen(GetCursorPos)): %ld MouseY(Screen(GetCursorPos)): %ld\n", m_mouseScreenPositionGETCURSOR.x, m_mouseScreenPositionGETCURSOR.y);
OutputDebugString(s);
}
問題は、このメソッドで取得した値がWINAPI 関数で取得した値m_mouseScreenPosition
と異なること です。m_mouseScreenPositionGETCURSOR
GetCursorPos()
要約すれば
私の質問の全体的なセットは次のとおりだと思います。
関連する構造の値
lLastX
と値は何ですか? それらは画面座標/クライアント座標に関連していますか。つまり、返される値は画面上のピクセルと 1:1 の関係ですか、それともディスプレイにはまったく関係なく、むしろマウスの詳細 (感度など) に関連しているため、1 ではありませんか? :1 ピクセルとの関係は?lLastY
RAWMOUSE
1 に対する答えが表示座標ではなくマウスに関連している場合: マウス ポインターの実際の画面座標を単独で決定することは可能
WM_INPUT
ですか? または、メッセージをトラップするかWM_MOUSEMOVE
、GetCursorPos() を使用してクライアント空間と画面空間のカーソル座標を決定する必要がありますか?2 に対する答えが / を使用する必要が
WM_MOUSEMOVE
ある場合: /と同様にGetCursorPos()
使用することになった場合に注意すべきパフォーマンスの問題はありますか? それとも、パフォーマンスに関する私の懸念は根拠がありませんか?RAWINPUT
WM_MOUSEMOVE
GetCursorPos()
ここまでやり遂げられたのであれば、感謝の意を表したいと思います。助けや情報を提供していただければ幸いです。ありがとうございました!