获取窗口内鼠标位置异常求助:坐标与窗口分辨率不符
你遇到的核心问题是混淆了「窗口整体尺寸」和「客户区(渲染区域)尺寸」——你设置的1680x1050是包含标题栏、边框的整个窗口大小,Windows会自动从这个尺寸里扣除边框和标题栏的占用空间,导致实际渲染区域的尺寸比预期小,所以光标移到最右侧只能到1660左右。下面一步步给你解决思路:
一、为什么会出现坐标偏差?
CreateWindowEx中传入的宽高参数对应的是整个窗口的尺寸(包含标题栏、边框),而非你需要的渲染区域(客户区)尺寸。系统会根据窗口样式自动计算边框、标题栏的宽度/高度,从总尺寸中扣除后才是客户区的实际大小,这就是坐标达不到预期值的根本原因。
另外,你提到光标在标题栏内时y坐标为0:标题栏属于窗口的非客户区,此时ScreenToClient转换后的坐标本应落在客户区范围之外(通常y为负数),你看到的0可能是特殊场景下的表现,但我们的核心目标是获取客户区内的有效坐标,所以先聚焦到正确设置客户区尺寸上。
二、创建客户区尺寸为1680x1050的窗口
要让渲染区域正好是1680x1050,你需要用AdjustWindowRectEx函数,根据目标客户区尺寸反算出所需的窗口整体大小(包含边框和标题栏)。修改你的窗口创建代码如下:
// 定义目标客户区尺寸 const int targetClientWidth = 1680; const int targetClientHeight = 1050; // 计算能容纳目标客户区的窗口整体尺寸 RECT windowRect = {0, 0, targetClientWidth, targetClientHeight}; AdjustWindowRectEx( &windowRect, (WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME) | WS_VISIBLE, FALSE, 0 ); // 创建窗口时使用计算后的尺寸 HWND windowHandle = CreateWindowEx( 0, windowClass.lpszClassName, L"D3D11 Rendering", (WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME) | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, windowRect.right - windowRect.left, // 窗口实际宽度 windowRect.bottom - windowRect.top, // 窗口实际高度 0, 0, hInstance, 0 );
AdjustWindowRectEx会根据你指定的窗口样式,自动计算出刚好能容纳目标客户区的窗口大小,这样创建出来的窗口,客户区就完全符合你想要的1680x1050了。
三、正确获取客户区内的光标坐标
窗口尺寸设置正确后,两种方法都能准确获取客户区坐标:
方法1:通过WM_MOUSEMOVE事件获取
WM_MOUSEMOVE消息的lParam参数本身就是相对于客户区左上角的坐标,直接解析即可,无需额外转换:
case WM_MOUSEMOVE: { int clientX = GET_X_LPARAM(lParam); int clientY = GET_Y_LPARAM(lParam); // clientX范围是0~1679,clientY范围是0~1049,完全对应客户区 break; }
注意:该消息仅在光标处于客户区内时触发,所以得到的坐标一定是有效的渲染区域坐标。
方法2:用GetCursorPos + ScreenToClient主动获取
如果需要在主循环中主动查询光标位置,这个方法依然有效,现在窗口尺寸正确后,转换结果会准确对应客户区:
POINT cursorPos; GetCursorPos(&cursorPos); ScreenToClient(windowHandle, &cursorPos); // 可选:判断光标是否在客户区内,避免处理非客户区的无效坐标 RECT clientRect; GetClientRect(windowHandle, &clientRect); if (PtInRect(&clientRect, cursorPos)) { // cursorPos.x和cursorPos.y是有效的客户区坐标 }
额外说明
- 你用
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME去掉窗口可调边框的样式,不会影响AdjustWindowRectEx的计算逻辑,上面的代码完全适用。 - 如果后续需要动态调整客户区尺寸,同样可以用
AdjustWindowRectEx重新计算窗口大小,再调用SetWindowPos更新窗口。
内容的提问来源于stack exchange,提问作者AbyssalLemon

