触控:使用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 。而不是再次加入第二个点,否则会覆盖导致多指失效。

posted on 2024-03-04 19:26  TanZhiWei  阅读(82)  评论(0编辑  收藏  举报