在Windows应用程序中获取鼠标位置

时间:2018-06-06 14:22:58

标签: c++ winapi coordinates mouse directx-11

我使用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 :(得分:3)

您从WM_LBUTTONDOWN收到的坐标是客户坐标,并且是正确的。这里的真正问题源于窗口区域客户区域之间的区别。

窗口区域包含整个窗口,包括标题栏和边框。您从RECT获得的GetWindowRect大小足以覆盖窗口的每个像素,以便在屏幕上叠加该大小的黑盒会导致整个窗口,标题栏和边框包含在内,消失。

然而,客户区是Windows为您创建的边框内的区域。您从RECT获得的GetClientRect足够大,再次,在屏幕上叠加一个大小的黑盒子将覆盖整个3D场景,但保留标题栏和边框可见。

这里的理论和定义都很好,但现在我们需要解决这个问题。事实证明,除了Remy Lebeau指出的API合规性问题(使用GET_X_LPARAM() / GET_Y_LPARAM()而非转移)之外,您在窗口过程中使用的代码完全正常,无需修改。引入错误的实际位置是在窗口创建代码期间。

nWidth的{​​{1}}和nHeight参数指定了窗口的宽度和高度,而不是客户区。因此,您的客户区域将更小。但是,您希望客户区具有这些宽度。

事实证明,这是一个常见的事件,Windows 2000添加了一个函数来为给定的客户区域生成适当的窗口宽度和高度:CreateWindow。要使用它,请将AdjustWindowRect来电更改为以下内容:

CreateWindow

这将抵消您的坐标,以确保客户区域的大小与DisplayManager认为的大小完全相同。

修改

如果您有扩展窗口样式,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); 允许您将这些扩展窗口样式指定为该函数的附加第四个参数。