C#实现Windows全桌面全局隐藏鼠标光标(不限窗口焦点)
Windows平台全局桌面鼠标光标隐藏实现方案
你之前尝试的两种方案失效的根本原因:
Cursor.Hide是WinForms封装的线程级API,仅对调用线程所属的窗口生效,无法跨进程作用于全局桌面ShowCursor同样是线程级的显示计数接口,仅在调用线程持有前台窗口焦点时才会生效,全局场景下调用无效果
核心实现思路
使用user32.dll提供的系统级光标替换接口SetSystemCursor,触发隐藏时将系统标准光标临时替换为1x1大小的完全透明光标,该修改对所有前台应用全局生效;需要恢复时直接重置系统光标配置即可。
该方案不会修改鼠标实际坐标,完全匹配系统原生「打字时隐藏指针」的表现:光标在原位置直接隐藏,移动后在原位置重新显示,不会出现移动到边角方案带来的操作位置偏移、干扰其他软件逻辑的问题。
核心实现代码(C#)
using System; using System.Drawing; using System.Runtime.InteropServices; internal static class GlobalCursorController { #region Win32 常量定义 // 系统标准光标类型ID private const int OCR_NORMAL = 32512; // 常规箭头光标 private const int OCR_IBEAM = 32513; // 文本输入I型光标 private const int OCR_HAND = 32649; // 链接手型光标 private const int OCR_WAIT = 32514; // 等待沙漏光标 private const int OCR_CROSS = 32515; // 十字选择光标 // 可根据需要补充调整大小、移动等其他光标类型ID private const uint SPI_SETCURSORS = 0x0057; private const uint SPIF_SENDCHANGE = 0x0002; #endregion #region Win32 API 声明 [DllImport("user32.dll", SetLastError = true)] private static extern bool SetSystemCursor(IntPtr hcur, uint id); [DllImport("user32.dll", SetLastError = true)] private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni); [DllImport("user32.dll")] private static extern IntPtr CopyCursor(IntPtr pcur); [DllImport("user32.dll")] private static extern bool DestroyCursor(IntPtr hCursor); [DllImport("user32.dll")] private static extern bool DestroyIcon(IntPtr hIcon); [DllImport("user32.dll")] private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); [DllImport("user32.dll")] private static extern IntPtr CreateIconIndirect(ref IconInfo icon); [StructLayout(LayoutKind.Sequential)] private struct IconInfo { public bool fIcon; public int xHotspot; public int yHotspot; public IntPtr hbmMask; public IntPtr hbmColor; } #endregion private static IntPtr _transparentCursor = IntPtr.Zero; /// <summary> /// 全局隐藏桌面所有光标 /// </summary> public static void Hide() { // 初始化透明光标资源 if (_transparentCursor == IntPtr.Zero) { using (Bitmap transparentBmp = new Bitmap(1, 1)) { transparentBmp.SetPixel(0, 0, Color.Transparent); IntPtr hIcon = transparentBmp.GetHicon(); IconInfo iconInfo = new IconInfo(); GetIconInfo(hIcon, ref iconInfo); iconInfo.fIcon = false; // 标记资源为光标而非图标 iconInfo.xHotspot = 0; iconInfo.yHotspot = 0; _transparentCursor = CreateIconIndirect(ref iconInfo); DestroyIcon(hIcon); } } // 将所有标准系统光标替换为透明光标 uint[] targetCursorIds = { OCR_NORMAL, OCR_IBEAM, OCR_HAND, OCR_WAIT, OCR_CROSS }; foreach (uint cursorId in targetCursorIds) { IntPtr cursorCopy = CopyCursor(_transparentCursor); SetSystemCursor(cursorCopy, cursorId); } } /// <summary> /// 恢复系统默认光标显示 /// </summary> public static void Show() { // 重置系统光标为默认配置 SystemParametersInfo(SPI_SETCURSORS, 0, IntPtr.Zero, SPIF_SENDCHANGE); // 释放透明光标资源 if (_transparentCursor != IntPtr.Zero) { DestroyCursor(_transparentCursor); _transparentCursor = IntPtr.Zero; } } }
使用注意事项
- 热键触发隐藏时直接调用
GlobalCursorController.Hide()即可,无需关注当前前台窗口所属进程,修改对所有应用全局生效 - 监听全局鼠标移动事件,检测到鼠标坐标变动时调用
GlobalCursorController.Show()即可实现移动自动恢复的效果 - 必须在程序退出、全局异常捕获逻辑中加入
Show()方法调用,避免程序异常退出后系统光标持续为透明状态 - 如果需要覆盖更多光标场景(比如窗口调整大小光标、移动光标),只需要在
targetCursorIds数组中补充对应光标类型ID即可
内容的提问来源于stack exchange,提问作者Ryan Griggs
相关产品推荐
相关产品推荐

