通过InjectTouchInput API模拟触屏操作
本文通过对InjectTouchInput API的封装,实现模拟触屏操作。微软官方文档说明,在调用InjectTouchInput API之前,需要调用InitializeTouchInjection API来配置触摸注入的上下文。下面直接上代码:
1 class InputInjector 2 { 3 public static void InitTouchInjection() 4 { 5 if (!InitializeTouchInjection()) 6 { 7 var errorCode = Marshal.GetLastWin32Error(); 8 throw new Win32Exception(errorCode); 9 } 10 } 11 12 public static bool InjectTouchDown(Point position, out int win32ErrorCode) 13 { 14 var touchDownOperation = InputPointerOptions.InRange | InputPointerOptions.InContact | InputPointerOptions.PointerDown; 15 var contact = CreatePointerTouchInfo(position, touchDownOperation); 16 return InjectTouchInput(1, new[] { contact }, out win32ErrorCode); 17 } 18 19 public static bool InjectTouchMove(Point position, out int win32ErrorCode) 20 { 21 var touchMoveOperation = InputPointerOptions.InRange | InputPointerOptions.InContact | InputPointerOptions.Update; 22 var contact = CreatePointerTouchInfo(position, touchMoveOperation); 23 return InjectTouchInput(1, new[] { contact }, out win32ErrorCode); 24 } 25 26 public static bool InjectTouchUp(Point position, out int win32ErrorCode) 27 { 28 var touchUpOperation = InputPointerOptions.InRange | InputPointerOptions.InContact | InputPointerOptions.PointerUp; 29 var contact = CreatePointerTouchInfo(position, touchUpOperation); 30 return InjectTouchInput(1, new[] { contact }, out win32ErrorCode); 31 } 32 33 public static bool InjectTouchInput(uint count, IEnumerable<PointerTouchInfo> contacts, out int win32ErrorCode) 34 { 35 win32ErrorCode = 0; 36 var isOk = InjectTouchInput(count, contacts.ToArray()); 37 if (!isOk) 38 { 39 win32ErrorCode = Marshal.GetLastWin32Error(); 40 } 41 42 return isOk; 43 } 44 45 private static PointerTouchInfo CreatePointerTouchInfo(Point position, InputPointerOptions operations) 46 { 47 PointerTouchInfo contact = new PointerTouchInfo(); 48 contact.PointerInfo.PointerType = PointerInputType.Touch; 49 contact.PointerInfo.PointerId = 1; 50 contact.PointerInfo.PointerFlags = operations; 51 contact.PointerInfo.PixelLocation.X = (int)position.X; 52 contact.PointerInfo.PixelLocation.Y = (int)position.Y; 53 contact.TouchFlags = TouchFlags.None; 54 contact.TouchMask = TouchMaskFlags.ContactArea | TouchMaskFlags.Orientation | TouchMaskFlags.Pressure; 55 //contact.Orientation = 0; 56 //contact.Pressure = 512; 57 contact.ContactArea.Left = (int)position.X - 5; 58 contact.ContactArea.Top = (int)position.Y - 5; 59 contact.ContactArea.Right = (int)position.X + 5; 60 contact.ContactArea.Bottom = (int)position.Y + 5; 61 62 return contact; 63 } 64 65 [DllImport("user32.dll", SetLastError = true)] 66 private extern static bool InitializeTouchInjection(uint maxCount = 256, int dwMode = (int)TouchFeedback.Default); 67 68 [DllImport("user32.dll", SetLastError = true)] 69 private extern static bool InjectTouchInput(uint count, PointerTouchInfo[] contacts); 70 71 enum TouchFeedback 72 { 73 Default = 1, 74 Indirect = 2, 75 None = 3 76 } 77 } 78 79 enum TouchOperation 80 { 81 None = 0, 82 TouchDown, 83 TouchMove, 84 TouchUp, 85 } 86 87 [StructLayout(LayoutKind.Sequential)] 88 public struct PointerTouchInfo 89 { 90 public InputPointerInfo PointerInfo; 91 public TouchFlags TouchFlags; 92 public TouchMaskFlags TouchMask; 93 public InputRectangle ContactArea; 94 public InputRectangle rawContactArea; 95 public uint Orientation; 96 public uint Pressure; 97 } 98 99 [StructLayout(LayoutKind.Sequential)] 100 public struct InputRectangle 101 { 102 public int Left; 103 public int Right; 104 public int Top; 105 public int Bottom; 106 } 107 108 [StructLayout(LayoutKind.Sequential)] 109 public struct InputPointerInfo 110 { 111 public PointerInputType PointerType; 112 public uint PointerId; 113 public uint FrameId; 114 public InputPointerOptions PointerFlags; 115 public IntPtr SourceDevice; 116 public IntPtr HwndTarget; 117 public InputPoint PixelLocation; 118 public InputPoint HimetricLocation; 119 public InputPoint PixelLocationRaw; 120 public InputPoint HimetricLocationRaw; 121 public int TimeOffsetInMilliseconds; 122 public uint HistoryCount; 123 public int InputData; 124 public int KeyStates; 125 public ulong PerformanceCount; 126 public PointerButtonChangeType ButtonChangeType; 127 } 128 129 public enum PointerInputType 130 { 131 Pointer = 1, 132 Touch, 133 Pen, 134 Mouse, 135 TouchPad, 136 } 137 138 [Flags] 139 public enum InputPointerOptions : uint 140 { 141 /// <summary> 142 /// No pointer modifier. Default. 143 /// </summary> 144 None = 0x0u, 145 /// <summary> 146 /// Indicates the arrival of a new pointer. 147 /// </summary> 148 New = 0x1u, 149 /// <summary> 150 /// Indicates that the pointer continues to exist. When this flag is not set, 151 /// it indicates the pointer has left detection range. 152 /// </summary> 153 InRange = 0x2u, 154 /// <summary> 155 /// Indicates that the pointer is in contact with the digitizer surface or area. 156 /// When this flag is not set, it indicates a hovering pointer. 157 /// </summary> 158 InContact = 0x4u, 159 /// <summary> 160 /// Indicates a primary action. 161 /// </summary> 162 FirstButton = 0x10u, 163 /// <summary> 164 /// Indicates a secondary action. 165 /// </summary> 166 SecondButton = 0x20u, 167 /// <summary> 168 /// Indicates that the pointer can perform actions beyond those available to non-primary pointers. 169 /// For example, when a primary pointer makes contact with a window’s surface, 170 /// it might provide the window an opportunity to activate. 171 /// </summary> 172 Primary = 0x2000u, 173 /// <summary> 174 /// Indicates a suggestion from the source device about whether the pointer represents 175 /// an intended or accidental interaction, which is especially relevant for touch 176 /// pointers where an accidental interaction (such as with the palm of the hand) 177 /// can trigger input. The presence of this flag indicates that the source device 178 /// has high confidence that this input is part of an intended interaction. 179 /// </summary> 180 Confidence = 0x4000u, 181 /// <summary> 182 /// Indicates that the pointer is departing in an abnormal manner, such as when the 183 /// system receives invalid input for the pointer or when a device with active pointers 184 /// departs abruptly. If the application receiving the input is in a position to 185 /// do so, it should treat the interaction as not completed and reverse any effects 186 /// of the pointer. 187 /// </summary> 188 Canceled = 0x8000u, 189 /// <summary> 190 /// Indicates that this pointer made contact with the digitizer surface. A touch 191 /// pointer has this flag set when it is in contact with the digitizer surface. 192 /// </summary> 193 PointerDown = 0x10000u, 194 /// <summary> 195 /// Indicates a simple update that does not include pointer state changes. 196 /// </summary> 197 Update = 0x20000u, 198 /// <summary> 199 /// Indicates that this pointer ended contact with the digitizer surface. A touch 200 /// pointer has this flag set when it ends contact with the digitizer surface. 201 /// </summary> 202 PointerUp = 0x40000u, 203 /// <summary> 204 /// Indicates that this pointer was captured by (associated with) another element 205 /// and the original element has lost capture. 206 /// </summary> 207 CaptureChanged = 0x200000u 208 } 209 210 /// <summary> 211 /// Contains the screen coordinates of the pointer in device-independent pixel (DIP). 212 /// </summary> 213 [StructLayout(LayoutKind.Sequential)] 214 public struct InputPoint 215 { 216 /// <summary> 217 /// The x-coordinate of the pointer in device-independent pixel (DIP). 218 /// </summary> 219 public int X; 220 /// <summary> 221 /// The y-coordinate of the pointer in device-independent pixel (DIP). 222 /// </summary> 223 public int Y; 224 } 225 226 public enum PointerButtonChangeType 227 { 228 None, 229 FirstButtonDown, 230 FirstButtonUp, 231 SecondButtonDown, 232 SecondButtonUp, 233 ThirdButtonDown, 234 ThirdButtonUp, 235 FourthButtonDown, 236 FourthButtonUp, 237 FifthButtonDown, 238 FifthButtonUp, 239 } 240 241 [Flags] 242 public enum TouchFlags : uint 243 { 244 None = 0, 245 } 246 247 [Flags] 248 public enum TouchMaskFlags : uint 249 { 250 None = 0, 251 ContactArea = 1, 252 Orientation = 2, 253 Pressure = 4, 254 } 255 }
参考:
1.https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-injecttouchinput
2.UWP: https://docs.microsoft.com/zh-cn/uwp/api/windows.ui.input.preview.injection.inputinjector.uninitializetouchinjection?view=winrt-22621
本文来自博客园,作者:叶落劲秋,转载请注明原文链接:https://www.cnblogs.com/tianlang358/p/16532733.html