WindowsAPI-C#版_原始裝置輸入常用API
阿新 • • 發佈:2022-12-02
WindowsAPI-C#版_原始裝置輸入常用API:
/** *┌──────────────────────────────────────────────────────────────┐ *│ 描 述:WindowsAPI_鍵鼠、遊戲杆、觸控式螢幕和麥克風等輸入裝置 *│ 作 者:執筆小白 *│ 版 本:1.0 *│ 建立時間:2022-11-13 15:40:56 *└──────────────────────────────────────────────────────────────┘ *┌──────────────────────────────────────────────────────────────┐ *│ 名稱空間: WindowAPIHelper.API *│ 類 名:WindowsAPI_KeyboardAndMouseInput *└──────────────────────────────────────────────────────────────┘ */ using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace WindowAPIHelper.API { /// <summary> /// WindowsAPI_鍵鼠、遊戲杆、觸控式螢幕和麥克風等輸入裝置 /// </summary> public class WindowsAPI_KeyboardAndMouseInput { #region 常用 /// <summary> /// 註冊提供原始輸入資料的裝置 /// 若要接收 WM_INPUT 訊息,應用程式必須先使用 RegisterRawInputDevices 註冊原始輸入裝置。 預設情況下,應用程式不會接收原始輸入。 /// </summary> /// <param name="pRawInputDevice">表示提供原始輸入的裝置,RAWINPUTDEVICE[]陣列</param> /// <param name="uiNumDevices">pRawInputDevices 指向的 RAWINPUTDEVICE 結構數。</param> /// <param name="cbSize">RAWINPUTDEVICE 結構的大小(以位元組為單位)</param> /// <returns>如果函式成功,則為 TRUE;否則為 FALSE。 如果函式失敗,請呼叫 GetLastError 以獲取詳細資訊。</returns> [DllImport("User32.dll")] public extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize); /// <summary> /// 檢索有關原始輸入裝置的資訊 /// </summary> /// <param name="hDevice">原始輸入裝置的控制代碼</param> /// <param name="uiCommand">指定將在 pData 中返回哪些資料 (uint)</param> /// <param name="pData">指向包含 uiCommand 指定的資訊的緩衝區的指標(如果 uiCommandRIDI_DEVICEINFO,請將RID_DEVICE_INFO的cbSize 成員設定為sizeof(RID_DEVICE_INFO)呼叫 GetRawInputDeviceInfo 之前。)</param> /// <param name="pcbSize">如果成功,此函式將返回一個非負數,指示覆制到 pData 的位元組數。如果 pData 不足以容納資料,則函式返回 -1。 如果 pData 為 NULL,則函式返回值為零。</param> /// <returns></returns> [DllImport("User32.dll")] public extern static uint GetRawInputDeviceInfo(IntPtr hDevice, UiCommand uiCommand, IntPtr pData, ref uint pcbSize); /// <summary> /// 從指定裝置檢索原始輸入 /// </summary> /// <param name="hRawInput">控制代碼</param> /// <param name="uiCommand">指定將在 pData 中返回哪些資料 (uint)</param> /// <param name="pData">指向 來自 RAWINPUT 結構的資料的指標。 這取決於 uiCommand 的值。 如果 pData 為 NULL,則緩衝區的所需大小在 *mbSize 中返回。</param> /// <param name="pcbSize">pData 中資料的大小(以位元組為單位)。</param> /// <param name="cbSizeHeader">RAWINPUTHEADER 結構的大小(以位元組為單位)。</param> /// <returns></returns> [DllImport("User32.dll")] public extern static uint GetRawInputData(IntPtr hRawInput, UiCommand uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader); /// <summary> /// 從指定裝置檢索原始輸入資料組 /// </summary> /// <param name="pData">指向 來自 RAWINPUT 結構的資料的指標。 這取決於 uiCommand 的值。 如果 pData 為 NULL,則緩衝區的所需大小在 *mbSize 中返回。</param> /// <param name="pcbSize">pData 中資料的大小(以位元組為單位)。</param> /// <param name="cbSizeHeader">RAWINPUTHEADER 結構的大小(以位元組為單位)。</param> /// <returns></returns> [DllImport("User32.dll")] public extern static uint GetRawInputBuffer(IntPtr pData, ref uint pcbSize, uint cbSizeHeader); // tagRAWINPUTHEADER(包含原始輸入資料的一部分的標頭資訊) 略:可以使用GetRawInputData // RAWINPUT函式(原始輸入) 略:可以使用GetRawInputData #endregion 常用 #region 列舉、結構等資料型別 /// <summary> /// 指定將在 pData 中返回哪些資料 (uint) /// </summary> public enum UiCommand { #region getRawInputData 函式(從指定裝置檢索原始輸入) RID_INPUT = 0x10000003, // 從 RAWINPUT 結構獲取標頭資訊。 RID_HEADER = 0x10000005, // 從 RAWINPUT 結構獲取原始資料。 #endregion getRawInputData 函式 #region GetRawInputDeviceInfo 函式(檢索有關原始輸入裝置的資訊) RIDI_PREPARSEDDATA = 0x20000005, // pData 指向 頂級集合預分析資料的緩衝區的PHIDP_PREPARSED_DATA指標。 RIDI_DEVICENAME = 0x20000007, // pData 指向包含 裝置介面名稱的字串。 RIDI_DEVICEINFO = 0x2000000b, // pData 指向 RID_DEVICE_INFO結構。 #endregion GetRawInputDeviceInfo 函式 } /// <summary> /// RAWINPUTDEVICE(原始輸入裝置的資訊_與儲存裝置資訊有關聯的資訊) /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTDEVICE { /// <summary> /// 原始輸入裝置的頂級集合使用情況頁。 /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort usUsagePage; /// <summary> /// 原始輸入裝置的頂級集合使用情況 ID /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort usUsage; /// <summary> /// 指定如何解釋 usUsagePage 和 usUsage 提供的資訊的模式標誌。 /// 預設情況下,只要具有視窗焦點,作業系統就會從具有指定 頂級集合 的裝置傳送原始輸入, (TLC) 到已註冊的應用程式。 /// </summary> [MarshalAs(UnmanagedType.U4)] public DwFlags dwFlags; /// <summary> /// 目標視窗的控制代碼。 如果 為 NULL ,則它遵循鍵盤焦點。 /// </summary> public IntPtr hwndTarget; } /// <summary> /// 原始輸入裝置的資訊_裝置有關的資訊 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTHEADER { /// <summary> /// 輸入裝置的型別(滑鼠、鍵盤、不是鍵盤或滑鼠的某些裝置) /// </summary> [MarshalAs(UnmanagedType.U4)] public DwType dwType; // 輸入裝置的型別(滑鼠、鍵盤、不是鍵盤或滑鼠的某些裝置) /// <summary> /// 整個輸入資料包的大小(以位元組為單位)。 這包括 RAWINPUT 加上 RAWHID 可變長度陣列中可能的額外輸入報告。 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwSize; // 整個輸入資料包的大小(以位元組為單位)。 這包括 RAWINPUT 加上 RAWHID 可變長度陣列中可能的額外輸入報告。 /// <summary> /// 生成原始輸入資料的裝置的控制代碼。 /// </summary> public IntPtr hDevice; // 生成原始輸入資料的裝置的控制代碼。 /// <summary> /// 在WM_INPUT訊息的 wParam 引數中傳遞的值。 /// </summary> [MarshalAs(UnmanagedType.U4)] public int wParam; // 在WM_INPUT訊息的 wParam 引數中傳遞的值。 } /// <summary> /// 原始輸入資訊的結構 /// </summary> [StructLayout(LayoutKind.Explicit)] public struct RAWINPUT { /// <summary> /// 標頭資訊 /// </summary> [FieldOffset(0)] public RAWINPUTHEADER header; /// <summary> /// 滑鼠資訊 /// </summary> [FieldOffset(16)] public RAWMOUSE mouse; /// <summary> /// 鍵盤資訊 /// </summary> [FieldOffset(16)] public RAWKEYBOARD keyboard; /// <summary> /// 不是鍵盤或滑鼠的某些裝置 /// </summary> [FieldOffset(16)] public RAWHID hid; } #region 定義來自任何裝置的原始輸入資料 /// <summary> /// 定義來自任何裝置的原始輸入資料 /// </summary> [StructLayout(LayoutKind.Explicit)] public struct RID_DEVICE_INFO { /// <summary> /// RID_DEVICE_INFO結構的大小(以位元組為單位) /// </summary> [FieldOffset(0)] public int cbSize; /// <summary> /// 原始輸入資料的型別 /// </summary> [FieldOffset(4)] public DwType dwType; /// <summary> /// 定義滑鼠 的RID_DEVICE_INFO_MOUSE 結構;dwType=RIM_TYPEMOUSE時有值 /// </summary> [FieldOffset(8)] public RID_DEVICE_INFO_MOUSE mouse; /// <summary> /// 定義鍵盤 的RID_DEVICE_INFO_KEYBOARD 結構;dwType=RIM_TYPEKEYBOARD時有值 /// </summary> [FieldOffset(8)] public RID_DEVICE_INFO_KEYBOARD keyboard; /// <summary> /// 定義 HID 裝置的 RID_DEVICE_INFO_HID 結構;dwType=RIM_TYPEHID時有值 /// </summary> [FieldOffset(8)] public RID_DEVICE_INFO_HID hid; } /// <summary> /// 定義來自指定滑鼠的原始輸入資料(備註,對於滑鼠,“使用情況”頁為 1,使用情況為 2) /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RID_DEVICE_INFO_MOUSE { /// <summary> /// 滑鼠裝置標識屬性的位欄位 /// </summary> [MarshalAs(UnmanagedType.U4)] public DwId dwId; /// <summary> /// 滑鼠的按鈕數 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwNumberOfButtons; /// <summary> /// 每秒資料點數。 此資訊可能不適用於每個滑鼠裝置。 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwSampleRate; /// <summary> /// 如果滑鼠具有用於水平滾動的滾輪,則為 TRUE;否則為 FALSE。Windowsxp: 僅從 Windows Vista 開始支援此成員。 /// </summary> [MarshalAs(UnmanagedType.U4)] public int fHasHorizontalWheel; // true存為int,用bool可能有bug } /// <summary> /// 定義來自指定鍵盤的原始輸入資料 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RID_DEVICE_INFO_KEYBOARD { /// <summary> /// 鍵盤的型別 /// </summary> [MarshalAs(UnmanagedType.U4)] public DwType dwType; /// <summary> /// 鍵盤的特定於供應商的子型別 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwSubType; /// <summary> /// 掃描程式碼模式。通常為1,這意味著使用“掃描程式碼集1” /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwKeyboardMode; /// <summary> /// 鍵盤上的函式鍵數 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwNumberOfFunctionKeys; /// <summary> /// 鍵盤上的 LED 指示器數 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwNumberOfIndicators; /// <summary> /// 鍵盤上的鍵總數 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwNumberOfKeysTotal; } /// <summary> /// 定義來自指定人機介面裝置 (HID) 的原始輸入資料 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RID_DEVICE_INFO_HID { /// <summary> /// HID 的供應商識別符號 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwVendorId; /// <summary> /// HID 的產品識別符號 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwProductId; /// <summary> /// HID 的版本號 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwVersionNumber; /// <summary> /// 裝置的頂級集合使用情況頁 /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort usUsagePage; /// <summary> /// 裝置的頂級集合使用情況 /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort usUsage; } #endregion 定義來自任何裝置的原始輸入資料 #region 原始輸入資訊的結構 /// <summary> /// 原始輸入來自滑鼠資訊 /// </summary> [StructLayout(LayoutKind.Explicit)] public struct RAWMOUSE { /// <summary> /// 設定獲取滑鼠的相對移動還是絕對移動 /// </summary> [MarshalAs(UnmanagedType.U2)] [FieldOffset(0)] public UsFlags usFlags; #region DUMMYUNIONNAME 結構 /// <summary> /// 按鈕標識 /// </summary> [MarshalAs(UnmanagedType.U4)] [FieldOffset(4)] public ulong ulButtons; /// <summary> /// 按鈕資訊 /// </summary> [FieldOffset(4)] public DUMMYSTRUCTNAME buttonsStr; #endregion DUMMYUNIONNAME 結構 /// <summary> /// 滑鼠按鈕的原始狀態。Win32子系統不使用此成員。 /// </summary> [MarshalAs(UnmanagedType.U4)] [FieldOffset(8)] public ulong ulRawButtons; /// <summary> /// X方向的運動。相對運動或絕對運動取決於usFlags的值。 /// </summary> [FieldOffset(12)] public long lLastX; /// <summary> /// Y方向的運動。相對運動或絕對運動取決於usFlags的值。 /// </summary> [FieldOffset(16)] public long lLastY; /// <summary> /// 事件裝置的特定附加資訊。 /// </summary> [MarshalAs(UnmanagedType.U4)] [FieldOffset(20)] public ulong ulExtraInformation; } /// <summary> /// 原始輸入來自鍵盤資訊 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RAWKEYBOARD { /// <summary> /// 指定與按鍵關聯的掃描程式碼。見部落格補充-鍵值Key /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort MakeCode; /// <summary> /// 掃描程式碼資訊的標誌 /// </summary> [MarshalAs(UnmanagedType.U2)] public RAWKEYBOARD_Flags Flags; /// <summary> /// 保留;必須為零 /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort Reserved; /// <summary> /// 相應的 舊虛擬金鑰程式碼 /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort VKey; /// <summary> /// 相應的 舊式鍵盤視窗訊息,例如 WM_KEYDOWN、 WM_SYSKEYDOWN等 /// </summary> [MarshalAs(UnmanagedType.U4)] public uint Message; /// <summary> /// 事件特定於裝置的其他資訊 /// </summary> [MarshalAs(UnmanagedType.U4)] public ulong ExtraInformation; } /// <summary> /// 原始輸入來自不是鍵盤或滑鼠的某些裝置 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct RAWHID { /// <summary> /// bRawData中每個HID輸入的大小(以位元組為單位)。 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwSizHid; /// <summary> /// bRawData中HID輸入的數量。 /// </summary> [MarshalAs(UnmanagedType.U4)] public int dwCount; /// <summary> /// 原始輸入資料,作為位元組陣列。 /// </summary> [MarshalAs(UnmanagedType.U4)] public byte bRawData; } #endregion 原始輸入資訊的結構 /// <summary> /// WM_INPUT:輸入裝置的型別(滑鼠、鍵盤、不是鍵盤或滑鼠的某些裝置) /// 輸入裝置的型別(再細分型別) /// </summary> public enum DwType { #region 原始輸入來自哪個裝置 /// <summary> /// 原始輸入來自滑鼠 /// </summary> RIM_TYPEMOUSE = 0, // 原始輸入來自滑鼠 /// <summary> /// 原始輸入來自鍵盤 /// </summary> RIM_TYPEKEYBOARD = 1, // 原始輸入來自鍵盤 /// <summary> /// 原始輸入來自不是鍵盤或滑鼠的某些裝置 /// </summary> RIM_TYPEHID = 2, // 原始輸入來自不是鍵盤或滑鼠的某些裝置 #endregion 原始輸入來自哪個裝置 #region 鍵盤型別 增強型101或102鍵鍵盤 = 0x4, 日語鍵盤 = 0x7, 朝鮮語鍵盤 = 0x8, 未知型別或HID鍵盤= 0x51 #endregion 鍵盤型別 } /// <summary> /// 指定如何解釋 usUsagePage 和 usUsage 提供的資訊的模式標誌。 /// </summary> public enum DwFlags { Default = 0x00000000, // 預設 RIDEV_REMOVE = 0x00000001, // 從包含列表中刪除頂級集合。 這會告知作業系統停止從與頂級集合匹配的裝置讀取。 RIDEV_EXCLUDE = 0x00000010, // 指定讀取完整使用情況頁時要排除的頂級集合。 此標誌僅影響已使用 RIDEV_PAGEONLY 指定的 TLC。 RIDEV_PAGEONLY = 0x00000020, // 指定其頂級集合來自指定 usUsagePage 的所有裝置。 請注意, usUsage 必須為零。 若要排除特定的頂級集合,請使用 RIDEV_EXCLUDE。 RIDEV_NOLEGACY = 0x00000030, // 阻止 usUsagePage 或 usUsage 指定的任何裝置生成 舊訊息。 這僅適用於滑鼠和鍵盤。 RIDEV_INPUTSINK = 0x00000100, // 如果已設定,則即使呼叫方不在前臺,呼叫方也能夠接收輸入。 請注意,必須指定 hwndTarget 。 RIDEV_CAPTUREMOUSE = 0x00000200, // 滑鼠按鈕單擊不會啟用另一個視窗。 僅當為滑鼠裝置指定了RIDEV_NOLEGACY時,才能指定RIDEV_CAPTUREMOUSE。 RIDEV_NOHOTKEYS = 0x00000200, // 不會處理應用程式定義的鍵盤裝置熱鍵。 但是,系統熱鍵;例如,仍處理 Alt+TAB 和 Ctrl+ALT+DEL。 預設情況下,將處理所有鍵盤熱鍵。 即使未指定RIDEV_NOLEGACY且 hwndTarget 為 NULL,也可以指定RIDEV_NOHOTKEYS。 RIDEV_APPKEYS = 0x00000400, // 處理應用程式命令金鑰。 僅當為鍵盤裝置指定了RIDEV_NOLEGACY時,才能指定RIDEV_APPKEYS。 RIDEV_EXINPUTSINK = 0x00001000, // 僅當前臺應用程式未處理它時,呼叫方才能在後臺接收輸入。 換句話說,如果未為原始輸入註冊前臺應用程式,則註冊的後臺應用程式將收到輸入。在 Windows Vista 之前不支援此標誌 RIDEV_DEVNOTIFY = 0x00002000 // 允許呼叫方接收裝置到達和裝置刪除 WM_INPUT_DEVICE_CHANGE 通知。在 Windows Vista 之前不支援此標誌 } #region 滑鼠原始輸入有關型別 /// <summary> /// 設定獲取滑鼠的相對移動還是絕對移動 /// </summary> public enum UsFlags { MOUSE_MOVE_RELATIVE = 0x00, // 相對於最後一個滑鼠位置的滑鼠移動資料。 MOUSE_MOVE_ABSOLUTE = 0x01, // 基於絕對位置的滑鼠移動資料。 MOUSE_VIRTUAL_DESKTOP = 0x02, // 滑鼠座標對映到虛擬桌面(對於多監視器系統)。 MOUSE_ATTRIBUTES_CHANGED = 0x04, // 滑鼠屬性已更改;應用程式需要查詢滑鼠屬性。 MOUSE_MOVE_NOCOALESCE = 0x08, // 此滑鼠移動事件未合併。預設情況下,可以合併滑鼠移動事件。Windows XP/2000:不支援此值。 } /// <summary> /// 標識按鈕觸發事件(標識了哪個鍵發生了什麼事件) /// </summary> public enum UsButtonFlags { RI_MOUSE_BUTTON_1_DOWN = 0x0001, // RI_MOUSE_LEFT_BUTTON_DOWN RI_MOUSE_BUTTON_1_UP = 0x0002, // RI_MOUSE_LEFT_BUTTON_UP RI_MOUSE_BUTTON_2_DOWN = 0x0004, // RI_MOUSE_RIGHT_BUTTON_DOWN RI_MOUSE_BUTTON_2_UP = 0x0008, // RI_MOUSE_RIGHT_BUTTON_UP RI_MOUSE_BUTTON_3_DOWN = 0x0010, // RI_MOUSE_MIDDLE_BUTTON_DOWN RI_MOUSE_BUTTON_3_UP = 0x0020, // RI_MOUSE_MIDDLE_BUTTON_UP RI_MOUSE_BUTTON_4_DOWN = 0x0040, // X_BUTTON1 changed to down. RI_MOUSE_BUTTON_4_UP = 0x0080, // X_BUTTON1 changed to up. RI_MOUSE_BUTTON_5_DOWN = 0x0100, // X_BUTTON2 changed to down. RI_MOUSE_BUTTON_5_UP = 0x0200, // X_BUTTON2 changed to up. RI_MOUSE_WHEEL = 0x0400, // 滑鼠滾輪,值儲存在inusButtonData中;正值表示車輪向前滾動,遠離使用者;負值表示車輪向後滾動。 RI_MOUSE_HWHEEL = 0x0800, // 滑鼠水平滾輪,值儲存在inusButtonData中;正值表示車輪向右旋轉;負值表示車輪向左旋轉。 } #endregion 滑鼠原始輸入有關型別 #region 鍵盤原始輸入有關型別 /// <summary> /// 按鍵掃描程式碼資訊的標誌 /// </summary> public enum RAWKEYBOARD_Flags { RI_KEY_MAKE = 0, // 金鑰關閉 RI_KEY_BREAK = 1, // 金鑰已啟動 RI_KEY_E0 = 2, // 掃描程式碼具有 E0 字首 RI_KEY_E1 = 4, // 掃描程式碼具有 E1 字首 } #endregion 鍵盤原始輸入有關型別 /// <summary> /// 按鈕資訊 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct DUMMYSTRUCTNAME { /// <summary> /// 標識按鈕觸發事件(標識了哪個鍵發生了什麼事件) /// </summary> [MarshalAs(UnmanagedType.U2)] public UsButtonFlags usButtonFlags; /// <summary> /// 按鈕事件資訊資料 /// </summary> [MarshalAs(UnmanagedType.U2)] public ushort usButtonData; } /// <summary> /// 滑鼠裝置標識屬性的位欄位 /// </summary> public enum DwId { MOUSE_HID_HARDWARE = 0x0080, // HID 滑鼠 WHEELMOUSE_HID_HARDWARE = 0x0100, // HID 滾輪滑鼠 HORIZONTAL_WHEEL_PRESENT = 0x8000, // 帶有水平滾輪的滑鼠 } #endregion 列舉、結構等資料型別 } }