win32Api提供一种方法,模拟用户触摸点击

InjectTouchInput function

  • InitializeTouchInjection
  • InjectTouchInput

在模拟添加触摸输入(InjectTouchInput)前,需要提前初始化(InitializeTouchInjection)

     /// <summary>
/// Use this Classes static methods to initialize and inject touch input.
/// </summary>
public class NativeMethods
{
/// <summary>
/// Call this first to initialize the TouchInjection!
/// </summary>
/// <param name="maxCount">The maximum number of touch points to simulate. Must be less than 256!</param>
/// <param name="feedbackMode">Specifies the visual feedback mode of the generated touch points</param>
/// <returns>true if success</returns>
[DllImport("User32.dll")]
public static extern bool InitializeTouchInjection(uint maxCount = , TouchFeedback feedbackMode = TouchFeedback.DEFAULT); /// <summary>
/// Inject an array of POINTER_TUCH_INFO
/// </summary>
/// <param name="count">The exact number of entries in the array</param>
/// <param name="contacts">The POINTER_TOUCH_INFO to inject</param>
/// <returns>true if success</returns>
[DllImport("User32.dll")]
public static extern bool InjectTouchInput(int count, [MarshalAs(UnmanagedType.LPArray), In] PointerTouchInfo[] contacts);
} static class IdGenerator
{
static private int _int;
private static uint _uint;
private static readonly object _mutex = new object(); public static int GetUniqueInt()
{
Interlocked.Increment(ref _int);
return _int;
} public static uint GetUinqueUInt()
{
lock (_mutex)
{
if (_uint > )
{
ResetUint();
}
if (_uint == uint.MaxValue)
throw new IndexOutOfRangeException();
else
{
_uint++;
return _uint;
}
}
} public static void ResetUint()
{
lock (_mutex)
{
_uint = uint.MinValue;
}
}
} #region Types
/// <summary>
/// Enum of touch visualization options
/// </summary>
public enum TouchFeedback
{
/// <summary>
/// Specifies default touch visualizations.
/// </summary>
DEFAULT = 0x1,
/// <summary>
/// Specifies indirect touch visualizations.
/// </summary>
INDIRECT = 0x2,
/// <summary>
/// Specifies no touch visualizations.
/// </summary>
NONE = 0x3
} /// <summary>
/// The contact area.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct ContactArea
{
[FieldOffset()]
public int left;
[FieldOffset()]
public int top;
[FieldOffset()]
public int right;
[FieldOffset()]
public int bottom;
} /// <summary>
/// Values that can appear in the TouchMask field of the PointerTouchInfo structure
/// </summary>
public enum TouchFlags
{
/// <summary>
/// Indicates that no flags are set.
/// </summary>
NONE = 0x00000000
} /// <summary>
/// Values that can appear in the TouchMask field of the PointerTouchInfo structure.
/// </summary>
public enum TouchMask
{
/// <summary>
/// Default. None of the optional fields are valid.
/// </summary>
NONE = 0x00000000,
/// <summary>
/// The ContactArea field is valid
/// </summary>
CONTACTAREA = 0x00000001,
/// <summary>
/// The orientation field is valid
/// </summary>
ORIENTATION = 0x00000002,
/// <summary>
/// The pressure field is valid
/// </summary>
PRESSURE = 0x00000004
} /// <summary>
/// Values that can appear in the PointerFlags field of the PointerInfo structure.
/// </summary>
public enum PointerFlags
{
/// <summary>
/// Default
/// </summary>
NONE = 0x00000000,
/// <summary>
/// Indicates the arrival of a new pointer
/// </summary>
NEW = 0x00000001,
/// <summary>
/// Indicates that this pointer continues to exist. When this flag is not set, it indicates the pointer has left detection range.
/// This flag is typically not set only when a hovering pointer leaves detection range (PointerFlag.UPDATE is set) or when a pointer in contact with a window surface leaves detection range (PointerFlag.UP is set).
/// </summary>
INRANGE = 0x00000002,
/// <summary>
/// Indicates that this pointer is in contact with the digitizer surface. When this flag is not set, it indicates a hovering pointer.
/// </summary>
INCONTACT = 0x00000004,
/// <summary>
/// Indicates a primary action, analogous to a mouse left button down.
///A touch pointer has this flag set when it is in contact with the digitizer surface.
///A pen pointer has this flag set when it is in contact with the digitizer surface with no buttons pressed.
///A mouse pointer has this flag set when the mouse left button is down.
/// </summary>
FIRSTBUTTON = 0x00000010,
/// <summary>
/// Indicates a secondary action, analogous to a mouse right button down.
/// A touch pointer does not use this flag.
/// A pen pointer has this flag set when it is in contact with the digitizer surface with the pen barrel button pressed.
/// A mouse pointer has this flag set when the mouse right button is down.
/// </summary>
SECONDBUTTON = 0x00000020,
/// <summary>
/// Indicates a secondary action, analogous to a mouse right button down.
/// A touch pointer does not use this flag.
/// A pen pointer does not use this flag.
/// A mouse pointer has this flag set when the mouse middle button is down.
/// </summary>
THIRDBUTTON = 0x00000040,
/// <summary>
/// Indicates actions of one or more buttons beyond those listed above, dependent on the pointer type. Applications that wish to respond to these actions must retrieve information specific to the pointer type to determine which buttons are pressed. For example, an application can determine the buttons states of a pen by calling GetPointerPenInfo and examining the flags that specify button states.
/// </summary>
OTHERBUTTON = 0x00000080,
/// <summary>
/// Indicates that this pointer has been designated as primary. A primary pointer may perform actions beyond those available to non-primary pointers. For example, when a primary pointer makes contact with a window’s surface, it may provide the window an opportunity to activate by sending it a WM_POINTERACTIVATE message.
/// </summary>
PRIMARY = 0x00000100,
/// <summary>
/// Confidence is a suggestion from the source device about whether the pointer represents an intended or accidental interaction, which is especially relevant for PT_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 = 0x00000200,
/// <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 concerned pointer.
/// </summary>
CANCELLED = 0x00000400,
/// <summary>
/// Indicates that this pointer just transitioned to a “down” state; that is, it made contact with the window surface.
/// </summary>
DOWN = 0x00010000,
/// <summary>
/// Indicates that this information provides a simple update that does not include pointer state changes.
/// </summary>
UPDATE = 0x00020000,
/// <summary>
/// Indicates that this pointer just transitioned to an “up” state; that is, it broke contact with the window surface.
/// </summary>
UP = 0x00040000,
/// <summary>
/// Indicates input associated with a pointer wheel. For mouse pointers, this is equivalent to the action of the mouse scroll wheel (WM_MOUSEWHEEL).
/// </summary>
WHEEL = 0x00080000,
/// <summary>
/// Indicates input associated with a pointer h-wheel. For mouse pointers, this is equivalent to the action of the mouse horizontal scroll wheel (WM_MOUSEHWHEEL).
/// </summary>
HWHEEL = 0x00100000
} /// <summary>
/// The TouchPoint structure defines the x- and y- coordinates of a point.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct TouchPoint
{
/// <summary>
/// The x-coordinate of the point.
/// </summary>
public int X;
/// <summary>
/// The y-coordinate of the point.
/// </summary>
public int Y;
} /// <summary>
/// Identifies the pointer input types.
/// </summary>
public enum PointerInputType
{
/// <summary>
/// Generic pointer type. This type never appears in pointer messages or pointer data. Some data query functions allow the caller to restrict the query to specific pointer type. The PT_POINTER type can be used in these functions to specify that the query is to include pointers of all types
/// </summary>
POINTER = 0x00000001,
/// <summary>
/// Touch pointer type.
/// </summary>
TOUCH = 0x00000002,
/// <summary>
/// Pen pointer type.
/// </summary>
PEN = 0x00000003,
/// <summary>
/// Mouse pointer type
/// </summary>
MOUSE = 0x00000004,
/// <summary>
/// touchpad pointer type
/// </summary>
TOUCHPAD = 0x00000005
}; /// <summary>
/// Contains basic pointer information common to all pointer types. Applications can retrieve this information using the GetPointerInfo, GetPointerFrameInfo, GetPointerInfoHistory and GetPointerFrameInfoHistory functions.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct PointerInfo
{
/// <summary>
/// A value from the PointerInputType enumeration that specifies the pointer type.
/// </summary>
public PointerInputType pointerType; /// <summary>
/// An identifier that uniquely identifies a pointer during its lifetime. A pointer comes into existence when it is first detected and ends its existence when it goes out of detection range. Note that if a physical entity (finger or pen) goes out of detection range and then returns to be detected again, it is treated as a new pointer and may be assigned a new pointer identifier.
/// </summary>
public uint PointerId; /// <summary>
/// An identifier common to multiple pointers for which the source device reported an update in a single input frame. For example, a parallel-mode multi-touch digitizer may report the positions of multiple touch contacts in a single update to the system.
/// Note that frame identifier is assigned as input is reported to the system for all pointers across all devices. Therefore, this field may not contain strictly sequential values in a single series of messages that a window receives. However, this field will contain the same numerical value for all input updates that were reported in the same input frame by a single device.
/// </summary>
public uint FrameId; /// <summary>
/// May be any reasonable combination of flags from the Pointer Flags constants.
/// </summary>
public PointerFlags PointerFlags; /// <summary>
/// Handle to the source device that can be used in calls to the raw input device API and the digitizer device API.
/// </summary>
public IntPtr SourceDevice; /// <summary>
/// Window to which this message was targeted. If the pointer is captured, either implicitly by virtue of having made contact over this window or explicitly using the pointer capture API, this is the capture window. If the pointer is uncaptured, this is the window over which the pointer was when this message was generated.
/// </summary>
public IntPtr WindowTarget; /// <summary>
/// Location in screen coordinates.
/// </summary>
public TouchPoint PtPixelLocation; /// <summary>
/// Location in device coordinates.
/// </summary>
public TouchPoint PtPixelLocationRaw; /// <summary>
/// Location in HIMETRIC units.
/// </summary>
public TouchPoint PtHimetricLocation; /// <summary>
/// Location in device coordinates in HIMETRIC units.
/// </summary>
public TouchPoint PtHimetricLocationRaw; /// <summary>
/// A message time stamp assigned by the system when this input was received.
/// </summary>
public uint Time; /// <summary>
/// Count of inputs that were coalesced into this message. This count matches the total count of entries that can be returned by a call to GetPointerInfoHistory. If no coalescing occurred, this count is 1 for the single input represented by the message.
/// </summary>
public uint HistoryCount; /// <summary>
/// A value whose meaning depends on the nature of input.
/// When flags indicate PointerFlag.WHEEL, this value indicates the distance the wheel is rotated, expressed in multiples or factors of WHEEL_DELTA. A positive value indicates that the wheel was rotated forward and a negative value indicates that the wheel was rotated backward.
/// When flags indicate PointerFlag.HWHEEL, this value indicates the distance the wheel is rotated, expressed in multiples or factors of WHEEL_DELTA. A positive value indicates that the wheel was rotated to the right and a negative value indicates that the wheel was rotated to the left.
/// </summary>
public uint InputData; /// <summary>
/// Indicates which keyboard modifier keys were pressed at the time the input was generated. May be zero or a combination of the following values.
/// POINTER_MOD_SHIFT – A SHIFT key was pressed.
/// POINTER_MOD_CTRL – A CTRL key was pressed.
/// </summary>
public uint KeyStates; /// <summary>
/// TBD
/// </summary>
public ulong PerformanceCount; /// <summary>
/// ???
/// </summary>
public PointerButtonChangeType ButtonChangeType;
} /// <summary>
/// Enumeration of PointerButtonChangeTypes
/// </summary>
public enum PointerButtonChangeType
{
NONE,
FIRSTBUTTON_DOWN,
FIRSTBUTTON_UP,
SECONDBUTTON_DOWN,
SECONDBUTTON_UP,
THIRDBUTTON_DOWN,
THIRDBUTTON_UP,
FOURTHBUTTON_DOWN,
FOURTHBUTTON_UP,
FIFTHBUTTON_DOWN,
FIFTHBUTTON_UP
} /// <summary>
/// Contains information about a 'contact' (coordinates, size, pressure...)
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct PointerTouchInfo
{
///<summary>
/// Contains basic pointer information common to all pointer types.
///</summary>
public PointerInfo PointerInfo; ///<summary>
/// Lists the touch flags.
///</summary>
public TouchFlags TouchFlags; /// <summary>
/// Indicates which of the optional fields contain valid values. The member can be zero or any combination of the values from the Touch Mask constants.
/// </summary>
public TouchMask TouchMasks; ///<summary>
/// Pointer contact area in pixel screen coordinates.
/// By default, if the device does not report a contact area,
/// this field defaults to a 0-by-0 rectangle centered around the pointer location.
///</summary>
public ContactArea ContactArea; /// <summary>
/// A raw pointer contact area.
/// </summary>
public ContactArea ContactAreaRaw; ///<summary>
/// A pointer orientation, with a value between 0 and 359, where 0 indicates a touch pointer
/// aligned with the x-axis and pointing from left to right; increasing values indicate degrees
/// of rotation in the clockwise direction.
/// This field defaults to 0 if the device does not report orientation.
///</summary>
public uint Orientation; ///<summary>
/// Pointer pressure normalized in a range of 0 to 256.
///</summary>
public uint Pressure; /// <summary>
/// Move the touch point, together with its ContactArea
/// </summary>
/// <param name="deltaX">the change in the x-value</param>
/// <param name="deltaY">the change in the y-value</param>
public void Move(int deltaX, int deltaY)
{
PointerInfo.PtPixelLocation.X += deltaX;
PointerInfo.PtPixelLocation.Y += deltaY;
ContactArea.left += deltaX;
ContactArea.right += deltaX;
ContactArea.top += deltaY;
ContactArea.bottom += deltaY;
}
}
#endregion

