You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GLEW与WinAPI窗口大小及鼠标点击坐标不一致问题排查

高DPI缩放场景下GLFW与WinAPI窗口坐标差异问题

在150%显示器缩放设置下,WinAPI创建的窗口比GLFW创建的大1.5倍,两者官方文档均明确宽高参数采用屏幕坐标。排查后确认是系统高DPI缩放导致该差异。通过设置glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);可以解决窗口大小不匹配的问题,但此时GLFW鼠标回调返回的点击坐标仍为物理像素值,与WinAPI返回的逻辑坐标存在150%的缩放差异。

相关代码片段

GLFW鼠标回调代码片段

glfwSetMouseButtonCallback(window, 
    [](GLFWwindow* window, int button, int action, int mods) 
    {
        if (action == GLFW_RELEASE)
        {
            double xpos, ypos;
            glfwGetCursorPos(window, &xpos, &ypos);
            cout << "release x:"<<xpos<<" y:"<< ypos << endl;
        }
    }
);

WinAPI(ATL)鼠标回调代码片段

LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    using std::cout;
    using std::endl;
    POINT c{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
    cout<< c<< endl;

    InvalidateRect(0, false);
    return 0;
}

完整代码示例

完整GLFW代码

// GLFW
#include <GL/glew.h> // 注意:GLEW必须在GLFW之前包含
#include <GLFW/glfw3.h>
#include <iostream>
using namespace std;

const int width = 1280, height = 720;
int main(int argc, char* argv[])
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
    GLFWwindow* window = glfwCreateWindow(width, height, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        cerr << "GLEW Error: " << glewGetErrorString(err) << endl;
        return -1;
    }

    // 初始化OpenGL程序

    glfwSetMouseButtonCallback(window, 
        [](GLFWwindow* window, int button, int action, int mods) 
        {
            if (action == GLFW_RELEASE)
            {
                double xpos, ypos;
                glfwGetCursorPos(window, &xpos, &ypos);
                cout << "release x:"<<xpos<<" y:"<< ypos << endl;
            }
        }
    );
    glfwSetKeyCallback(window, 
        [](GLFWwindow* window, int key, int scancode, int action, int mods)
        {
            if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE)
                glfwSetWindowShouldClose(window, true);
        }
    );

    while (!glfwWindowShouldClose(window))
    {
        /// 绘制OpenGL内容
        glfwSwapBuffers(window);
        glfwPollEvents();

    }

    glfwDestroyWindow(window);
    exit(EXIT_SUCCESS);
}

完整WinAPI(ATL)代码

// WinAPI
#include <GL/glew.h>
#include <Windows.h>
#include <Windowsx.h>

#include <atlbase.h>
#include <atlwin.h>

#include <iostream>

using std::cout;
using std::endl;

std::ostream& operator<< (std::ostream& os, POINT pt)
{
    os << "{x:" << pt.x << " y:" << pt.y << "}";
    return os;
}
int glProgramInit()
{
 // 在此初始化OpenGL程序
}

class CMyWindow : public CWindowImpl<CMyWindow>
{
public:

    CMyWindow() {}
    virtual ~CMyWindow() {}

    /////////////////////////// 消息处理函数 /////////////////////////////////

    LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        HDC hdc;
        // display();
        SwapBuffers(hdc = this->GetWindowDC());
        ReleaseDC(hdc);
        return 0;
    }
    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        // glProgramDestroy();
        PostQuitMessage(0);
        return 0;
    }

    HGLRC initOpenGL(HDC hdc)
    {
        using std::cerr;
        using std::endl;
        PIXELFORMATDESCRIPTOR pfd =
        {
            sizeof(PIXELFORMATDESCRIPTOR), 1,
            PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,    // 标志位
            PFD_TYPE_RGBA,        // 帧缓冲类型:RGBA或调色板
            32,                   // 帧缓冲颜色深度
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            24,                   // 深度缓冲位数
            8,                    // 模板缓冲位数
            0,                    // 辅助缓冲数量
            PFD_MAIN_PLANE, 0, 0, 0, 0
        };

        int  newPixelFormat = ChoosePixelFormat(hdc, &pfd);
        SetPixelFormat(hdc, newPixelFormat, &pfd);

        HGLRC hglrc = wglCreateContext(hdc);
        wglMakeCurrent(hdc, hglrc);

        GLenum err = glewInit();
        if (GLEW_OK != err)
        {
            cerr << "GLEW Error: " << glewGetErrorString(err) << endl;
            return 0;
        }
        return hglrc;
    }
    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        RECT rc = CWindow::rcDefault;
        this->GetWindowRect(&rc);
        rc.right  = rc.left + width;
        rc.bottom = rc.top  + height;
        this->SetWindowPos(HWND_TOP, &rc, SWP_NOZORDER);

        HDC hdc;
        this->initOpenGL(hdc = this->GetWindowDC());
        ReleaseDC(hdc);

        glProgramInit();
        return 0;
    }
    LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        using std::cout;
        using std::endl;
        POINT c{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
        cout<< c<< endl;

        InvalidateRect(0, false);
        return 0;
    }

    BEGIN_MSG_MAP(CMyWindow)
        MESSAGE_HANDLER(WM_DESTROY,   OnDestroy)
        MESSAGE_HANDLER(WM_PAINT,     OnPaint)
        MESSAGE_HANDLER(WM_CREATE,    OnCreate)
        MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
    END_MSG_MAP()
};

using namespace std;

int main()
{
    CMyWindow cwnd;

    HWND hWnd = cwnd.Create(NULL, CWindow::rcDefault, L"Hello", WS_OVERLAPPEDWINDOW);
    cwnd.ShowWindow(SW_SHOW);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
    {
        DispatchMessage(&msg);
    }
    return 0;
}

内容的提问来源于stack exchange,提问作者armagedescu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:00:18