本文介紹如何操作windows系統游標。正常我們設定/隱藏游標,只能改變當前窗體或者控制元件範圍,無法全域性操作windows游標。接到一個需求,想隱藏windows全域性的滑鼠游標顯示,下面講下如何操作
先了解下系統滑鼠游標,在滑鼠屬性-自定義列表中可以看到一共有13種型別,對應13種工作狀態:
作業系統提供了一組預定義的游標,如箭頭、手形、沙漏等,位於 C:\Windows\Cursors目錄下。
對應的Windows.Input.CursorType列舉:
1 public enum CursorType 2 { 3 None, 4 No, 5 Arrow, 6 AppStarting, 7 Cross, 8 Help, 9 IBeam, 10 SizeAll, 11 SizeNESW, 12 SizeNS, 13 SizeNWSE, 14 SizeWE, 15 UpArrow, 16 Wait, 17 Hand, 18 Pen, 19 ScrollNS, 20 ScrollWE, 21 ScrollAll, 22 ScrollN, 23 ScrollS, 24 ScrollW, 25 ScrollE, 26 ScrollNW, 27 ScrollNE, 28 ScrollSW, 29 ScrollSE, 30 ArrowCD, 31 }
游標顯示邏輯:
- 全域性游標設定:在桌面或非控制元件區域,使用預設系統游標。
- 視窗控制元件的設定:每個視窗控制元件可以設定自己的游標型別。當滑鼠移動到該控制元件上時,將自動切換到該設定的游標。如果未設定則顯示系統游標
- 當滑鼠移動、點選或執行其他操作時,系統會檢測並相應更新游標形狀。應用程式也可以改變拖放等操作的游標
對當前滑鼠狀態有獲取需求的,可以透過GetCursorInfo獲取,當前滑鼠游標id以及控制代碼:
1 private IntPtr GetCurrentCursor() 2 { 3 CURSORINFO cursorInfo; 4 cursorInfo.cbSize = Marshal.SizeOf(typeof(CURSORINFO)); 5 GetCursorInfo(out cursorInfo); 6 var cursorId = cursorInfo.hCursor; 7 var cursorHandle = CopyIcon(cursorId); 8 return cursorHandle; 9 }
那如何隱藏系統游標呢?系統游標可以透過SetSystemCursor function (winuser.h) - Win32 apps | Microsoft Learn函式設定,不過貌似沒有隱藏游標的入口
可以換個思路,建立一個空白游標即可。我做了一個blank.cur:自己動手製作 windows滑鼠游標檔案(.cur格式)-CSDN部落格然後隱藏系統游標:
1 private void HideCursor() 2 { 3 _cursorHandle = GetCurrentCursor(); 4 //替換為空白滑鼠游標 5 var cursorFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Blank.cur"); 6 IntPtr cursor = LoadCursorFromFile(cursorFile); 7 SetSystemCursor(cursor, OcrNormal); 8 }
恢復系統游標的顯示,將之前游標Handle設定回去:
1 var success = SetSystemCursor(_cursorHandle, OcrNormal);
以上是實現了當前游標的替換。但上面有介紹過滑鼠游標狀態有13種,會根據應用程式狀態進行切換,所以其它游標也要處理。
對13種游標都替換為空白游標,13種游標CursorId值在setSystemCursor文件有說明:
1 private readonly int[] _systemCursorIds = new int[] { 32512, 32513, 32514, 32515, 32516, 32642, 32643, 32644, 32645, 32646, 32648, 32649, 32650 }; 2 private readonly IntPtr[] _previousCursorHandles = new IntPtr[13]; 3 private void HideCursor() 4 { 5 for (int i = 0; i < _systemCursorIds.Length; i++) 6 { 7 var cursor = LoadCursor(IntPtr.Zero, _systemCursorIds[i]); 8 var cursorHandle = CopyIcon(cursor); 9 _previousCursorHandles[i] = cursorHandle; 10 //替換為空白滑鼠游標 11 var cursorFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Blank.cur"); 12 IntPtr blankCursor = LoadCursorFromFile(cursorFile); 13 SetSystemCursor(blankCursor, (uint)_systemCursorIds[i]); 14 } 15 }
執行驗證:系統桌面、應用窗體如VisualStudio以及網頁等游標編輯狀態,都成功隱藏
還原游標狀態:
1 private void ShowCursor() 2 { 3 for (int i = 0; i < _systemCursorIds.Length; i++) 4 { 5 SetSystemCursor(_previousCursorHandles[i], (uint)_systemCursorIds[i]); 6 } 7 }
用到的User32及引數類:
1 [DllImport("user32.dll", SetLastError = true)] 2 public static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName); 3 [DllImport("user32.dll")] 4 public static extern IntPtr CopyIcon(IntPtr cusorId); 5 [DllImport("user32.dll")] 6 public static extern IntPtr LoadCursorFromFile(string lpFileName); 7 [DllImport("user32.dll")] 8 public static extern bool SetSystemCursor(IntPtr hcur, uint id); 9 [DllImport("user32.dll")] 10 static extern bool GetCursorInfo(out CURSORINFO pci); 11 12 [StructLayout(LayoutKind.Sequential)] 13 public struct POINT 14 { 15 public Int32 x; 16 public Int32 y; 17 } 18 19 [StructLayout(LayoutKind.Sequential)] 20 public struct CURSORINFO 21 { 22 public Int32 cbSize; // Specifies the size, in bytes, of the structure. 23 // The caller must set this to Marshal.SizeOf(typeof(CURSORINFO)). 24 public Int32 flags; // Specifies the cursor state. This parameter can be one of the following values: 25 // 0 The cursor is hidden. 26 // CURSOR_SHOWING The cursor is showing. 27 public IntPtr hCursor; // Handle to the cursor. 28 public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor. 29 }
需要說明的是,系統游標修改請謹慎處理,游標修改後人工操作不太容易恢復,對應用程式退出、崩潰等情況做好游標恢復操作。
以上demo程式碼見:kybs00/HideSystemCursorDemo: 隱藏windows系統游標 (github.com)
參考資料:
AllAPI.net - Your #1 source for using API-functions in Visual Basic! (mentalis.org)
createCursor 函式 (winuser.h) - Win32 apps | Microsoft Learn
SetSystemCursor function (winuser.h) - Win32 apps | Microsoft Learn
關鍵字:自定義游標、隱藏/顯示游標、windows系統游標顯示