通过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

posted @ 2022-07-29 16:31  叶落劲秋  阅读(751)  评论(0编辑  收藏  举报