Skip to content

Commit

Permalink
Add support for winui3 (#29)
Browse files Browse the repository at this point in the history
* Add support for winui

* Small refactor

* Fix timeout

* Small refactorings

* Small refactorings

* Replace previous solution and support app arguments

* Reformatting
  • Loading branch information
Gitii committed Aug 17, 2022
1 parent 668a2eb commit 4008ec8
Show file tree
Hide file tree
Showing 15 changed files with 372 additions and 84 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[*.cs]
indent_style = space
indent_size = 2
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

.config

# User-specific files
*.rsuser
*.suo
Expand Down
5 changes: 3 additions & 2 deletions WinAppDriver.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30611.23
# Visual Studio Version 17
VisualStudioVersion = 17.3.32804.467
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infra", "src\Infra\Infra.csproj", "{0AEB4D3B-2969-42B1-8B08-9577EB9C44EA}"
EndProject
Expand All @@ -15,6 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinAppDriver.IntegrationTes
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{37A70166-F25D-4B38-ACAE-9A3E53A4B974}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
README.md = README.md
EndProjectSection
EndProject
Expand Down
74 changes: 53 additions & 21 deletions src/Infra/Communication/ApplicationMananger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
using Microsoft.Windows.Apps.Test.Foundation;
using Microsoft.Windows.Apps.Test.Foundation.Waiters;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WinAppDriver.Infra.Helper;
using WinAppDriver.Infra.ModernApp;

namespace WinAppDriver.Infra.Communication
{
Expand All @@ -18,41 +18,67 @@ private UIObject GetTopLevelWindow(UIObject uiObject)
{
if (uiObject == null) return null;

while (uiObject.Parent != UIObject.Root) {
while (uiObject.Parent != UIObject.Root)
{
uiObject = uiObject.Parent;
}

return uiObject;
}

private UICondition GetForceMatchCondition(string forceMatchAppTitle, string forceMatchClassName)
{
if (string.IsNullOrEmpty(forceMatchAppTitle))
{
return string.IsNullOrEmpty(forceMatchClassName) ? null : UICondition.CreateFromClassName(forceMatchClassName);
return string.IsNullOrEmpty(forceMatchClassName)
? null
: UICondition.CreateFromClassName(forceMatchClassName);
}
else if (string.IsNullOrEmpty(forceMatchClassName))
{
return UICondition.CreateFromName(forceMatchAppTitle);
}
return UICondition.CreateFromName(forceMatchAppTitle).AndWith(UICondition.CreateFromClassName(forceMatchClassName));

return UICondition.CreateFromName(forceMatchAppTitle)
.AndWith(UICondition.CreateFromClassName(forceMatchClassName));
}


// refer https://github.com/microsoft/microsoft-ui-xaml/blob/40531c714f8003bf0d341a0729fa04dd2ed87710/test/testinfra/MUXTestInfra/Infra/Application.cs#L269
public IApplication LaunchModernApp(string appName, string forceMatchAppTitle, string forceMatchClassName)
public IApplication LaunchModernApp(string appName, string arguments, string forceMatchClassName,
string forceMatchAppTitle)
{
UICondition condition = UICondition.CreateFromClassName("ApplicationFrameWindow").OrWith(UICondition.CreateFromClassName("Windows.UI.Core.CoreWindow"));
UICondition condition = UICondition.CreateFromClassName("ApplicationFrameWindow")
.OrWith(UICondition.CreateFromClassName("Windows.UI.Core.CoreWindow"))
.OrWith(UICondition.CreateFromClassName("WinUIDesktopWin32WindowClass"));

var forceMatch = GetForceMatchCondition(forceMatchAppTitle, forceMatchClassName);
if (forceMatch != null)
{
condition = condition.OrWith(forceMatch);
}

var coreWindow = UAPApp.Launch(appName, condition);
var rootWindow = GetTopLevelWindow(coreWindow);
return new Application(new Element(rootWindow), coreWindow.ProcessId);
try
{
var launchedApp = ModernAppManager.Launch(appName, arguments, condition);

var coreWindow = UIObjectHelpers.GetTopLevelUIObject(launchedApp,
new[] { UIObjectHelpers.UWP_CLASS_NAME, UIObjectHelpers.WINUI_CLASS_NAME });
var rootWindow = GetTopLevelWindow(coreWindow);

return new Application(new Element(rootWindow), coreWindow.ProcessId);
}
catch
{
// dump ui object tree to make debugging easier
UIObjectHelpers.LogObjectTree(UIObject.Root);

throw;
}
}

public IApplication LaunchLegacyApp(string filename, string arguments, string workingDirectory, string forceMatchAppTitle, string forceMatchClassName)
public IApplication LaunchLegacyApp(string filename, string arguments, string workingDirectory,
string forceMatchAppTitle, string forceMatchClassName)
{
var forceMatch = GetForceMatchCondition(forceMatchAppTitle, forceMatchClassName);

Expand Down Expand Up @@ -83,6 +109,7 @@ public IApplication LaunchLegacyApp(string filename, string arguments, string wo
{
throw new AppLaunchException("Fail to start legacy process");
}

windowOpenedWaiter.TryWait(TimeSpan.FromSeconds(10));

int retry = 5;
Expand All @@ -92,16 +119,17 @@ public IApplication LaunchLegacyApp(string filename, string arguments, string wo
{
// check if the new opened window
if (windowOpenedWaiter.Source != null)
{
{
var root = GetTopLevelWindow(windowOpenedWaiter.Source);
if (windowOpenedWaiter.Source.ProcessId == process.Id || (forceMatch != null && root.Matches(forceMatch)))
if (windowOpenedWaiter.Source.ProcessId == process.Id ||
(forceMatch != null && root.Matches(forceMatch)))
{
return new Application(new Element(root), process.Id);
}
}

Task.Delay(sleepTimer).Wait(sleepTimer);
}

}

var condition = UICondition.Create(UIProperty.Get(ActionStrings.ProcessId), process.Id);
Expand All @@ -123,7 +151,7 @@ public IApplication LaunchLegacyApp(string filename, string arguments, string wo
}
}


public IApplication LaunchApplication(Capabilities capabilities)
{
var app = capabilities.app;
Expand All @@ -134,7 +162,9 @@ public IApplication LaunchApplication(Capabilities capabilities)
{
var attachToTopLevelWindowClassName = capabilities.attachToTopLevelWindowClassName;

Debug.WriteLine("LaunchApplication attach to " + attachToTopLevelWindowClassName == null ? "Root" : "window with ClassName" + attachToTopLevelWindowClassName);
Debug.WriteLine("LaunchApplication attach to " + attachToTopLevelWindowClassName == null
? "Root"
: "window with ClassName" + attachToTopLevelWindowClassName);

if (String.IsNullOrEmpty(attachToTopLevelWindowClassName))
{
Expand All @@ -146,7 +176,8 @@ public IApplication LaunchApplication(Capabilities capabilities)
var matched = UIObject.Root.Children.FindMultiple(condition).FirstOrDefault();
if (matched == null)
{
throw new AppLaunchException("There is no window match with class name " + attachToTopLevelWindowClassName);
throw new AppLaunchException("There is no window match with class name " +
attachToTopLevelWindowClassName);
}
else
{
Expand All @@ -157,14 +188,15 @@ public IApplication LaunchApplication(Capabilities capabilities)
else if (app.Contains("!"))
{
Debug.WriteLine("Start UWPApp " + app);
return LaunchModernApp(capabilities.app, capabilities.forceMatchAppTitle, capabilities.forceMatchClassName);
return LaunchModernApp(capabilities.app, capabilities.appArguments, capabilities.forceMatchClassName,
capabilities.forceMatchAppTitle);
}
else
{
Debug.WriteLine("Start Legacy app " + capabilities.ToString());
return LaunchLegacyApp(app, capabilities.appArguments, capabilities.appWorkingDir, capabilities.forceMatchAppTitle, capabilities.forceMatchClassName);
return LaunchLegacyApp(app, capabilities.appArguments, capabilities.appWorkingDir,
capabilities.forceMatchAppTitle, capabilities.forceMatchClassName);
}

}
}
}
}
4 changes: 1 addition & 3 deletions src/Infra/Helper/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace WinAppDriver.Infra.Helper
{
Expand All @@ -19,4 +17,4 @@ public class Helpers
[DllImport("user32.dll", SetLastError = true)]
public static extern bool BringWindowToTop(IntPtr hWnd);
}
}
}
5 changes: 1 addition & 4 deletions src/Infra/Helper/JsonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
// Licensed under the MIT License.

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace WinAppDriver.Infra.Utils
{
Expand All @@ -24,4 +21,4 @@ public static string Serialize<T>(T obj)
return JsonConvert.SerializeObject(obj);
}
}
}
}
84 changes: 41 additions & 43 deletions src/Infra/Helper/KeyboardHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

