0

バックグラウンド:

私は、Windows API を使用して開発するほとんどの時間で、マウスとキーボードの入力にそれぞれWM_MOUSEMOVEWM_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_mouseScreenPositionGETCURSORGetCursorPos()

要約すれば

私の質問の全体的なセットは次のとおりだと思います。

  1. 関連する構造の値lLastXと値は何ですか? それらは画面座標/クライアント座標に関連していますか。つまり、返される値は画面上のピクセルと 1:1 の関係ですか、それともディスプレイにはまったく関係なく、むしろマウスの詳細 (感度など) に関連しているため、1 ではありませんか? :1 ピクセルとの関係は?lLastYRAWMOUSE

  2. 1 に対する答えが表示座標ではなくマウスに関連している場合: マウス ポインターの実際の画面座標を単独で決定することは可能WM_INPUTですか? または、メッセージをトラップするかWM_MOUSEMOVE、GetCursorPos() を使用してクライアント空間と画面空間のカーソル座標を決定する必要がありますか?

  3. 2 に対する答えが / を使用する必要がWM_MOUSEMOVEある場合: /と同様にGetCursorPos()使用することになった場合に注意すべきパフォーマンスの問題はありますか? それとも、パフォーマンスに関する私の懸念は根拠がありませんか?RAWINPUTWM_MOUSEMOVEGetCursorPos()

ここまでやり遂げられたのであれば、感謝の意を表したいと思います。助けや情報を提供していただければ幸いです。ありがとうございました!

4

1 に答える 1

0
  1. 「返される値は、WM_MOUSEMOVE メッセージから得られるようなスクリーン スペースの値ではないことに注意してください。これは取得している生データであるため、値を解釈する必要があります。値は通常、最後の位置に関連しているため、動きを示しています。 RAWMOUSE 構造体の usFlags を確認できます。」私がいつも素晴らしいと思うToymakerからこれを手に入れました。ここ

  2. RAWINPUT は、相対入力を取得するためにのみ作成されます。それが生の理由です。本当に GetCursorPos を使用したくない場合は、WM_MOUSEMOVE を使用して l/w パラメータを確認してください。

  3. GetCursorPos() のパフォーマンス テストを実際に行ったことはありませんが、自分のプロジェクトで少し読んだことがありますが、それに対する異議は見たことがありません。RAWINPUT を使用するかどうかに関係なく、GetCursorPos をフレームごとに 1 回、または更新ごとに呼び出すことは、ほとんどありません。カメラの回転に使用しましたが、常に正常に機能しています。

于 2013-07-16T20:16:26.467 に答える