在GLFW的无边框全屏窗口中,明明被设定为不隐藏光标,光标却仍然不可见

编程语言 2026-07-10

我最近开始了一个只用GLFW、GLAD和 GLM的游戏开发项目。一路顺风,直到我试图把窗口从普通的1280x720改为(无边框)全屏窗口:

我的光标在其他窗口上是可见且可用的,但在游戏聚焦时,光标在主显示器上会变得不可见。光标仍然可以在窗口后面正常移动,只是完全看不见。

通过Discord屏幕共享的朋友看到游戏在第一帧就像被冻结了一样,但却能看到我的光标在屏幕上移动,而我这边看到的游戏却很正常却没有光标。不太确定这意味着什么,但或许有帮助……

下面是负责创建窗口的代码。这是代码中唯一对窗口有操作的地方。即使(我认为)我明确把光标设为可见,我似乎仍然无法阻止它在聚焦的游戏窗口上被隐藏:

#include <GLFW/glfw3.h>

class WindowSystem {
    public:
        WindowSystem();
        ~WindowSystem();

        [[nodiscard]] GLFWwindow* getWindow() const { return window; }
        [[nodiscard]] bool keepWindowOpen() const { return !glfwWindowShouldClose(window); }

        void windowSwap() const;

        static int WIDTH;
        static int HEIGHT;

    private:
        GLFWwindow* window;
};
#include <iostream>
#include <glad/glad.h>
#include "systems/core/WindowSystem.hpp"

// Defaults
int WindowSystem::WIDTH = 1280;
int WindowSystem::HEIGHT = 720;

WindowSystem::WindowSystem() {
    if (!glfwInit()) std::cerr << "Failed to initialize GLFW" << std::endl;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWmonitor* monitor = glfwGetPrimaryMonitor();
    const GLFWvidmode* mode = glfwGetVideoMode(monitor);
    WIDTH = mode->width;
    HEIGHT = mode->height;

    glfwWindowHint(GLFW_RED_BITS, mode->redBits);
    glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
    glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
    glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
    glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "MV_Game", nullptr, nullptr);
    if (window == nullptr) std::cerr << "Failed to open GLFW window" << std::endl;

    glfwMakeContextCurrent(window);
    glfwSetWindowPos(window, 0, 0);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

    if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress)))
        std::cerr << "Failed to initialize GLAD" << std::endl;
}

WindowSystem::~WindowSystem() {
    glfwDestroyWindow(window);
    glfwTerminate();
}

void WindowSystem::windowSwap() const {
    glfwSwapBuffers(window);
    glfwPollEvents();
}

glfwGetKeyglfwGetCursorPosglfwSetMouseButtonCallback 这样的函数虽然按预期完美工作,顺便说一句,是光标在明确被设置为不可见时却被隐藏了。我已经尝试了我能找到的所有方法,现在已经完全束手无策。要在我的电脑上复现,只需要下面这个main,当然还要GLFW和 GLAD。

#include <memory>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "systems/core/WindowSystem.hpp"

int main() {
    const auto windowSystem = std::make_unique<WindowSystem>();
    while (!glfwWindowShouldClose(windowSystem->getWindow())) {
        glClear(GL_COLOR_BUFFER_BIT);
        // Rendering stuff
        windowSystem->windowSwap();
    }
}

更新

虽然窗口初始化确实还有改进空间,但真正的元凶最终是Medal(裁剪软件)。虽然关闭Medal似乎可以修复光标问题,但这并不理想……此外,在Discord的屏幕共享中,窗口看起来仍然像是冻结。

解决方案

我认为光标这一行并不是这里的实际问题所在。

这个:

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

已经是让GLFW使用正常可见光标的正确方式了。所以如果这个:

std::cout << glfwGetInputMode(window, GLFW_CURSOR) << "\n";

打印出 GLFW_CURSOR_NORMAL,那么GLFW并不是故意隐藏它。

更大的问题在于你的窗口并没有真正创建为全屏。你是这样做的:

window = glfwCreateWindow(WIDTH, HEIGHT, "MV_Game", nullptr, nullptr);

因为monitor参数是 nullptr,这会创建一个普通的窗口模式窗口。然后你移除装饰并把它移动到 (0, 0),看起来像无边框全屏,实际上仍然只是一个普通的无装饰窗口。

先尝试把它真正创建为一个全屏窗口:

GLFWmonitor* monitor = glfwGetPrimaryMonitor();
const GLFWvidmode* mode = glfwGetVideoMode(monitor);

WIDTH = mode->width;
HEIGHT = mode->height;

glfwWindowHint(GLFW_RED_BITS, mode->redBits);
glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);

window = glfwCreateWindow(WIDTH, HEIGHT, "MV_Game", monitor, nullptr);
if (!window)
    throw std::runtime_error("Failed to open GLFW window");

glfwMakeContextCurrent(window);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

另外,为了真正的全屏,请移除以下这些:

glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
glfwSetWindowPos(window, 0, 0);

它们是给普通窗口用的。全屏窗口不需要手动禁用装饰。

如果你真的想要伪无边框全屏,不要把 (0, 0) 硬编码。使用显示器的位置:

int mx, my;
glfwGetMonitorPos(monitor, &mx, &my);

glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);

window = glfwCreateWindow(WIDTH, HEIGHT, "MV_Game", nullptr, nullptr);
if (!window)
    throw std::runtime_error("Failed to open GLFW window");

glfwSetWindowPos(window, mx, my);
glfwMakeContextCurrent(window);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

(0, 0) 硬编码在多显示器设置上可能会出错,即使大多数时候看起来没问题。

Discord的情况也让我觉得这不一定是你的输入代码的问题。Discord常常把游戏和光标作为分层捕获。因此朋友看到光标而游戏看起来像被冻结,并不能真正证明GLFW在隐藏它。听起来更像是Windows/GPU/合成器的问题。

接下来我会检查这些:

std::cout << glfwGetVersionString() << "\n";
std::cout << glfwGetInputMode(window, GLFW_CURSOR) << "\n";
std::cout << (glfwGetWindowMonitor(window) != nullptr) << "\n";

如果光标模式是正常的但仍然消失,就停止调试鼠标输入。更新GLFW,更新GPU驱动,禁用诸如Discord、NVIDIA、AMD、Xbox Game Bar等覆盖工具。这更像是平台/显示的问题,而不是GLFW的输入问题。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章