我们模拟触摸A(100,100)并移动到(500,500):

提前初始化“触摸注入”

     private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
NativeMethods.InitializeTouchInjection();
}

模拟触摸移动:

     private void FakeTouchMove(int fromX, int fromY, int toX, int toY)
{
// Touch Down
PointerTouchInfo contact = MakePointerTouchInfo(fromX, fromY, , );
PointerFlags oFlags = PointerFlags.DOWN | PointerFlags.INRANGE | PointerFlags.INCONTACT;
contact.PointerInfo.PointerFlags = oFlags;
NativeMethods.InjectTouchInput(, new[] { contact }); // Touch Move
int movedX = toX - fromX;
int movedY = toY - fromY;
contact.Move(movedX, movedY);
oFlags = PointerFlags.INRANGE | PointerFlags.INCONTACT | PointerFlags.UPDATE;
contact.PointerInfo.PointerFlags = oFlags;
NativeMethods.InjectTouchInput(, new[] { contact }); // Touch Up
contact.PointerInfo.PointerFlags = PointerFlags.UP;
NativeMethods.InjectTouchInput(, new[] { contact });
}
private PointerTouchInfo MakePointerTouchInfo(int x, int y, int radius,
uint orientation = , uint pressure = )
{
PointerTouchInfo contact = new PointerTouchInfo();
contact.PointerInfo.pointerType = PointerInputType.TOUCH;
contact.TouchFlags = TouchFlags.NONE;
contact.Orientation = orientation;
contact.Pressure = pressure;
contact.TouchMasks = TouchMask.CONTACTAREA | TouchMask.ORIENTATION | TouchMask.PRESSURE;
contact.PointerInfo.PtPixelLocation.X = x;
contact.PointerInfo.PtPixelLocation.Y = y;
uint unPointerId = IdGenerator.GetUinqueUInt();
Console.WriteLine("PointerId " + unPointerId);
contact.PointerInfo.PointerId = unPointerId;
contact.ContactArea.left = x - radius;
contact.ContactArea.right = x + radius;
contact.ContactArea.top = y - radius;
contact.ContactArea.bottom = y + radius;
return contact;
}

