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

如何编程实现全局鼠标光标替换与自动恢复功能?

实现方案(Windows C++)

1. 全局热键监听

使用RegisterHotKey注册全局热键,监听指定组合键(示例为Ctrl+Shift+H),触发光标隐藏逻辑。

示例代码:

#include <windows.h>

#define HOTKEY_ID 1
#define HOTKEY_MOD (MOD_CONTROL | MOD_SHIFT)
#define HOTKEY_KEY 'H'

// 保存全局状态
bool g_CursorHidden = false;
HCURSOR g_TransparentCursor = NULL;
HCURSOR g_OriginalCursors[OCR_LAST] = {0};
HHOOK g_MouseHook = NULL;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        case WM_HOTKEY:
            if (wParam == HOTKEY_ID) {
                g_CursorHidden = true;
                // 触发光标隐藏逻辑
                HideCursor();
                // 确保鼠标钩子已注册
                if (!g_MouseHook) {
                    g_MouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, GetModuleHandle(NULL), 0);
                }
            }
            return 0;
        case WM_DESTROY:
            UnregisterHotKey(hwnd, HOTKEY_ID);
            UnregisterMouseHook();
            RestoreCursor();
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    // 注册消息窗口(用于接收热键事件)
    const wchar_t CLASS_NAME[] = L"CursorHiderWndClass";
    WNDCLASS wc = {0};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
    if (!hwnd) return 0;

    // 注册热键
    if (!RegisterHotKey(hwnd, HOTKEY_ID, HOTKEY_MOD, HOTKEY_KEY)) {
        MessageBox(NULL, L"热键注册失败", L"错误", MB_ICONERROR);
        return 0;
    }

    // 消息循环
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

2. 获取当前光标类型

通过GetCursorInfo获取当前光标句柄,与系统预定义光标句柄对比,判断光标类型(如普通箭头、文本光标等)。

示例函数:

int GetCurrentCursorType() {
    CURSORINFO ci = {0};
    ci.cbSize = sizeof(CURSORINFO);
    if (!GetCursorInfo(&ci)) return -1;

    HCURSOR hArrow = LoadCursor(NULL, IDC_ARROW);
    HCURSOR hIBeam = LoadCursor(NULL, IDC_IBEAM);
    HCURSOR hWait = LoadCursor(NULL, IDC_WAIT);
    HCURSOR hCross = LoadCursor(NULL, IDC_CROSS);

    if (ci.hCursor == hArrow) return OCR_NORMAL;
    else if (ci.hCursor == hIBeam) return OCR_IBEAM;
    else if (ci.hCursor == hWait) return OCR_WAIT;
    else if (ci.hCursor == hCross) return OCR_CROSS;
    else return -1; // 应用自定义光标
}

3. 全局光标替换与恢复

3.1 创建透明光标

生成1x1全透明的光标资源,用于隐藏显示:

HCURSOR CreateTransparentCursor() {
    HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, NULL);
    ICONINFO ii = {0};
    ii.fIcon = FALSE;
    ii.hbmMask = hBitmap;
    ii.hbmColor = hBitmap;
    HCURSOR hCursor = CreateIconIndirect(&ii);
    DeleteObject(hBitmap);
    return hCursor;
}

3.2 隐藏与恢复系统光标

使用SetSystemCursor替换系统级光标,同时保存原始光标句柄用于恢复:

void HideCursor() {
    if (!g_TransparentCursor) {
        g_TransparentCursor = CreateTransparentCursor();
    }

    // 遍历常见系统光标类型,替换为透明样式
    int cursorTypes[] = {OCR_NORMAL, OCR_IBEAM, OCR_WAIT, OCR_CROSS, OCR_UPARROW};
    for (int type : cursorTypes) {
        if (!g_OriginalCursors[type]) {
            g_OriginalCursors[type] = CopyCursor(LoadCursor(NULL, MAKEINTRESOURCE(type)));
        }
        SetSystemCursor(g_TransparentCursor, type);
    }
}

void RestoreCursor() {
    // 恢复原始系统光标
    int cursorTypes[] = {OCR_NORMAL, OCR_IBEAM, OCR_WAIT, OCR_CROSS, OCR_UPARROW};
    for (int type : cursorTypes) {
        if (g_OriginalCursors[type]) {
            SetSystemCursor(g_OriginalCursors[type], type);
            DestroyCursor(g_OriginalCursors[type]);
            g_OriginalCursors[type] = NULL;
        }
    }
    if (g_TransparentCursor) {
        DestroyCursor(g_TransparentCursor);
        g_TransparentCursor = NULL;
    }
    g_CursorHidden = false;
}

3.3 处理应用自定义光标

通过**低级鼠标钩子(WH_MOUSE_LL)**全局监测鼠标动作,强制替换自定义光标为透明样式,鼠标移动时恢复:

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0 && g_CursorHidden) {
        if (wParam == WM_MOUSEMOVE) {
            // 检测到鼠标移动,恢复光标
            RestoreCursor();
            UnregisterMouseHook();
        } else {
            // 强制设置透明光标
            SetCursor(g_TransparentCursor);
        }
    }
    return CallNextHookEx(g_MouseHook, nCode, wParam, lParam);
}

void UnregisterMouseHook() {
    if (g_MouseHook) {
        UnhookWindowsHookEx(g_MouseHook);
        g_MouseHook = NULL;
    }
}

4. 关键注意事项

  • SetSystemCursor会永久修改系统光标,必须保存原始句柄并在退出时恢复,否则重启前系统光标会保持修改状态。
  • 低级鼠标钩子(WH_MOUSE_LL)无需单独DLL,直接在进程内运行,适合全局监测。
  • 所有GDI资源(光标、位图)需在退出时手动销毁,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:44:56