Skip to content

Commit 185925c

Browse files
authored
Merge pull request #111 from FlaUI/add-windows-extension-scripts
Add scroll script and fix other Windows extensions
2 parents 4408741 + d66f5f4 commit 185925c

File tree

7 files changed

+110
-42
lines changed

7 files changed

+110
-42
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ Using the WebdriverIO JavaScript client:
179179
const result = driver.executeScript("powerShell", [{ command: `1+1` }]);
180180
```
181181

182+
## Windows extensions
183+
184+
To enable easy switching from appium-windows-driver, there is a rudimentary implementation of `windows: click`, `windows: hover`, `windows: scroll` and `windows: keys`.
185+
182186
## Supported WebDriver Commands
183187

184188
| Method | URI Template | Command | Implemented |

src/FlaUI.WebDriver/Controllers/ExecuteController.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ public async Task<ActionResult> ExecuteScript([FromRoute] string sessionId, [Fro
3535
return await ExecuteWindowsClickScript(session, executeScriptRequest);
3636
case "windows: hover":
3737
return await ExecuteWindowsHoverScript(session, executeScriptRequest);
38+
case "windows: scroll":
39+
return await ExecuteWindowsScrollScript(session, executeScriptRequest);
3840
default:
39-
throw WebDriverResponseException.UnsupportedOperation("Only 'powerShell' scripts are supported");
41+
throw WebDriverResponseException.UnsupportedOperation("Only 'powerShell', 'windows: keys', 'windows: click', 'windows: hover' scripts are supported");
4042
}
4143
}
4244

@@ -103,6 +105,21 @@ private async Task<ActionResult> ExecuteWindowsClickScript(Session session, Exec
103105
return WebDriverResult.Success();
104106
}
105107

108+
private async Task<ActionResult> ExecuteWindowsScrollScript(Session session, ExecuteScriptRequest executeScriptRequest)
109+
{
110+
if (executeScriptRequest.Args.Count != 1)
111+
{
112+
throw WebDriverResponseException.InvalidArgument($"Expected an array of exactly 1 arguments for the windows: click script, but got {executeScriptRequest.Args.Count} arguments");
113+
}
114+
var action = JsonSerializer.Deserialize<WindowsScrollScript>(executeScriptRequest.Args[0], new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
115+
if (action == null)
116+
{
117+
throw WebDriverResponseException.InvalidArgument("Action cannot be null");
118+
}
119+
await _windowsExtensionService.ExecuteScrollScript(session, action);
120+
return WebDriverResult.Success();
121+
}
122+
106123
private async Task<ActionResult> ExecuteWindowsHoverScript(Session session, ExecuteScriptRequest executeScriptRequest)
107124
{
108125
if (executeScriptRequest.Args.Count != 1)

src/FlaUI.WebDriver/Models/WindowsClickScript.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@ public class WindowsClickScript
66
public int? X { get; set; }
77
public int? Y { get; set; }
88
public string? Button { get; set; }
9+
public string[]? ModifierKeys { get; set; }
10+
public int? DurationMs { get; set; }
11+
public int? Times { get; set; }
12+
public int? InterClickDelayMs { get; set; }
913
}
1014
}

src/FlaUI.WebDriver/Models/WindowsHoverScript.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ public class WindowsHoverScript
99
public int? EndY { get; set; }
1010
public string? EndElementId { get; set; }
1111
public int? DurationMs { get; set; }
12+
public string[]? ModifierKeys { get; set; }
1213
}
1314
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace FlaUI.WebDriver.Models
2+
{
3+
public class WindowsScrollScript
4+
{
5+
public string? ElementId { get; set; }
6+
public int? X { get; set; }
7+
public int? Y { get; set; }
8+
public int? DeltaX { get; set; }
9+
public int? DeltaY { get; set; }
10+
public string[]? ModifierKeys { get; set; }
11+
}
12+
}

src/FlaUI.WebDriver/Services/IWindowsExtensionService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace FlaUI.WebDriver.Services
55
public interface IWindowsExtensionService
66
{
77
Task ExecuteClickScript(Session session, WindowsClickScript action);
8+
Task ExecuteScrollScript(Session session, WindowsScrollScript action);
89
Task ExecuteHoverScript(Session session, WindowsHoverScript action);
910
Task ExecuteKeyScript(Session session, WindowsKeyScript action);
1011
}

src/FlaUI.WebDriver/Services/WindowsExtensionService.cs

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using FlaUI.Core.Input;
2+
using FlaUI.Core.Tools;
23
using FlaUI.Core.WindowsAPI;
34
using FlaUI.WebDriver.Models;
45
using System.Drawing;
@@ -16,76 +17,104 @@ public WindowsExtensionService(ILogger<WindowsExtensionService> logger)
1617

1718
public async Task ExecuteClickScript(Session session, WindowsClickScript action)
1819
{
19-
var mouseButton = action.Button != null ? Enum.Parse<MouseButton>(action.Button, true) : MouseButton.Left;
20-
if (action.ElementId != null)
20+
if (action.DurationMs.HasValue)
2121
{
22-
var element = session.FindKnownElementById(action.ElementId);
23-
if (element == null)
24-
{
25-
throw WebDriverResponseException.ElementNotFound(action.ElementId);
26-
}
27-
_logger.LogDebug("Clicking element {ElementId} with mouse button {MouseButton}", action.ElementId, mouseButton);
28-
Mouse.Click(element.BoundingRectangle.Location, mouseButton);
22+
throw WebDriverResponseException.UnsupportedOperation("Duration is not yet supported");
2923
}
30-
else if (action.X.HasValue && action.Y.HasValue)
24+
if (action.Times.HasValue)
3125
{
32-
_logger.LogDebug("Clicking point ({X}, {Y}) with mouse button {MouseButton}", action.X.Value, action.Y.Value, mouseButton);
33-
Mouse.Click(new Point { X = action.X.Value, Y = action.Y.Value }, mouseButton);
26+
throw WebDriverResponseException.UnsupportedOperation("Times is not yet supported");
3427
}
35-
else
28+
if (action.ModifierKeys != null)
3629
{
37-
throw WebDriverResponseException.InvalidArgument("Either \"elementId\" or \"x\" and \"y\" must be provided");
30+
throw WebDriverResponseException.UnsupportedOperation("Modifier keys are not yet supported");
3831
}
32+
var point = GetPoint(action.ElementId, action.X, action.Y, session);
33+
var mouseButton = action.Button != null ? Enum.Parse<MouseButton>(action.Button, true) : MouseButton.Left;
34+
_logger.LogDebug("Clicking point ({X}, {Y}) with mouse button {MouseButton}", point.X, point.Y, mouseButton);
35+
Mouse.Click(point, mouseButton);
3936
await Task.Yield();
4037
}
4138

42-
public async Task ExecuteHoverScript(Session session, WindowsHoverScript action)
39+
public async Task ExecuteScrollScript(Session session, WindowsScrollScript action)
4340
{
44-
if (action.StartX.HasValue && action.StartY.HasValue)
41+
if (action.ModifierKeys != null)
4542
{
46-
_logger.LogDebug("Moving mouse to ({X}, {Y})", action.StartX.Value, action.StartY.Value);
47-
Mouse.MoveTo(action.StartX.Value, action.StartY.Value);
43+
throw WebDriverResponseException.UnsupportedOperation("Modifier keys are not yet supported");
4844
}
49-
else if (action.StartElementId != null)
45+
var point = GetPoint(action.ElementId, action.X, action.Y, session);
46+
_logger.LogDebug("Scrolling at point ({X}, {Y})", point.X, point.Y);
47+
Mouse.Position = point;
48+
if (action.DeltaY.HasValue && action.DeltaY.Value != 0)
5049
{
51-
var element = session.FindKnownElementById(action.StartElementId);
50+
Mouse.Scroll(action.DeltaY.Value);
51+
}
52+
if (action.DeltaX.HasValue && action.DeltaX.Value != 0)
53+
{
54+
Mouse.HorizontalScroll(-action.DeltaX.Value);
55+
}
56+
await Task.Yield();
57+
}
58+
59+
private Point GetPoint(string? elementId, int? x, int? y, Session session)
60+
{
61+
if (elementId != null)
62+
{
63+
var element = session.FindKnownElementById(elementId);
5264
if (element == null)
5365
{
54-
throw WebDriverResponseException.ElementNotFound(action.StartElementId);
66+
throw WebDriverResponseException.ElementNotFound(elementId);
5567
}
56-
_logger.LogDebug("Moving mouse to element {ElementId}", action.StartElementId);
57-
Mouse.MoveTo(element.BoundingRectangle.Location);
68+
69+
if (x.HasValue && y.HasValue)
70+
{
71+
return new Point
72+
{
73+
X = element.BoundingRectangle.Left + x.Value,
74+
Y = element.BoundingRectangle.Top + y.Value
75+
};
76+
}
77+
78+
return element.BoundingRectangle.Center();
5879
}
59-
else
80+
81+
if (x.HasValue && y.HasValue)
6082
{
61-
throw WebDriverResponseException.InvalidArgument("Either \"startElementId\" or \"startX\" and \"startY\" must be provided");
83+
return new Point { X = x.Value, Y = y.Value };
6284
}
85+
86+
throw WebDriverResponseException.InvalidArgument("Either element ID or x and y must be provided");
87+
}
6388

64-
if (action.DurationMs.HasValue)
89+
public async Task ExecuteHoverScript(Session session, WindowsHoverScript action)
90+
{
91+
if (action.ModifierKeys != null)
6592
{
66-
_logger.LogDebug("Waiting for {DurationMs}ms", action.DurationMs.Value);
67-
await Task.Delay(action.DurationMs.Value);
93+
throw WebDriverResponseException.UnsupportedOperation("Modifier keys are not yet supported");
6894
}
95+
var startingPoint = GetPoint(action.StartElementId, action.StartX, action.StartY, session);
96+
var endPoint = GetPoint(action.EndElementId, action.EndX, action.EndY, session);
97+
98+
_logger.LogDebug("Moving mouse to starting point ({X}, {Y})", startingPoint.X, startingPoint.Y);
99+
Mouse.Position = startingPoint;
69100

70-
if (action.EndX.HasValue && action.EndY.HasValue)
101+
if (endPoint == startingPoint)
71102
{
72-
_logger.LogDebug("Moving mouse to ({X}, {Y})", action.EndX.Value, action.EndY.Value);
73-
Mouse.MoveTo(action.EndX.Value, action.EndY.Value);
103+
// Hover for specified time
104+
await Task.Delay(action.DurationMs ?? 100);
105+
return;
74106
}
75-
else if (action.EndElementId != null)
107+
108+
_logger.LogDebug("Moving mouse to end point ({X}, {Y})", endPoint.X, endPoint.Y);
109+
if (action.DurationMs.HasValue)
76110
{
77-
var element = session.FindKnownElementById(action.EndElementId);
78-
if (element == null)
111+
if (action.DurationMs.Value <= 0)
79112
{
80-
throw WebDriverResponseException.ElementNotFound(action.EndElementId);
113+
throw WebDriverResponseException.UnsupportedOperation("Duration less than or equal to zero is not supported");
81114
}
82-
_logger.LogDebug("Moving mouse to element {ElementId}", action.EndElementId);
83-
Mouse.MoveTo(element.BoundingRectangle.Location);
84-
}
85-
else
86-
{
87-
throw WebDriverResponseException.InvalidArgument("Either \"endElementId\" or \"endX\" and \"endY\" must be provided");
115+
Mouse.MovePixelsPerMillisecond = endPoint.Distance(startingPoint) / action.DurationMs.Value;
88116
}
117+
Mouse.MoveTo(endPoint);
89118
}
90119

91120
public async Task ExecuteKeyScript(Session session, WindowsKeyScript action)

0 commit comments

Comments
 (0)