触控:使用Win32 API 模拟触控注入
采用使用Win32 API 模拟触控,使用user32
/// <summary> /// 初始化触摸注入系统 /// </summary> /// <param name="maxCount"></param> /// <param name="dwMode"></param> /// <returns></returns> [DllImport("user32.dll", SetLastError = true)] private static extern bool InitializeTouchInjection(uint maxCount = 256, int dwMode = (int)TouchFeedback.Default); /// <summary> /// 向系统注入触摸事件 /// </summary> /// <param name="count"></param> /// <param name="contacts"></param> /// <returns></returns> [DllImport("user32.dll", SetLastError = true)] private static extern bool InjectTouchInput(uint count, PointerTouchInfo[] contacts);
1 触控按下,2 触控移动,3 触控抬起
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; namespace Windows { /// <summary> /// 输入源注入 /// </summary> public class InputSourceInjector { static InputSourceInjector() { //初始化触摸注入 if (!InitializeTouchInjection()) { var errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode, "Failed to initialize touch injection."); } } /// <summary> /// 注入触摸按下事件 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="win32ErrorCode"></param> /// <returns></returns> public static bool InjectTouchDown(int x, int y, out int win32ErrorCode) { Point position = new Point(x, y); var touchDownOperation = InputPointerOptions.InRange | InputPointerOptions.InContact | InputPointerOptions.PointerDown; var contact = CreatePointerTouchInfo(position, touchDownOperation); return InjectTouchInput(1, new[] { contact }, out win32ErrorCode); } /// <summary> /// 注入触摸移动事件 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="win32ErrorCode"></param> /// <returns></returns> public static bool InjectTouchMove(int x, int y, out int win32ErrorCode) { var position = new Point(x, y); var touchMoveOperation = InputPointerOptions.InRange | InputPointerOptions.InContact | InputPointerOptions.Update; var contact = CreatePointerTouchInfo(position, touchMoveOperation); return InjectTouchInput(1, new[] { contact }, out win32ErrorCode); } /// <summary> /// 注入触摸抬起事件 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="win32ErrorCode"></param> /// <returns></returns> public static bool InjectTouchUp(int x, int y, out int win32ErrorCode) { var position = new Point(x, y); var touchUpOperation = InputPointerOptions.PointerUp; var contact = CreatePointerTouchInfo(position, touchUpOperation); return InjectTouchInput(1, new[] { contact }, out win32ErrorCode); } #region 私有方法 /// <summary> /// 注入触摸事件 /// </summary> /// <param name="count"></param> /// <param name="contacts"></param> /// <param name="win32ErrorCode"></param> /// <returns></returns> private static bool InjectTouchInput(uint count, IEnumerable<PointerTouchInfo> contacts, out int win32ErrorCode) { win32ErrorCode = 0; var isOk = InjectTouchInput(count, contacts.ToArray()); if (!isOk) { win32ErrorCode = Marshal.GetLastWin32Error(); } return isOk; } private static PointerTouchInfo CreatePointerTouchInfo(Point position, InputPointerOptions operations) { _touchInfo.PointerInfo.PointerFlags = operations; _touchInfo.PointerInfo.PixelLocation.X = position.X; _touchInfo.PointerInfo.PixelLocation.Y = position.Y; _touchInfo.ContactArea.Left = position.X - 2; _touchInfo.ContactArea.Top = position.Y - 2; _touchInfo.ContactArea.Right = position.X + 2; _touchInfo.ContactArea.Bottom = position.Y + 2; return _touchInfo; } private static PointerTouchInfo _touchInfo = new PointerTouchInfo { PointerInfo = new InputPointerInfo { PointerType = PointerInputType.Touch, PointerId = 1 }, TouchFlags = TouchFlags.None, TouchMask = TouchMaskFlags.ContactArea | TouchMaskFlags.Orientation | TouchMaskFlags.Pressure }; private enum TouchFeedback { Default = 1, Indirect = 2, None = 3 } /// <summary> /// 初始化触摸注入系统 /// </summary> /// <param name="maxCount"></param> /// <param name="dwMode"></param> /// <returns></returns> [DllImport("user32.dll", SetLastError = true)] private static extern bool InitializeTouchInjection(uint maxCount = 256, int dwMode = (int)TouchFeedback.Default); /// <summary> /// 向系统注入触摸事件 /// </summary> /// <param name="count"></param> /// <param name="contacts"></param> /// <returns></returns> [DllImport("user32.dll", SetLastError = true)] private static extern bool InjectTouchInput(uint count, PointerTouchInfo[] contacts); #endregion } #region 结构体 [StructLayout(LayoutKind.Sequential)] public struct PointerTouchInfo { public InputPointerInfo PointerInfo; public TouchFlags TouchFlags; public TouchMaskFlags TouchMask; public InputRectangle ContactArea; public InputRectangle rawContactArea; public uint Orientation; public uint Pressure; } [StructLayout(LayoutKind.Sequential)] public struct InputRectangle { public int Left; public int Right; public int Top; public int Bottom; } [StructLayout(LayoutKind.Sequential)] public struct InputPointerInfo { public PointerInputType PointerType; public uint PointerId; public uint FrameId; public InputPointerOptions PointerFlags; public IntPtr SourceDevice; public IntPtr HwndTarget; public InputPoint PixelLocation; public InputPoint HimetricLocation; public InputPoint PixelLocationRaw; public InputPoint HimetricLocationRaw; public int TimeOffsetInMilliseconds; public uint HistoryCount; public int InputData; public int KeyStates; public ulong PerformanceCount; public PointerButtonChangeType ButtonChangeType; } /// <summary> /// 包含指针在设备独立像素(DIP)中的屏幕坐标 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct InputPoint { /// <summary> /// 指针在设备独立像素(DIP)中的 x 坐标 /// </summary> public int X; /// <summary> /// 指针在设备独立像素(DIP)中的 y 坐标 /// </summary> public int Y; } #endregion #region 枚举类 /// <summary> /// 输入类型 /// </summary> public enum PointerInputType { Pointer = 1, Touch, Pen, Mouse, TouchPad, } [Flags] public enum InputPointerOptions : uint { /// <summary> /// No pointer modifier. Default. /// </summary> None = 0x0u, /// <summary> /// Indicates the arrival of a new pointer. /// </summary> New = 0x1u, /// <summary> /// Indicates that the pointer continues to exist. When this flag is not set, /// it indicates the pointer has left detection range. /// </summary> InRange = 0x2u, /// <summary> /// Indicates that the pointer is in contact with the digitizer surface or area. /// When this flag is not set, it indicates a hovering pointer. /// </summary> InContact = 0x4u, /// <summary> /// Indicates a primary action. /// </summary> FirstButton = 0x10u, /// <summary> /// Indicates a secondary action. /// </summary> SecondButton = 0x20u, /// <summary> /// Indicates that the pointer can perform actions beyond those available to non-primary pointers. /// For example, when a primary pointer makes contact with a window’s surface, /// it might provide the window an opportunity to activate. /// </summary> Primary = 0x2000u, /// <summary> /// Indicates a suggestion from the source device about whether the pointer represents /// an intended or accidental interaction, which is especially relevant for touch /// pointers where an accidental interaction (such as with the palm of the hand) /// can trigger input. The presence of this flag indicates that the source device /// has high confidence that this input is part of an intended interaction. /// </summary> Confidence = 0x4000u, /// <summary> /// Indicates that the pointer is departing in an abnormal manner, such as when the /// system receives invalid input for the pointer or when a device with active pointers /// departs abruptly. If the application receiving the input is in a position to /// do so, it should treat the interaction as not completed and reverse any effects /// of the pointer. /// </summary> Canceled = 0x8000u, /// <summary> /// Indicates that this pointer made contact with the digitizer surface. A touch /// pointer has this flag set when it is in contact with the digitizer surface. /// </summary> PointerDown = 0x10000u, /// <summary> /// Indicates a simple update that does not include pointer state changes. /// </summary> Update = 0x20000u, /// <summary> /// Indicates that this pointer ended contact with the digitizer surface. A touch /// pointer has this flag set when it ends contact with the digitizer surface. /// </summary> PointerUp = 0x40000u, /// <summary> /// Indicates that this pointer was captured by (associated with) another element /// and the original element has lost capture. /// </summary> CaptureChanged = 0x200000u } public enum PointerButtonChangeType { None, FirstButtonDown, FirstButtonUp, SecondButtonDown, SecondButtonUp, ThirdButtonDown, ThirdButtonUp, FourthButtonDown, FourthButtonUp, FifthButtonDown, FifthButtonUp, } [Flags] public enum TouchFlags : uint { None = 0, } [Flags] public enum TouchMaskFlags : uint { None = 0, ContactArea = 1, Orientation = 2, Pressure = 4, } #endregion }
注意:多指操作,在第二点注入的时候,需要获取当前所有点的位置,同时注入多个点的down 。而不是再次加入第二个点,否则会覆盖导致多指失效。