namespace WinAppDriver.Infra.Communication
{


class KeyboardHelper
{
// https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#sessionsessionidelementidvalue
Expand All @@ -17,18 +15,18 @@ class KeyboardHelper
public const char TAB = '\uE004';
public const char CLEAR = '\uE005';
public const char RETURN = '\uE006';
public const char ENTER = '\uE007';
public const char ENTER = '\uE007';
public const char SHIFT = '\uE008';
public const char CONTROL = '\uE009';
public const char CONTROL = '\uE009';
public const char ALT = '\uE00A';
public const char PAUSE = '\uE00B';
public const char ESCAPE = '\uE00C';
public const char ESCAPE = '\uE00C';
public const char SPACE = '\uE00D';
public const char PAGEUP = '\uE00E';
public const char PAGEUP = '\uE00E';
public const char PAGEDOWN = '\uE00F';
public const char END = '\uE010';
public const char END = '\uE010';
public const char HOME = '\uE011';
public const char LEFTARROW = '\uE012';
public const char LEFTARROW = '\uE012';
public const char UPARROW = '\uE013';
public const char RIGHTARROW = '\uE014';
public const char DOWNARROW = '\uE015';
Expand Down Expand Up @@ -68,36 +66,36 @@ class KeyboardHelper

//https://github.com/microsoft/microsoft-ui-xaml/blob/c46d28b3e706a24a5b89ec110ac2e93a9a86aa58/test/testinfra/MUXTestInfra/Common/KeyboardHelper.cs#L58
private static Dictionary<char, string> keyToKeyStringDictionary = new Dictionary<char, string>()
{
{ ENTER, "{ENTER}" },
{ ESCAPE, "{ESC}" },
{ TAB, "{TAB}" },
{ UPARROW, "{UP}" },
{ DOWNARROW, "{DOWN}" },
{ LEFTARROW, "{LEFT}" },
{ RIGHTARROW, "{RIGHT}" },
{ PAGEUP, "{PGUP}" },
{ PAGEDOWN, "{PGDN}" },
{ HOME, "{HOME}" },
{ END, "{END}" },
{ SPACE, "{SPACE}" },
{ BACKSPACE, "{BACKSPACE}" },
{ F10, "{F10}" },
{ F9, "{F9}" },
{ F8, "{F8}" },
{ F7, "{F7}" },
{ F6, "{F6}" },
{ F5, "{F5}" },
{ F4, "{F4}" },
{ F3, "{F3}" },
{ F2, "{F2}" },
{ F1, "{F1}" },
{ RETURN, "{RETURN}" },
{ DELETE, "{DELETE}" },
};
{
{ ENTER, "{ENTER}" },
{ ESCAPE, "{ESC}" },
{ TAB, "{TAB}" },
{ UPARROW, "{UP}" },
{ DOWNARROW, "{DOWN}" },
{ LEFTARROW, "{LEFT}" },
{ RIGHTARROW, "{RIGHT}" },
{ PAGEUP, "{PGUP}" },
{ PAGEDOWN, "{PGDN}" },
{ HOME, "{HOME}" },
{ END, "{END}" },
{ SPACE, "{SPACE}" },
{ BACKSPACE, "{BACKSPACE}" },
{ F10, "{F10}" },
{ F9, "{F9}" },
{ F8, "{F8}" },
{ F7, "{F7}" },
{ F6, "{F6}" },
{ F5, "{F5}" },
{ F4, "{F4}" },
{ F3, "{F3}" },
{ F2, "{F2}" },
{ F1, "{F1}" },
{ RETURN, "{RETURN}" },
{ DELETE, "{DELETE}" },
};



public static string TranslateKey(string keys)
public static string TranslateKey(string keys)
{
keys = Keyboard.EscapeSpecialCharacters(keys);
StringBuilder sb = new StringBuilder();
Expand All @@ -107,7 +105,8 @@ public static string TranslateKey(string keys)
bool ctrDown = false;
bool winDown = false;

Action<char> modifyKey = (key) => {
Action<char> modifyKey = (key) =>
{
if (key == ALT)
{
altDown = !altDown;
Expand All @@ -126,9 +125,9 @@ public static string TranslateKey(string keys)
else if (key == WIN)
{
winDown = !winDown;
sb.Append(winDown? "{WIN DOWN}" : "WIN UP");
sb.Append(winDown ? "{WIN DOWN}" : "WIN UP");
}
};
};
foreach (var key in keys)
{
if (key == NULL)
Expand All @@ -152,9 +151,8 @@ public static string TranslateKey(string keys)
sb.Append(key);
}
}

return sb.ToString();
}
}


}
}
11 changes: 0 additions & 11 deletions src/Infra/Helper/PointerInputHelpers.cs

This file was deleted.

Loading

0 comments on commit 4008ec8

Please sign in to comment.