界面接收触摸消息:

使用InjectTouchInput函数模拟触摸,Touch、Stylus消息都可以接收到。

     private Line _proxyLine;
private void MainWindow_TouchDown(object sender, TouchEventArgs e)
{
System.Windows.Input.TouchPoint oPos = e.GetTouchPoint(this);
Line oLine = new Line();
oLine.Stroke = new SolidColorBrush(Colors.Red);
oLine.StrokeThickness = ;
oLine.X1 = oPos.Position.X;
oLine.Y1 = oPos.Position.Y;
_proxyLine = oLine;
Console.WriteLine("TouchDown;TouchID " + e.TouchDevice.Id + " TouchDown " + oPos.Position.X + " " + oPos.Position.Y);
} private void MainWindow_TouchMove(object sender, TouchEventArgs e)
{
System.Windows.Input.TouchPoint movedPoint = e.GetTouchPoint(this);
Console.WriteLine("TouchMove:TouchID " + e.TouchDevice.Id + " TouchMove " + movedPoint.Position.X + " " + movedPoint.Position.Y);
} private void MainWindow_TouchUp(object sender, TouchEventArgs e)
{
System.Windows.Input.TouchPoint oPos = e.GetTouchPoint(this);
this._proxyLine.X2 = oPos.Position.X;
this._proxyLine.Y2 = oPos.Position.Y;
RootGrid.Children.Add(this._proxyLine);
Console.WriteLine("TouchUp:TouchID " + e.TouchDevice.Id + " TouchUp " + oPos.Position.X + " " + oPos.Position.Y);
}

