如何编程实现全局鼠标光标替换与自动恢复功能?
实现方案(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
相关产品推荐
相关产品推荐

