Получение позиции мыши в приложении Windows - PullRequest
0 голосов
/ 06 июня 2018

Я пишу простой игровой движок с DirectX11 и использую Win32 API для создания окна и обработки ввода пользователя.Я реализую подпрограмму наложения лучей, чтобы выбирать и размещать объекты на местности, и все работает нормально, за исключением того, что когда я пытаюсь что-то разместить на земле, это имеет странное смещение вверху и влево:

enter image description here

После небольшой отладки я обнаружил, что мой код работает нормально, и проблема в координатах окна, которые я посылаю в класс / функцию приведения лучей:

LRESULT Game::GameWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_LBUTTONDOWN:
            /*MessageBox(mWindow, L"left mouse button clicked", L"CLICK", MB_OK);*/
            Timer::GetInstance()->Stop();
------->    Input::GetInstance()->Place(lParam & 0xFFFF, lParam >> 16 & 0xFFFF, mCamera, mEntity, mTerrain, mRenderer);
            return 0;
           // ....
           // .... other cases
    }
}

Координаты курсора мыши не находятся между 0 и шириной / высотой окна (в моем случае 1024 X 768), но максимальная ширина составляет 1004, а максимальная высота составляет 718 (более или менее).когда я нажимаю на правый нижний угол окна), это то, что я читаю при отладке приложения.

Окончательное доказательство этого состоит в том, что если я использую эти ширину и высоту в своем коде, объекты размещаютсягде они должны.Поэтому мой вопрос: почему координаты не покрывают весь размер окна?Я что-то упускаю / делаю что-то не так?Как я могу получить правильные координаты?

РЕДАКТИРОВАТЬ

моей функции требуются координаты клиентской области, координаты курсора мыши ВНУТРИ окна, конечно.

РЕДАКТИРОВАТЬ РЕДАКТИРОВАТЬ

это код, который я использую для создания окна

void Game::InitializeWindow(HINSTANCE hInstance)
{
    WNDCLASS windowClass = {};
    windowClass.hInstance = hInstance;
    windowClass.lpfnWndProc = &WndProc;
    windowClass.lpszClassName = L"wndClass";
    windowClass.lpszMenuName = NULL;
    windowClass.style = CS_HREDRAW | CS_VREDRAW;
    windowClass.cbClsExtra = 0;
    windowClass.cbWndExtra = 0;
    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    windowClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
    RegisterClass(&windowClass);

    mWindow = CreateWindow(L"wndClass", L"DirectX 11 Engine", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, DisplayManager::GetInstance()->GetDisplayWidth(), DisplayManager::GetInstance()->GetDisplayHeight(), 0, 0, hInstance, 0);
    if (!mWindow)
        ErrorBox(L"window creation failed");

    ShowWindow(mWindow, SW_SHOW);
    UpdateWindow(mWindow);
}

1 Ответ

0 голосов
/ 06 июня 2018

Координаты, которые вы получаете от WM_LBUTTONDOWN, являются клиентскими координатами и являются правильными.Настоящая проблема здесь связана с разницей между областью и клиентской областью .

Область окна содержит все окно, включая строку заголовка и границы.RECT, которое вы получите от GetWindowRect, достаточно велико, чтобы охватить каждый пиксель вашего окна, так что наложение черного поля такого размера на экран приведет к тому, что все ваше окно, строка заголовка и включенные границы исчезнут.

Однако клиентская область - это область внутри , которую Windows создает для вас.RECT, который вы получите от GetClientRect, достаточно велик, чтобы снова наложить черный прямоугольник такого размера на экран, чтобы он охватил всю 3D-сцену, но оставил бы заголовок и границы видимыми.

Теория и определения здесь все хорошо и хорошо, но теперь нам нужно решить проблему.Оказывается, код, который вы используете в своей оконной процедуре, за исключением проблем с соблюдением API, отмеченных Реми Лебо (используйте GET_X_LPARAM() / GET_Y_LPARAM() вместо сдвига), прекрасно работает и не требует изменений.Фактическая точка, в которой вы вводите ошибку, - это код создания окна.

Параметры nWidth и nHeight для CreateWindow указывают ширину и высоту окна , а неклиентская зона.Таким образом, ваша клиентская зона будет меньше.Однако вы хотите, чтобы область клиента имела такую ​​ширину.

Оказывается, это настолько распространенный случай, что Windows 2000 добавила функцию для генерации правильной ширины и высоты окна для данной области клиента: AdjustWindowRect,Чтобы использовать его, измените ваш CreateWindow вызов на следующее:

RECT windowRect;
windowRect.top = 0;
windowRect.left = 0;
windowRect.right = DisplayManager::GetInstance()->GetDisplayWidth();
windowRect.bottom = DisplayManager::GetInstance()->GetDisplayHeight();

AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE);

mWindow = CreateWindow(L"wndClass", 
                       L"DirectX 11 Engine", 
                       WS_OVERLAPPEDWINDOW, 
                       CW_USEDEFAULT, 
                       CW_USEDEFAULT, 
                       windowRect.right, 
                       windowRect.bottom, 
                       0, 
                       0, 
                       hInstance, 
                       0);

Это сместит ваши координаты, чтобы гарантировать, что клиентская область точно соответствует размеру, который, как думает DisplayManager, должен быть.

РЕДАКТИРОВАНИЕ

Если у вас расширенный стиль окна, AdjustWindowRectEx позволяет вам указать эти расширенные стили окна в качестве дополнительного четвертого аргумента функции.

...