触摸模拟结果:

WPF 后台模拟界面触摸点击的更多相关文章

  1. 使用WPF技术模拟手机界面

    原文:使用WPF技术模拟手机界面 1. 前言 WPF(Windows Presentation Foundation),即"Windows呈现基础",它的目的非常明确,就是用来把数 ...

  2. Wix 安装部署教程(九) --用WPF做安装界面

    经常安装PC端的应用,特别是重装系统之后,大致分为两类.一类像QQ,搜狗输入法这样的.分三步走的:第一个页面可以自定义安装路径和软件许可.第二个页面显示安装进度条,第三个页面推荐其他应用.先不管人家怎 ...

  3. C# WPF 一个设计界面

    微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏. C# WPF 一个设计界面 今天正月初三,大家在家呆着挺好,不要忘了自我充电. 武汉人民加油, ...

  4. C# WPF后台动态添加控件(经典)

    概述 在Winform中从后台添加控件相对比较容易,但是在WPF中,我们知道界面是通过XAML编写的,如何把后台写好的控件动态添加到前台呢?本节举例介绍这个问题. 这里要用到UniformGrid布局 ...

  5. Django后台管理界面

    之前的几篇记录了模板视图.模型等页面展示的相关内容,这篇主要写一下后台admin管理界面的内容. 激活管理界面 Django管理站点完全是可选择的,之前我们是把这些功能给屏蔽掉了.记得上篇中Djang ...

  6. WPF移动Window窗体(鼠标点击左键移动窗体自定义行为)

    XAML代码部分:1.引用System.Windows.Interactivity 2.为指定的控件添加一个拖动的行为 3.很简单的了解行为的作用和用法 <Window xmlns=" ...

  7. 使用Bootstrap+metisMenu完成简单的后台管理界面

    零. 写在前面 作者最近在一个小项目中需要写后台管理界面,在互联网上绕了一圈,最后决定使用Bootstrap+metisMenu来完成.理由1:Bootstrap是目前流行的前端框架,风格简约,简单易 ...

  8. 第二百三十节,jQuery EasyUI,后台管理界面---后台管理

    jQuery EasyUI,后台管理界面---后台管理 一,admin.php,后台管理界面 <?php session_start(); if (!isset($_SESSION['admin ...

  9. 转:Android随笔之——使用Root权限实现后台模拟全局按键、触屏事件方法(类似按键精灵)

    本文转载自CSDN的jzj1993,原文连接:http://blog.csdn.net/jzj1993/article/details/39158865 有时我们需要使用安卓实现在后台模拟系统按键,比 ...

随机推荐

  1. Python使用itchat获取微信好友信息~

    最近发现了一个好玩的包itchat,通过调用微信网页版的接口实现收发消息,获取好友信息等一些功能,各位可以移步itchat项目介绍查看详细信息. 目标: 获取好友列表 统计性别及城市分布 根据好友签名 ...

  2. vscode从听说到使用,vetur,prettier,htmljscssPrettify踩坑指南。

    今天基于vue-cli(2.9.3)构建一个新的项目.我用的sublime,es6的代码格式要与公司格式兼容.采用了vue-cli自带的eslint后,有一些不统一的部分需要修改.先看看sublime ...

  3. 【CKB.DEV 茶话会】如何在 CKB 上实现用户自定义 Token

    本贴内容主要来自于 CKB.DEV 茶话会第一期,本期主题是:如何在 CKB 上实现 UDT,分享人是:Cipher 王博. 茶话会现场视频: https://v.qq.com/x/page/x303 ...

  4. Python一秒搭建ftp服务器,帮助你在局域网共享文件【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  5. 【开发记录】Linux常用命令记录(一)【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  6. 带着canvas去流浪系列之四 绘制散点图

    [摘要] 用原生canvasAPI实现百度Echarts图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI ...

  7. Blazor 版 Bootstrap Admin 通用后台权限管理框架

    前言 上一篇介绍过了前后台分离的 NET Core 通用权限管理系统 在这篇文章简要的介绍了 Bootstrap Admin 后台管理框架的一些功能.本篇文章带来的是微软最新出的 Blazor 版本的 ...

  8. 利用python实现dll依赖关系导出

    #说明:遍历rootdir目录下所有dll,导出每个dll依赖的dll信息到dstdir目录下 # 配合NotePad++打开所有txt,搜索,可快速定位到某dll被依赖的所有dll文件 import ...

  9. 用Selenium自动化测试时,让ChromeDriver中不显示“正受到自动测试软件控制”

    背景: 在用Selenium做自动化测试的时候,默认ChromeDriver是会提示“Chrom正受到自动测试软件控制”的.如下图这样.但我们有些场景下,不希望这个提示出现.本文探索了几种语言去掉这个 ...

  10. PDF怎么删除页面?教你两个超级好用的方法

    在日常办公中,由于工作需要我们有时候会对PDF文件中的内容进行二次编辑,可能需要删除PDF文件中的一些页面.那么PDF怎么删除页面呢?小伙伴们还在为这个问题苦恼吗?那么今天小编就来教大家两个超级好用的 ...