Skip to content

Commit 715c64f

Browse files
Add initial touch injection API test
See comments in CommunityToolkit/Labs-Windows#124
1 parent c335c4b commit 715c64f

File tree

3 files changed

+166
-0
lines changed

3 files changed

+166
-0
lines changed

CommunityToolkit.Labs.Tests.Shared/App.xaml.cs

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ public sealed partial class App : Application
4242
private static Windows.UI.Xaml.Window currentWindow = Windows.UI.Xaml.Window.Current;
4343
#endif
4444

45+
public static Rect Bounds => currentWindow.Bounds;
46+
4547
// Holder for test content to abstract Window.Current.Content
4648
public static FrameworkElement? ContentRoot
4749
{

CommunityToolkit.Labs.Tests.Shared/CommunityToolkit.Labs.Tests.Shared.projitems

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<DependentUpon>App.xaml</DependentUpon>
2020
</Compile>
2121
<Compile Include="$(MSBuildThisFileDirectory)Log.cs" />
22+
<Compile Include="$(MSBuildThisFileDirectory)SimulateInput.cs" />
2223
<Compile Include="$(MSBuildThisFileDirectory)VisualUITestBase.cs" />
2324
</ItemGroup>
2425
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
using Microsoft.VisualStudio.TestTools.UnitTesting;
9+
using Windows.UI.Input.Preview.Injection;
10+
using Windows.Foundation;
11+
12+
#if !WINAPPSDK
13+
using Windows.UI.Input;
14+
using Windows.UI.Xaml;
15+
using Windows.UI.Xaml.Media;
16+
#else
17+
using Microsoft.UI.Input;
18+
using Microsoft.UI.Xaml;
19+
using Microsoft.UI.Xaml.Media;
20+
#endif
21+
22+
namespace CommunityToolkit.Labs.UnitTests;
23+
24+
public static class SimulateInput
25+
{
26+
private static InputInjector _input = InputInjector.TryCreate();
27+
private static uint _currentPointerId = 0;
28+
29+
public static void StartTouch()
30+
{
31+
Assert.IsNotNull(_input);
32+
33+
_input.InitializeTouchInjection(
34+
InjectedInputVisualizationMode.Default);
35+
}
36+
37+
/// <summary>
38+
/// Simulates a touch press on screen at the coordinates provided, in app-local coordinates. For instance use <code>App.ContentRoot.CoordinatesTo(element)</code>.
39+
/// </summary>
40+
/// <param name="point"></param>
41+
/// <returns></returns>
42+
public static uint TouchDown(Point point)
43+
{
44+
// Create a unique pointer ID for the injected touch pointer.
45+
// Multiple input pointers would require more robust handling.
46+
uint pointerId = _currentPointerId++;
47+
48+
var injectionPoint = TranslatePointForWindow(point);
49+
50+
// Create a touch data point for pointer down.
51+
// Each element in the touch data list represents a single touch contact.
52+
// For this example, we're mirroring a single mouse pointer.
53+
List<InjectedInputTouchInfo> touchData = new()
54+
{
55+
new()
56+
{
57+
Contact = new InjectedInputRectangle
58+
{
59+
Left = 30, Top = 30, Bottom = 30, Right = 30
60+
},
61+
PointerInfo = new InjectedInputPointerInfo
62+
{
63+
PointerId = pointerId,
64+
PointerOptions =
65+
InjectedInputPointerOptions.PointerDown |
66+
InjectedInputPointerOptions.InContact |
67+
InjectedInputPointerOptions.New,
68+
TimeOffsetInMilliseconds = 0,
69+
PixelLocation = new InjectedInputPoint
70+
{
71+
PositionX = (int)injectionPoint.X ,
72+
PositionY = (int)injectionPoint.Y
73+
}
74+
},
75+
Pressure = 1.0,
76+
TouchParameters =
77+
InjectedInputTouchParameters.Pressure |
78+
InjectedInputTouchParameters.Contact
79+
}
80+
};
81+
82+
// Inject the touch input.
83+
_input.InjectTouchInput(touchData);
84+
85+
return pointerId;
86+
}
87+
88+
public static void TouchMove(uint pointerId, int cX, int cY)
89+
{
90+
// Create a touch data point for pointer up.
91+
List<InjectedInputTouchInfo> touchData = new()
92+
{
93+
new()
94+
{
95+
Contact = new InjectedInputRectangle
96+
{
97+
Left = 30, Top = 30, Bottom = 30, Right = 30
98+
},
99+
PointerInfo = new InjectedInputPointerInfo
100+
{
101+
PointerId = pointerId,
102+
PointerOptions =
103+
InjectedInputPointerOptions.InRange |
104+
InjectedInputPointerOptions.InContact,
105+
TimeOffsetInMilliseconds = 0,
106+
PixelLocation = new InjectedInputPoint
107+
{
108+
PositionX = (int)cX ,
109+
PositionY = (int)cY
110+
}
111+
},
112+
Pressure = 1.0,
113+
TouchParameters =
114+
InjectedInputTouchParameters.Pressure |
115+
InjectedInputTouchParameters.Contact
116+
}
117+
};
118+
119+
// Inject the touch input.
120+
_input.InjectTouchInput(touchData);
121+
}
122+
123+
public static void TouchUp(uint pointerId)
124+
{
125+
Assert.IsNotNull(_input);
126+
127+
// Create a touch data point for pointer up.
128+
List<InjectedInputTouchInfo> touchData = new()
129+
{
130+
new()
131+
{
132+
PointerInfo = new InjectedInputPointerInfo
133+
{
134+
PointerId = pointerId,
135+
PointerOptions = InjectedInputPointerOptions.PointerUp
136+
}
137+
}
138+
};
139+
140+
// Inject the touch input.
141+
_input.InjectTouchInput(touchData);
142+
}
143+
144+
public static void StopTouch()
145+
{
146+
// Shut down the virtual input device.
147+
_input.UninitializeTouchInjection();
148+
}
149+
150+
private static Point TranslatePointForWindow(Point point)
151+
{
152+
// TODO: Do we want a ToPoint extension in the Toolkit? (is there an existing enum we can use to specify which corner/point of the rect? e.g. topleft, center, middleright, etc...?
153+
154+
// Get the top left screen coordinates of the app window rect.
155+
Point appBoundsTopLeft = new Point(App.Bounds.Left, App.Bounds.Top);
156+
157+
// Create the point for input injection and calculate its screen location.
158+
return new Point(
159+
appBoundsTopLeft.X + point.X,
160+
appBoundsTopLeft.Y + point.Y);
161+
162+
}
163+
}

0 commit comments

Comments
 (0)