首页 > 解决方案 > SDL 鼠标移动事件在鼠标按钮按下事件类型下提供不一致的 xrel、yrel 值

问题描述

我尝试使用 SDL2 和 OpenGL 4.6 核心模式制作 3D 游戏,但我发现了一个让我感到困惑的问题,我不知道如何解决它,代码如下:

// SDL2 initialize
// Create a SDL2 window
// Create a OpenGL 4.6 core context
// GLAD initialize
// ImGui initialize

// SDL Settings
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE);

// main loop
bool done = false;
bool relative = false;
while (!done) {
    SDL_Event event;
    while(SDL_PollEvent(&event)) {
        if (event.type == SDL_MOUSEBUTTONDOWN) {
            if (event.button.button == SDL_BUTTON_LEFT) {
                relative = true;
            }
        }
        if (event.type == SDL_MOUSEBUTTONUP) {
            if (event.button.button == SDL_BUTTON_LEFT) {
                relative = false;
            }
        }
        if (event.type == SDL_MOUSEMOTION) {
            std::cout << "Mouse Motion Triggered: (" + std::to_string(event.motion.xrel) +  " ," + std::to_string(event.motion.yrel) + ")" << std::endl;
        }
    }

    if (relative) {
        SDL_SetRelativeMouseMode(SDL_TRUE);
    } else {
        SDL_SetRelativeMouseMode(SDL_FALSE);
    }

    // Render ImGui

    SDL_GL_SwapWindow(window);
}

如您所见,当我一直按住鼠标左键,然后将鼠标从屏幕的左上角移动到屏幕的右下角时,我希望鼠标的相对运动返回是这样的.

Mouse Motion Triggered: (11 ,6)
Mouse Motion Triggered: (13 ,8)
Mouse Motion Triggered: (14 ,8)
Mouse Motion Triggered: (14 ,8)
Mouse Motion Triggered: (16 ,9)
Mouse Motion Triggered: (15 ,7)
Mouse Motion Triggered: (11 ,6)
Mouse Motion Triggered: (10 ,6)

相对坐标 x 和 y 值都应该是正数,但不是,实际结果是这样的:

Mouse Motion Triggered: (1 ,1)
Mouse Motion Triggered: (2 ,2)
Mouse Motion Triggered: (-6 ,-4)
Mouse Motion Triggered: (3 ,3)
Mouse Motion Triggered: (1 ,1)
Mouse Motion Triggered: (-2 ,-3)
Mouse Motion Triggered: (2 ,2)
Mouse Motion Triggered: (1 ,1)
Mouse Motion Triggered: (-4 ,-4)
Mouse Motion Triggered: (3 ,3)
Mouse Motion Triggered: (-3 ,-3)
Mouse Motion Triggered: (1 ,1)
Mouse Motion Triggered: (-2 ,-2)
Mouse Motion Triggered: (1 ,2)
Mouse Motion Triggered: (-2 ,-2)

这导致我的鼠标位置强制锁定在屏幕中间,然后我尝试解决这个问题,我重写了事件处理程序的代码,如下所示:

if (event.type == SDL_MOUSEBUTTONDOWN) {
    if (event.button.button == SDL_BUTTON_LEFT) {
        relative = true;
        std::cout << "relative: " << relative << std::endl;
    }
    if (event.button.button == SDL_BUTTON_RIGHT) {
        relative = false;
        std::cout << "relative: " << relative << std::endl;
    }
}
if (event.type == SDL_MOUSEBUTTONUP) {
    // Now this event is empty.
}

我意识到如果我只是按下鼠标左键一次,然后向同一个方向移动鼠标,整个功能可以正常工作,但是如果我一直按住鼠标左键并向同一个方向移动鼠标呢?相对鼠标返回值event.motion.xrelevent.motion.yrel很奇怪,这些会给出一个相反的方向,迫使我的鼠标位置回到屏幕的中心,我不知道为什么会发生这种情况。

问题是什么?

环境细节

标签: c++eventssdlmouse

解决方案


我找到了导致xrelandyrel值变得如此扭曲的主要原因,那就是ImGui_ImplSDL2_NewFrame(window). 当我注释掉这段代码时,相对鼠标报告正常,但是如果我将此行添加到主循环中,相对鼠标会报告奇怪的坐标,迫使我的鼠标回到屏幕中心,我怀疑可能是 ImGui尝试控制鼠标事件,它与我完全不知道的东西有控制冲突。

我看到了源代码imgui_impl_sdl.cpp,但我仍然不知道为什么会发生这种情况,解决这个问题的方法是我制作了一个切换键,点击 TAB 键来控制相机或 GUI 的鼠标。

这是我的最新代码:

// SDL2 initialize
// Create a SDL2 window
// Create a OpenGL 4.6 core context
// GLAD initialize

// ImGui initialize
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui_ImplSDL2_InitForOpenGL(window, context);
ImGui_ImplOpenGL3_Init("#version 330");
ImGui::StyleColorsDark();
ImGuiIO &io = ImGui::GetIO();

// SDL Settings
SDL_SetHintWithPriority(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1", SDL_HINT_OVERRIDE);
SDL_SetRelativeMouseMode(SDL_TRUE);

// main loop
bool done = false;
while (!done) {
    SDL_Event event;
    while(SDL_PollEvent(&event)) {
        ImGui_ImplSDL2_ProcessEvent(&event);
        if (event.type == SDL_MOUSEMOTION) {
            std::cout << "Mouse Motion Triggered: (" + std::to_string(event.motion.xrel) +  " ," + std::to_string(event.motion.yrel) + ")" << std::endl;
        }
    }

    // Render ImGui
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplSDL2_NewFrame(window); // <-- this is the main reason
    //ImGui::NewFrame();
    //ImGui::Render();

    //ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
    SDL_GL_SwapWindow(window);
}
// Delete ImGui and SDL Context, Window and SDL_QUIT()

ImGui 版本:1.83


推荐阅读