From 348e19d8469b840f14377667cf3f6fe3f29d6b23 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Mon, 26 Oct 2015 09:55:17 +0000 Subject: [PATCH 01/17] Touch executors - Press - Move - Release - SingleTap - DoubleTap - Long Press - Scroll - Flick --- .../TouchDoubleTapExecutor.cs | 32 +++++++ .../CommandExecutors/TouchFlickExecutor.cs | 73 +++++++++++++++ .../TouchLongPressExecutor.cs | 70 +++++++++++++++ .../CommandExecutors/TouchMoveExecutor.cs | 35 ++++++++ .../CommandExecutors/TouchPressExecutor.cs | 35 ++++++++ .../CommandExecutors/TouchReleaseExecutor.cs | 35 ++++++++ .../CommandExecutors/TouchScrollExecutor.cs | 90 +++++++++++++++++++ .../TouchSingleTapExecutor.cs | 32 +++++++ .../Winium.Desktop.Driver.csproj | 8 ++ 9 files changed, 410 insertions(+) create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchDoubleTapExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchSingleTapExecutor.cs diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchDoubleTapExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchDoubleTapExecutor.cs new file mode 100644 index 0000000..475b807 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchDoubleTapExecutor.cs @@ -0,0 +1,32 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchDoubleTapExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + if (!this.ExecutedCommand.Parameters.ContainsKey("element")) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + + return TouchSimulator.DoubleTap(element) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs new file mode 100644 index 0000000..418ad50 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs @@ -0,0 +1,73 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + using System.Threading; + using System.Windows; + + using Winium.Cruciatus; + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchFlickExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + if (this.ExecutedCommand.Parameters.ContainsKey("element")) + { + return FlickElement(); + } + + return Flick(); + } + + string Flick() + { + if (!(this.ExecutedCommand.Parameters.ContainsKey("xspeed") + && this.ExecutedCommand.Parameters.ContainsKey("yspeed"))) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var xSpeed = Convert.ToInt32(this.ExecutedCommand.Parameters["xspeed"]); + var ySpeed = Convert.ToInt32(this.ExecutedCommand.Parameters["yspeed"]); + + return TouchSimulator.Flick(xSpeed, ySpeed) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + string FlickElement() + { + if ( + !(this.ExecutedCommand.Parameters.ContainsKey("element") + && this.ExecutedCommand.Parameters.ContainsKey("xoffset") + && this.ExecutedCommand.Parameters.ContainsKey("yoffset") + && this.ExecutedCommand.Parameters.ContainsKey("speed"))) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + var element = this.Automator.ElementsRegistry.GetRegisteredElementOrNull(registeredKey); + + var xOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"]); + var yOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"]); + + var pixelsPerSecond = Convert.ToInt32(this.ExecutedCommand.Parameters["speed"]); + + return TouchSimulator.FlickElement(element, xOffset, yOffset, pixelsPerSecond) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs new file mode 100644 index 0000000..e649888 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs @@ -0,0 +1,70 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + + using Winium.Cruciatus.Core; + using Winium.Cruciatus.Elements; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchLongPressExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + var haveElement = this.ExecutedCommand.Parameters.ContainsKey("element"); + var havePoint = this.ExecutedCommand.Parameters.ContainsKey("x") + && this.ExecutedCommand.Parameters.ContainsKey("y"); + + if (!(haveElement || havePoint)) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + bool success; + CruciatusElement element = null; + var x = 0; + var y = 0; + + if (haveElement) + { + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + } + + if (havePoint) + { + x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); + y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + } + + var duration = this.ExecutedCommand.Parameters.ContainsKey("duration") + ? Convert.ToInt32(this.ExecutedCommand.Parameters["duration"]) + : 1000; + + if (haveElement && havePoint) + { + success = TouchSimulator.LongTap(element, x, y, duration); + } + else if (haveElement) + { + success = TouchSimulator.LongTap(element, duration); + } + else + { + success = TouchSimulator.LongTap(x, y, duration); + } + + return success + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs new file mode 100644 index 0000000..d520354 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs @@ -0,0 +1,35 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchMoveExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + if (!this.ExecutedCommand.Parameters.ContainsKey("x") + && this.ExecutedCommand.Parameters.ContainsKey("y")) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); + var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + + return TouchSimulator.TouchUpdate(x, y) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs new file mode 100644 index 0000000..9582a74 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs @@ -0,0 +1,35 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchPressExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + if (!this.ExecutedCommand.Parameters.ContainsKey("x") + && this.ExecutedCommand.Parameters.ContainsKey("y")) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); + var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + + return TouchSimulator.TouchDown(x, y) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs new file mode 100644 index 0000000..de541a8 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs @@ -0,0 +1,35 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchReleaseExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + if (!this.ExecutedCommand.Parameters.ContainsKey("x") + && this.ExecutedCommand.Parameters.ContainsKey("y")) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); + var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + + return TouchSimulator.TouchUp(x, y) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed ('x' and 'y' must match preceeding 'down' or 'move' request)"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs new file mode 100644 index 0000000..541642e --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs @@ -0,0 +1,90 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + using System.Threading; + using System.Windows; + + using Winium.Cruciatus; + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchScrollExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + var haveElement = this.ExecutedCommand.Parameters.ContainsKey("element"); + var haveOffset = this.ExecutedCommand.Parameters.ContainsKey("xoffset") + && this.ExecutedCommand.Parameters.ContainsKey("yoffset"); + + if (!haveOffset) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var element = CruciatusFactory.Root; + + if (haveElement) + { + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + } + + var rect = element.Properties.BoundingRectangle; + + var startPoint = new Point( + rect.Left + (rect.Width / 2), + rect.Top + (rect.Height / 2)); + + var xOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"]); + var yOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"]); + + var endPoint = new Point( + startPoint.X + xOffset, + startPoint.Y + yOffset); + + if (!TouchSimulator.TouchDown((int)startPoint.X, (int)startPoint.Y)) + { + return this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + var distance = Math.Sqrt(Math.Pow(startPoint.X - endPoint.X, 2) + Math.Pow(startPoint.Y - endPoint.Y, 2)); + + for (var soFar = 6; soFar < distance; soFar += 6) + { + var soFarFraction = soFar / distance; + + var x = (int)(startPoint.X + (xOffset * soFarFraction)); + var y = (int)(startPoint.Y + (yOffset * soFarFraction)); + if (!TouchSimulator.TouchUpdate(x, y)) + { + return this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + Thread.Sleep(8); + } + + var startTime = DateTime.Now; + while (DateTime.Now < (startTime + TimeSpan.FromMilliseconds(500))) + { + if (!TouchSimulator.TouchUpdate((int)endPoint.X, (int)endPoint.Y)) + { + return this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + Thread.Sleep(16); + } + + return TouchSimulator.TouchUp((int)endPoint.X, (int)endPoint.Y) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchSingleTapExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchSingleTapExecutor.cs new file mode 100644 index 0000000..6dbaeba --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchSingleTapExecutor.cs @@ -0,0 +1,32 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using Winium.Cruciatus.Core; + using Winium.StoreApps.Common; + + #endregion + + internal class TouchSingleTapExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + if (!ExecutedCommand.Parameters.ContainsKey("element")) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + + return TouchSimulator.Tap(element) + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + #endregion + } +} diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj index bf71cd7..f1d0c22 100644 --- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj +++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj @@ -113,6 +113,14 @@ + + + + + + + + From fc17d79a0fc8bc9ff3a0d61074c7160d07e5ca56 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Mon, 26 Oct 2015 09:59:02 +0000 Subject: [PATCH 02/17] GetElementLocation executor --- .../GetElementLocationExecutor.cs | 33 +++++++++++++++++++ .../Winium.Desktop.Driver.csproj | 1 + 2 files changed, 34 insertions(+) create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/GetElementLocationExecutor.cs diff --git a/src/Winium.Desktop.Driver/CommandExecutors/GetElementLocationExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/GetElementLocationExecutor.cs new file mode 100644 index 0000000..0f8ed26 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/GetElementLocationExecutor.cs @@ -0,0 +1,33 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System.Collections.Generic; + + using Winium.StoreApps.Common; + + #endregion + + internal class GetElementLocationExecutor : CommandExecutorBase + { + #region Methods + + protected override string DoImpl() + { + var registeredKey = this.ExecutedCommand.Parameters["ID"].ToString(); + + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + + var boundingRect = element.Properties.BoundingRectangle; + + var response = new Dictionary + { + { "x", boundingRect.X }, + { "y", boundingRect.Y } + }; + return this.JsonResponse(ResponseStatus.Success, response); + } + + #endregion + } +} diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj index f1d0c22..9ce25ec 100644 --- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj +++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj @@ -71,6 +71,7 @@ + From 79ac87df29821957e392d8059e43c10b6bd27763 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Mon, 26 Oct 2015 11:04:00 +0000 Subject: [PATCH 03/17] Touch down/move/up relative to element Not part of JSWP but implemented in Appium --- .../CommandExecutors/TouchMoveExecutor.cs | 16 +++++++++++++++- .../CommandExecutors/TouchPressExecutor.cs | 16 +++++++++++++++- .../CommandExecutors/TouchReleaseExecutor.cs | 16 +++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs index d520354..8364c26 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs @@ -25,7 +25,21 @@ protected override string DoImpl() var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); - return TouchSimulator.TouchUpdate(x, y) + bool success; + + if (this.ExecutedCommand.Parameters.ContainsKey("element")) + { + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + + success = TouchSimulator.TouchUpdate(element, x, y); + } + else + { + success = TouchSimulator.TouchUpdate(x, y); + } + + return success ? this.JsonResponse() : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); } diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs index 9582a74..c0efa71 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs @@ -25,7 +25,21 @@ protected override string DoImpl() var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); - return TouchSimulator.TouchDown(x, y) + bool success; + + if (this.ExecutedCommand.Parameters.ContainsKey("element")) + { + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + + success = TouchSimulator.TouchDown(element, x, y); + } + else + { + success = TouchSimulator.TouchDown(x, y); + } + + return success ? this.JsonResponse() : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); } diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs index de541a8..df15c22 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs @@ -25,7 +25,21 @@ protected override string DoImpl() var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); - return TouchSimulator.TouchUp(x, y) + bool success; + + if (this.ExecutedCommand.Parameters.ContainsKey("element")) + { + var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); + + success = TouchSimulator.TouchUp(element, x, y); + } + else + { + success = TouchSimulator.TouchUp(x, y); + } + + return success ? this.JsonResponse() : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed ('x' and 'y' must match preceeding 'down' or 'move' request)"); } From d805c61f327415bb90bf727c5205baba72cc8dd1 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Mon, 26 Oct 2015 11:06:04 +0000 Subject: [PATCH 04/17] Element parameter must, and does, exist here --- .../CommandExecutors/TouchFlickExecutor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs index 418ad50..db702d3 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs @@ -56,7 +56,7 @@ string FlickElement() } var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); - var element = this.Automator.ElementsRegistry.GetRegisteredElementOrNull(registeredKey); + var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); var xOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"]); var yOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"]); From 2e66d3ec95bee75daae8c8a11ed3b7fcd3ef3548 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 28 Oct 2015 16:01:17 +0000 Subject: [PATCH 05/17] Stop long request messages from getting truncated --- src/Winium.Desktop.Driver/HttpRequest.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Winium.Desktop.Driver/HttpRequest.cs b/src/Winium.Desktop.Driver/HttpRequest.cs index 5c9aa2f..81ea1c4 100644 --- a/src/Winium.Desktop.Driver/HttpRequest.cs +++ b/src/Winium.Desktop.Driver/HttpRequest.cs @@ -59,7 +59,11 @@ private static int GetContentLength(IReadOnlyDictionary headers) private static string ReadContent(TextReader textReader, int contentLength) { var readBuffer = new char[contentLength]; - textReader.Read(readBuffer, 0, readBuffer.Length); + var bytesRead = 0; + while (bytesRead < contentLength) + { + bytesRead += textReader.Read(readBuffer, bytesRead, contentLength - bytesRead); + } return readBuffer.Aggregate(string.Empty, (current, ch) => current + ch); } From 4417be5acebe22af1e06bbcc33f4c2d2c3135909 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 28 Oct 2015 16:02:07 +0000 Subject: [PATCH 06/17] DriverCommand properties for /touch/perform and /touch/multi/perform --- src/Winium.StoreApps.Common/DriverCommand.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Winium.StoreApps.Common/DriverCommand.cs b/src/Winium.StoreApps.Common/DriverCommand.cs index 2773f3f..d8ea9fb 100644 --- a/src/Winium.StoreApps.Common/DriverCommand.cs +++ b/src/Winium.StoreApps.Common/DriverCommand.cs @@ -461,6 +461,18 @@ public static class DriverCommand /// public static readonly string TouchSingleTap = "touchSingleTap"; + /// + /// Represents the TouchPerform command. + /// + /// + public static readonly string TouchPerform = "touchPerform"; + + /// + /// Represents the TouchMultiPerform command. + /// + /// + public static readonly string TouchMultiPerform = "touchMultiPerform"; + /// /// Represents the UploadFile command. /// From 8a7e23b94a6c8ec2eee7458861ed0812842a292d Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 28 Oct 2015 16:03:49 +0000 Subject: [PATCH 07/17] Add /touch/perform and /touch/multi/perform to UriDispatchTables --- src/Winium.Desktop.Driver/UriDispatchTables.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Winium.Desktop.Driver/UriDispatchTables.cs b/src/Winium.Desktop.Driver/UriDispatchTables.cs index aa3e610..e504ebc 100644 --- a/src/Winium.Desktop.Driver/UriDispatchTables.cs +++ b/src/Winium.Desktop.Driver/UriDispatchTables.cs @@ -286,7 +286,14 @@ private void InitializeSeleniumCommandDictionary() this.commandDictionary.Add( DriverCommand.TouchFlick, new CommandInfo("POST", "/session/{sessionId}/touch/flick")); + this.commandDictionary.Add( + DriverCommand.TouchPerform, + new CommandInfo("POST", "/session/{sessionId}/touch/perform")); + this.commandDictionary.Add( + DriverCommand.TouchMultiPerform, + new CommandInfo("POST", "/session/{sessionId}/touch/multi/perform")); this.commandDictionary.Add(DriverCommand.UploadFile, new CommandInfo("POST", "/session/{sessionId}/file")); + } private void InitializeWiniumCommandDictionary() From 83923a93ec78d3d40ff5fdec7ad1eb9c80e33826 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 28 Oct 2015 16:04:11 +0000 Subject: [PATCH 08/17] Executor for /touch/perform --- .../CommandExecutors/TouchPerformExecutor.cs | 271 ++++++++++++++++++ .../Winium.Desktop.Driver.csproj | 1 + 2 files changed, 272 insertions(+) create mode 100644 src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs new file mode 100644 index 0000000..48794b5 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs @@ -0,0 +1,271 @@ +namespace Winium.Desktop.Driver.CommandExecutors +{ + #region using + + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Windows; + + using Winium.StoreApps.Common; + using Newtonsoft.Json; + + using Winium.Cruciatus.Core; + using Winium.Cruciatus.Elements; + using Winium.Desktop.Driver.Automator; + using Winium.StoreApps.Common.Exceptions; + + #endregion + + internal class TouchPerformExecutor : CommandExecutorBase + { + + #region Inner classes + + class JsonTouchAction + { + CruciatusElement element; + + [JsonProperty("action")] + public string Action { get; set; } + + [JsonProperty("options")] + public Dictionary Options { get; set; } + } + + class TouchAction + { + public const string LongPress = "longpress"; + public const string MoveTo = "moveto"; + public const string Press = "press"; + public const string Release = "release"; + public const string Tap = "tap"; + public const string Wait = "wait"; + + JsonTouchAction _jsonTouchAction; + + Automator _automator; + + public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) + { + _jsonTouchAction = jsonTouchAction; + _automator = automator; + + if (this.Action == Wait) + { + this.MiliSeconds = Convert.ToInt32(jsonTouchAction.Options["ms"]); + return; + } + + if (this.Action == Release) + { + return; + } + + if (this.Action == LongPress) + { + this.MiliSeconds = jsonTouchAction.Options.ContainsKey("duration") + ? Convert.ToInt32(jsonTouchAction.Options["duration"]) + : 1000; + } + } + + public string Action => _jsonTouchAction.Action.ToLower(); + + public Point GetLocation() + { + var point = new Point(); + + if (_jsonTouchAction.Options.ContainsKey("element")) + { + var element = _automator.ElementsRegistry.GetRegisteredElement( + _jsonTouchAction.Options["element"]); + + var rect = element.Properties.BoundingRectangle; + + point.X = (int)rect.Left; + point.Y = (int)rect.Top; + } + + if (_jsonTouchAction.Options.ContainsKey("x")) + { + point.X += Convert.ToInt32(_jsonTouchAction.Options["x"]); + } + + if (_jsonTouchAction.Options.ContainsKey("y")) + { + point.Y += Convert.ToInt32(_jsonTouchAction.Options["y"]); + } + + return point; + } + + public int MiliSeconds { get; } + } + + #endregion + + #region Methods + + protected override string DoImpl() + { + if (!this.ExecutedCommand.Parameters.ContainsKey("actions")) + { + // TODO: in the future '400 : invalid argument' will be used + return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); + } + + var actions = this.ExecutedCommand.Parameters["actions"] + .ToObject>() + .Select(a => new TouchAction(a, this.Automator)) + .ToList(); + + var success = false; + + if (actions.Count == 4 + && actions[0].Action == TouchAction.Press + && actions[1].Action == TouchAction.Wait + && actions[2].Action == TouchAction.MoveTo + && actions[3].Action == TouchAction.Release) + { + success = Flick(actions); + } + else if (actions.Count == 5 + && actions[0].Action == TouchAction.Press + && actions[1].Action == TouchAction.Wait + && actions[2].Action == TouchAction.MoveTo + && actions[3].Action == TouchAction.Wait + && actions[4].Action == TouchAction.Release) + { + success = DragWithTimes(actions); + } + else if (actions.Count == 3 + && actions[0].Action == TouchAction.LongPress + && actions[1].Action == TouchAction.MoveTo + && actions[2].Action == TouchAction.Release) + { + success = Drag(actions); + } + else + { + success = Perform(actions); + } + + return success + ? this.JsonResponse() + : this.JsonResponse(ResponseStatus.UnknownError, "Touch input failed"); + } + + private static bool Flick(List actions) + { + var startPoint = actions[0].GetLocation(); + var endPoint = actions[2].GetLocation(); + + return TouchSimulator.Flick( + (int)startPoint.X, + (int)startPoint.Y, + (int)endPoint.X, + (int)endPoint.Y, + actions[1].MiliSeconds); + } + + private static bool DragWithTimes(List actions) + { + var startPoint = actions[0].GetLocation(); + var endPoint = actions[2].GetLocation(); + + return TouchSimulator.Scroll( + (int)startPoint.X, + (int)startPoint.Y, + (int)endPoint.X, + (int)endPoint.Y, + actions[1].MiliSeconds, + actions[3].MiliSeconds); + } + + private static bool Drag(List actions) + { + var startPoint = actions[0].GetLocation(); + var endPoint = actions[1].GetLocation(); + + return TouchSimulator.Scroll( + (int)startPoint.X, + (int)startPoint.Y, + (int)endPoint.X, + (int)endPoint.Y); + } + + private static bool Perform(List actions) + { + var previousX = 0; + var previousY = 0; + var havePrevious = false; + string previousAction = null; + + foreach (var action in actions) + { + Point point; + + switch (action.Action) + { + case TouchAction.LongPress: + point = action.GetLocation(); + TouchSimulator.LongTap((int)point.X, (int)point.Y, action.MiliSeconds); + havePrevious = false; + break; + case TouchAction.MoveTo: + point = action.GetLocation(); + TouchSimulator.TouchUpdate((int)point.X, (int)point.Y); + previousX = (int)point.X; + previousY = (int)point.Y; + havePrevious = true; + break; + case TouchAction.Press: + point = action.GetLocation(); + TouchSimulator.TouchDown((int)point.X, (int)point.Y); + previousX = (int)point.X; + previousY = (int)point.Y; + havePrevious = true; + break; + case TouchAction.Release: + if (previousAction == TouchAction.Tap || previousAction == TouchAction.LongPress) + { + break; + } + TouchSimulator.TouchUp(previousX, previousY); + havePrevious = false; + break; + case TouchAction.Tap: + point = action.GetLocation(); + TouchSimulator.Tap((int)point.X, (int)point.Y); + havePrevious = false; + break; + case TouchAction.Wait: + if (havePrevious) + { + var startTime = DateTime.Now; + while (DateTime.Now < startTime + TimeSpan.FromMilliseconds(action.MiliSeconds)) + { + TouchSimulator.TouchUpdate(previousX, previousY); + Thread.Sleep(16); + } + } + else + { + Thread.Sleep(action.MiliSeconds); + } + break; + default: + throw new AutomationException($"unrecognised action {action.Action}"); + } + + previousAction = action.Action; + } + + return true; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj index 9ce25ec..9bf19d7 100644 --- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj +++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj @@ -118,6 +118,7 @@ + From 3f487c2cd6ae951998c163fdbdb9cdbe0324e9a2 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 28 Oct 2015 20:10:37 +0000 Subject: [PATCH 09/17] Winium.Cruciatus depends on TCD.System.TouchInjection --- src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj | 4 ++++ src/Winium.Desktop.Driver/packages.config | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj index 9bf19d7..5adb406 100644 --- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj +++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj @@ -50,6 +50,10 @@ + + ..\packages\TCD.System.TouchInjection.1.0.0\lib\net45\TCD.System.TouchInjection.dll + True + diff --git a/src/Winium.Desktop.Driver/packages.config b/src/Winium.Desktop.Driver/packages.config index 8a2562a..4e1f55c 100644 --- a/src/Winium.Desktop.Driver/packages.config +++ b/src/Winium.Desktop.Driver/packages.config @@ -6,5 +6,6 @@ + \ No newline at end of file From f3cbb115e4b3c07adfcdb88a1a922b01e1bac150 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 28 Oct 2015 20:11:19 +0000 Subject: [PATCH 10/17] Touch center of element if no x/y provided --- .../CommandExecutors/TouchPerformExecutor.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs index 48794b5..f27e843 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs @@ -84,8 +84,13 @@ public Point GetLocation() var rect = element.Properties.BoundingRectangle; - point.X = (int)rect.Left; - point.Y = (int)rect.Top; + point.X = _jsonTouchAction.Options.ContainsKey("x") + ? rect.Left + : (rect.Left + (rect.Width / 2)); + + point.Y = _jsonTouchAction.Options.ContainsKey("y") + ? rect.Top + : (rect.Top + (rect.Height / 2)); } if (_jsonTouchAction.Options.ContainsKey("x")) From 581116bfb26e912dc33ed981efeee513328539a5 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Thu, 29 Oct 2015 15:23:31 +0000 Subject: [PATCH 11/17] Move TouchAction classes out of TouchPerformExecutor They will be used by TouchMultiPerformExecutor as well --- .../CommandExecutors/TouchPerformExecutor.cs | 96 +---------------- .../CommandHelpers/JsonTouchAction.cs | 22 ++++ .../CommandHelpers/TouchAction.cs | 102 ++++++++++++++++++ .../Winium.Desktop.Driver.csproj | 2 + 4 files changed, 127 insertions(+), 95 deletions(-) create mode 100644 src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs create mode 100644 src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs index f27e843..4ed0c0a 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs @@ -9,108 +9,14 @@ using System.Windows; using Winium.StoreApps.Common; - using Newtonsoft.Json; - using Winium.Cruciatus.Core; - using Winium.Cruciatus.Elements; - using Winium.Desktop.Driver.Automator; + using Winium.Desktop.Driver.CommandHelpers; using Winium.StoreApps.Common.Exceptions; #endregion internal class TouchPerformExecutor : CommandExecutorBase { - - #region Inner classes - - class JsonTouchAction - { - CruciatusElement element; - - [JsonProperty("action")] - public string Action { get; set; } - - [JsonProperty("options")] - public Dictionary Options { get; set; } - } - - class TouchAction - { - public const string LongPress = "longpress"; - public const string MoveTo = "moveto"; - public const string Press = "press"; - public const string Release = "release"; - public const string Tap = "tap"; - public const string Wait = "wait"; - - JsonTouchAction _jsonTouchAction; - - Automator _automator; - - public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) - { - _jsonTouchAction = jsonTouchAction; - _automator = automator; - - if (this.Action == Wait) - { - this.MiliSeconds = Convert.ToInt32(jsonTouchAction.Options["ms"]); - return; - } - - if (this.Action == Release) - { - return; - } - - if (this.Action == LongPress) - { - this.MiliSeconds = jsonTouchAction.Options.ContainsKey("duration") - ? Convert.ToInt32(jsonTouchAction.Options["duration"]) - : 1000; - } - } - - public string Action => _jsonTouchAction.Action.ToLower(); - - public Point GetLocation() - { - var point = new Point(); - - if (_jsonTouchAction.Options.ContainsKey("element")) - { - var element = _automator.ElementsRegistry.GetRegisteredElement( - _jsonTouchAction.Options["element"]); - - var rect = element.Properties.BoundingRectangle; - - point.X = _jsonTouchAction.Options.ContainsKey("x") - ? rect.Left - : (rect.Left + (rect.Width / 2)); - - point.Y = _jsonTouchAction.Options.ContainsKey("y") - ? rect.Top - : (rect.Top + (rect.Height / 2)); - } - - if (_jsonTouchAction.Options.ContainsKey("x")) - { - point.X += Convert.ToInt32(_jsonTouchAction.Options["x"]); - } - - if (_jsonTouchAction.Options.ContainsKey("y")) - { - point.Y += Convert.ToInt32(_jsonTouchAction.Options["y"]); - } - - return point; - } - - public int MiliSeconds { get; } - } - - #endregion - #region Methods protected override string DoImpl() diff --git a/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs b/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs new file mode 100644 index 0000000..b84ece5 --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs @@ -0,0 +1,22 @@ +namespace Winium.Desktop.Driver.CommandHelpers +{ + #region usings + + using System.Collections.Generic; + using Newtonsoft.Json; + + #endregion + + class JsonTouchAction + { + #region Public Properties + + [JsonProperty("action")] + public string Action { get; set; } + + [JsonProperty("options")] + public Dictionary Options { get; set; } + + #endregion + } +} diff --git a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs new file mode 100644 index 0000000..f42199d --- /dev/null +++ b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs @@ -0,0 +1,102 @@ +namespace Winium.Desktop.Driver.CommandHelpers +{ + #region using + + using System; + using System.Windows; + + using Winium.Desktop.Driver.Automator; + + #endregion + + class TouchAction + { + #region Fields + + JsonTouchAction _jsonTouchAction; + + Automator _automator; + + #endregion + + #region Public Constants + + public const string LongPress = "longpress"; + public const string MoveTo = "moveto"; + public const string Press = "press"; + public const string Release = "release"; + public const string Tap = "tap"; + public const string Wait = "wait"; + + #endregion + + #region Public Properties + + public string Action => _jsonTouchAction.Action.ToLower(); + + public int MiliSeconds { get; } + + #endregion + + #region Public Methods + + public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) + { + _jsonTouchAction = jsonTouchAction; + _automator = automator; + + if (this.Action == Wait) + { + this.MiliSeconds = Convert.ToInt32(jsonTouchAction.Options["ms"]); + return; + } + + if (this.Action == Release) + { + return; + } + + if (this.Action == LongPress) + { + this.MiliSeconds = jsonTouchAction.Options.ContainsKey("duration") + ? Convert.ToInt32(jsonTouchAction.Options["duration"]) + : 1000; + } + } + + public Point GetLocation() + { + var point = new Point(); + + if (_jsonTouchAction.Options.ContainsKey("element")) + { + var element = _automator.ElementsRegistry.GetRegisteredElement( + _jsonTouchAction.Options["element"]); + + var rect = element.Properties.BoundingRectangle; + + point.X = _jsonTouchAction.Options.ContainsKey("x") + ? rect.Left + : (rect.Left + (rect.Width / 2)); + + point.Y = _jsonTouchAction.Options.ContainsKey("y") + ? rect.Top + : (rect.Top + (rect.Height / 2)); + } + + if (_jsonTouchAction.Options.ContainsKey("x")) + { + point.X += Convert.ToInt32(_jsonTouchAction.Options["x"]); + } + + if (_jsonTouchAction.Options.ContainsKey("y")) + { + point.Y += Convert.ToInt32(_jsonTouchAction.Options["y"]); + } + + return point; + } + + #endregion + } +} diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj index 5adb406..c51c9f8 100644 --- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj +++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj @@ -127,6 +127,8 @@ + + From c291fe0f38eaf10820be5ae1181ff3ca0352d130 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Thu, 29 Oct 2015 15:28:08 +0000 Subject: [PATCH 12/17] MoveTo actions drag instead of jumping straight to the specified point --- .../CommandExecutors/TouchPerformExecutor.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs index 4ed0c0a..efc76e4 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs @@ -114,8 +114,10 @@ private static bool Perform(List actions) var havePrevious = false; string previousAction = null; - foreach (var action in actions) + for (var i = 0; i < actions.Count; i ++) { + var action = actions[i]; + Point point; switch (action.Action) @@ -126,8 +128,13 @@ private static bool Perform(List actions) havePrevious = false; break; case TouchAction.MoveTo: + int? duration = null; + if (i > 0 && actions[i - 1].Action == TouchAction.Wait) + { + duration = actions[i - 1].MiliSeconds; + } point = action.GetLocation(); - TouchSimulator.TouchUpdate((int)point.X, (int)point.Y); + TouchSimulator.MoveTo(previousX, previousY, (int)point.X, (int)point.Y, duration); previousX = (int)point.X; previousY = (int)point.Y; havePrevious = true; @@ -153,6 +160,10 @@ private static bool Perform(List actions) havePrevious = false; break; case TouchAction.Wait: + if (actions.Count > i + 1 && actions[i + 1].Action == TouchAction.MoveTo) + { + break; + } if (havePrevious) { var startTime = DateTime.Now; From 97dd18e780507b728d37e6f638e474665c16e246 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Thu, 29 Oct 2015 18:13:26 +0000 Subject: [PATCH 13/17] When no element supplied, x/y should be relative to previous action This working differently to the press/wait/moveto/release and the longpress/moveto/release action set doesn't seem like a good idea to me but it's what Appium does in recent versions. --- .../CommandExecutors/TouchPerformExecutor.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs index efc76e4..54afdb8 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs @@ -134,9 +134,11 @@ private static bool Perform(List actions) duration = actions[i - 1].MiliSeconds; } point = action.GetLocation(); - TouchSimulator.MoveTo(previousX, previousY, (int)point.X, (int)point.Y, duration); - previousX = (int)point.X; - previousY = (int)point.Y; + var x = (int)point.X; + var y = (int)point.Y; + TouchSimulator.MoveTo(previousX, previousY, previousX + x, previousY + y, duration); + previousX += x; + previousY += y; havePrevious = true; break; case TouchAction.Press: From d8413da740a6c9ad19ed812b5ff3db1dbb9d9502 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Fri, 30 Oct 2015 11:46:37 +0000 Subject: [PATCH 14/17] Avoid infinite loop in reading request if client disappears --- src/Winium.Desktop.Driver/Listener.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Winium.Desktop.Driver/Listener.cs b/src/Winium.Desktop.Driver/Listener.cs index d9884ac..cc6f07b 100644 --- a/src/Winium.Desktop.Driver/Listener.cs +++ b/src/Winium.Desktop.Driver/Listener.cs @@ -90,7 +90,24 @@ public void StartListening() // Get a stream object for reading and writing using (var stream = client.GetStream()) { - var acceptedRequest = HttpRequest.ReadFromStreamWithoutClosing(stream); + stream.ReadTimeout = 60 * 1000; + + HttpRequest acceptedRequest; + + try + { + acceptedRequest = HttpRequest.ReadFromStreamWithoutClosing(stream); + } + catch (IOException ex) + { + Logger.Error("Error occured while reading request: {0}", ex); + + client.Close(); + Logger.Debug("Client closed\n"); + + continue; + } + Logger.Debug("ACCEPTED REQUEST {0}", acceptedRequest.StartingLine); var response = this.HandleRequest(acceptedRequest); From c20f34abc10addac0e31f563678e0221b906fca8 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Mon, 2 Nov 2015 16:31:06 +0000 Subject: [PATCH 15/17] /touch/perform Tap action takes optional count parameter --- .../CommandExecutors/TouchPerformExecutor.cs | 6 +++++- src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs index 54afdb8..0d7ca03 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPerformExecutor.cs @@ -158,7 +158,11 @@ private static bool Perform(List actions) break; case TouchAction.Tap: point = action.GetLocation(); - TouchSimulator.Tap((int)point.X, (int)point.Y); + for (var n = 1; n <= action.Count; n++) + { + TouchSimulator.Tap((int)point.X, (int)point.Y); + Thread.Sleep(250); + } havePrevious = false; break; case TouchAction.Wait: diff --git a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs index f42199d..8ec3ba5 100644 --- a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs +++ b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs @@ -36,6 +36,8 @@ class TouchAction public int MiliSeconds { get; } + public int Count { get; } + #endregion #region Public Methods @@ -56,6 +58,12 @@ public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) return; } + if (this.Action == Tap) + { + int count; + this.Count = int.TryParse(jsonTouchAction.Options["count"], out count) ? count : 1; + } + if (this.Action == LongPress) { this.MiliSeconds = jsonTouchAction.Options.ContainsKey("duration") From eead1e934b9fff4af03afe7d38c53143233a4dfd Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Tue, 3 Nov 2015 13:20:29 +0000 Subject: [PATCH 16/17] Handle decimal values provided as numeric options. --- .../CommandExecutors/TouchFlickExecutor.cs | 11 ++++++----- .../CommandExecutors/TouchLongPressExecutor.cs | 7 ++++--- .../CommandExecutors/TouchMoveExecutor.cs | 5 +++-- .../CommandExecutors/TouchPressExecutor.cs | 5 +++-- .../CommandExecutors/TouchReleaseExecutor.cs | 5 +++-- .../CommandExecutors/TouchScrollExecutor.cs | 5 +++-- .../CommandHelpers/JsonTouchAction.cs | 6 ++++++ .../CommandHelpers/TouchAction.cs | 8 ++++---- .../Extensions/CommandHelper.cs | 18 ++++++++++++++++++ .../Winium.Desktop.Driver.csproj | 1 + 10 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/Winium.Desktop.Driver/Extensions/CommandHelper.cs diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs index db702d3..070b609 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchFlickExecutor.cs @@ -8,6 +8,7 @@ namespace Winium.Desktop.Driver.CommandExecutors using Winium.Cruciatus; using Winium.Cruciatus.Core; + using Winium.Desktop.Driver.Extensions; using Winium.StoreApps.Common; #endregion @@ -35,8 +36,8 @@ string Flick() return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); } - var xSpeed = Convert.ToInt32(this.ExecutedCommand.Parameters["xspeed"]); - var ySpeed = Convert.ToInt32(this.ExecutedCommand.Parameters["yspeed"]); + var xSpeed = this.ExecutedCommand.GetParameterAsInt("xspeed"); + var ySpeed = this.ExecutedCommand.GetParameterAsInt("yspeed"); return TouchSimulator.Flick(xSpeed, ySpeed) ? this.JsonResponse() @@ -58,10 +59,10 @@ string FlickElement() var registeredKey = this.ExecutedCommand.Parameters["element"].ToString(); var element = this.Automator.ElementsRegistry.GetRegisteredElement(registeredKey); - var xOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"]); - var yOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"]); + var xOffset = this.ExecutedCommand.GetParameterAsInt("xoffset"); + var yOffset = this.ExecutedCommand.GetParameterAsInt("yoffset"); - var pixelsPerSecond = Convert.ToInt32(this.ExecutedCommand.Parameters["speed"]); + var pixelsPerSecond = this.ExecutedCommand.GetParameterAsInt("speed"); return TouchSimulator.FlickElement(element, xOffset, yOffset, pixelsPerSecond) ? this.JsonResponse() diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs index e649888..c7cc60b 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchLongPressExecutor.cs @@ -6,6 +6,7 @@ namespace Winium.Desktop.Driver.CommandExecutors using Winium.Cruciatus.Core; using Winium.Cruciatus.Elements; + using Winium.Desktop.Driver.Extensions; using Winium.StoreApps.Common; #endregion @@ -39,12 +40,12 @@ protected override string DoImpl() if (havePoint) { - x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); - y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + x = this.ExecutedCommand.GetParameterAsInt("x"); + y = this.ExecutedCommand.GetParameterAsInt("y"); } var duration = this.ExecutedCommand.Parameters.ContainsKey("duration") - ? Convert.ToInt32(this.ExecutedCommand.Parameters["duration"]) + ? this.ExecutedCommand.GetParameterAsInt("duration") : 1000; if (haveElement && havePoint) diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs index 8364c26..a09c6a4 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchMoveExecutor.cs @@ -5,6 +5,7 @@ namespace Winium.Desktop.Driver.CommandExecutors using System; using Winium.Cruciatus.Core; + using Winium.Desktop.Driver.Extensions; using Winium.StoreApps.Common; #endregion @@ -22,8 +23,8 @@ protected override string DoImpl() return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); } - var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); - var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + var x = this.ExecutedCommand.GetParameterAsInt("x"); + var y = this.ExecutedCommand.GetParameterAsInt("y"); bool success; diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs index c0efa71..e6c7014 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchPressExecutor.cs @@ -5,6 +5,7 @@ using System; using Winium.Cruciatus.Core; + using Winium.Desktop.Driver.Extensions; using Winium.StoreApps.Common; #endregion @@ -22,8 +23,8 @@ protected override string DoImpl() return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); } - var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); - var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + var x = this.ExecutedCommand.GetParameterAsInt("x"); + var y = this.ExecutedCommand.GetParameterAsInt("y"); bool success; diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs index df15c22..c9b336b 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchReleaseExecutor.cs @@ -5,6 +5,7 @@ namespace Winium.Desktop.Driver.CommandExecutors using System; using Winium.Cruciatus.Core; + using Winium.Desktop.Driver.Extensions; using Winium.StoreApps.Common; #endregion @@ -22,8 +23,8 @@ protected override string DoImpl() return this.JsonResponse(ResponseStatus.UnknownError, "WRONG PARAMETERS"); } - var x = Convert.ToInt32(this.ExecutedCommand.Parameters["x"]); - var y = Convert.ToInt32(this.ExecutedCommand.Parameters["y"]); + var x = this.ExecutedCommand.GetParameterAsInt("x"); + var y = this.ExecutedCommand.GetParameterAsInt("y"); bool success; diff --git a/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs index 541642e..76adeb3 100644 --- a/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs +++ b/src/Winium.Desktop.Driver/CommandExecutors/TouchScrollExecutor.cs @@ -8,6 +8,7 @@ namespace Winium.Desktop.Driver.CommandExecutors using Winium.Cruciatus; using Winium.Cruciatus.Core; + using Winium.Desktop.Driver.Extensions; using Winium.StoreApps.Common; #endregion @@ -42,8 +43,8 @@ protected override string DoImpl() rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2)); - var xOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["xoffset"]); - var yOffset = Convert.ToInt32(this.ExecutedCommand.Parameters["yoffset"]); + var xOffset = this.ExecutedCommand.GetParameterAsInt("xoffset"); + var yOffset = this.ExecutedCommand.GetParameterAsInt("yoffset"); var endPoint = new Point( startPoint.X + xOffset, diff --git a/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs b/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs index b84ece5..504e140 100644 --- a/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs +++ b/src/Winium.Desktop.Driver/CommandHelpers/JsonTouchAction.cs @@ -2,6 +2,7 @@ { #region usings + using System; using System.Collections.Generic; using Newtonsoft.Json; @@ -17,6 +18,11 @@ class JsonTouchAction [JsonProperty("options")] public Dictionary Options { get; set; } + public int GetOptionAsInt(string optionName) + { + return (int)Math.Round(Convert.ToDouble(Options[optionName])); + } + #endregion } } diff --git a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs index 8ec3ba5..bac8afa 100644 --- a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs +++ b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs @@ -49,7 +49,7 @@ public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) if (this.Action == Wait) { - this.MiliSeconds = Convert.ToInt32(jsonTouchAction.Options["ms"]); + this.MiliSeconds = jsonTouchAction.GetOptionAsInt("ms"); return; } @@ -67,7 +67,7 @@ public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) if (this.Action == LongPress) { this.MiliSeconds = jsonTouchAction.Options.ContainsKey("duration") - ? Convert.ToInt32(jsonTouchAction.Options["duration"]) + ? jsonTouchAction.GetOptionAsInt("duration") : 1000; } } @@ -94,12 +94,12 @@ public Point GetLocation() if (_jsonTouchAction.Options.ContainsKey("x")) { - point.X += Convert.ToInt32(_jsonTouchAction.Options["x"]); + point.X += _jsonTouchAction.GetOptionAsInt("x"); } if (_jsonTouchAction.Options.ContainsKey("y")) { - point.Y += Convert.ToInt32(_jsonTouchAction.Options["y"]); + point.Y += _jsonTouchAction.GetOptionAsInt("y"); } return point; diff --git a/src/Winium.Desktop.Driver/Extensions/CommandHelper.cs b/src/Winium.Desktop.Driver/Extensions/CommandHelper.cs new file mode 100644 index 0000000..ce9cde8 --- /dev/null +++ b/src/Winium.Desktop.Driver/Extensions/CommandHelper.cs @@ -0,0 +1,18 @@ +namespace Winium.Desktop.Driver.Extensions +{ + #region using + + using System; + + using Winium.StoreApps.Common; + + #endregion + + public static class CommandHelper + { + public static int GetParameterAsInt(this Command command, string propertyName) + { + return (int)Math.Round(Convert.ToDouble(command.Parameters[propertyName])); + } + } +} diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj index c51c9f8..3d044b1 100644 --- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj +++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj @@ -133,6 +133,7 @@ + From 3cf94cd676257ea2134fd8a73b10f29c26cd7840 Mon Sep 17 00:00:00 2001 From: Jonathan Stoneman Date: Wed, 11 Nov 2015 15:53:52 +0100 Subject: [PATCH 17/17] Fix key not found exception when count is not provided --- src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs index bac8afa..6687bcb 100644 --- a/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs +++ b/src/Winium.Desktop.Driver/CommandHelpers/TouchAction.cs @@ -60,8 +60,9 @@ public TouchAction(JsonTouchAction jsonTouchAction, Automator automator) if (this.Action == Tap) { - int count; - this.Count = int.TryParse(jsonTouchAction.Options["count"], out count) ? count : 1; + this.Count = jsonTouchAction.Options.ContainsKey("count") + ? Convert.ToInt32(jsonTouchAction.Options["count"]) + : 1; } if (this.Action == LongPress)