diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index b135fae1c..564967919 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,13 +3,13 @@ "isRoot": true, "tools": { "uno.check": { - "version": "1.3.1", + "version": "1.10.0", "commands": [ "uno-check" ] }, "xamlstyler.console": { - "version": "3.2008.4", + "version": "3.2206.4", "commands": [ "xstyler" ] diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a8ffd349..cbfc4c374 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,14 +25,14 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Needed until XAML Styler updates to .NET 6 - - name: Install .NET Core 3.1 SDK - uses: actions/setup-dotnet@v1 + - name: Install .NET 6 SDK + uses: actions/setup-dotnet@v3 with: - dotnet-version: '3.1.x' + dotnet-version: '6.0.x' # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Restore Tools from Manifest list in the Repository - name: Restore dotnet tools @@ -49,13 +49,13 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: Install .NET 6 SDK - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.202' + dotnet-version: '6.0.x' # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Restore Tools from Manifest list in the Repository - name: Restore dotnet tools @@ -123,13 +123,13 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - name: Install .NET 6 SDK - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.202' + dotnet-version: '6.0.x' # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Restore Tools from Manifest list in the Repository - name: Restore dotnet tools @@ -200,13 +200,13 @@ jobs: steps: - name: Install .NET 6 SDK - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.202' + dotnet-version: '6.0.x' # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Add msbuild to PATH uses: microsoft/setup-msbuild@v1.0.3 @@ -255,13 +255,13 @@ jobs: steps: - name: Install .NET 6 SDK - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.201' + dotnet-version: '6.0.x' # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Generate solution shell: pwsh diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests.csproj b/common/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests.csproj index ff9b195ac..891006984 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests.csproj +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests/CommunityToolkit.Labs.Core.SourceGenerators.LabsUITestMethod.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests.csproj b/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests.csproj index 4b5907449..2a1967ee9 100644 --- a/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests.csproj +++ b/common/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests/CommunityToolkit.Labs.Core.SourceGenerators.Tests.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/common/CommunityToolkit.Labs.Tests.Shared/App.xaml.cs b/common/CommunityToolkit.Labs.Tests.Shared/App.xaml.cs index 1b12ef5c4..001deddb9 100644 --- a/common/CommunityToolkit.Labs.Tests.Shared/App.xaml.cs +++ b/common/CommunityToolkit.Labs.Tests.Shared/App.xaml.cs @@ -17,6 +17,7 @@ using Windows.UI.Xaml.Navigation; #else using Microsoft.UI.Dispatching; +using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; @@ -25,6 +26,7 @@ using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Navigation; using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; +using System.Runtime.InteropServices; #endif namespace CommunityToolkit.Labs.Tests; @@ -37,16 +39,16 @@ public sealed partial class App : Application // MacOS and iOS don't know the correct type without a full namespace declaration, confusing it with NSWindow and UIWindow. // Using static will not work. #if WINAPPSDK - private static Microsoft.UI.Xaml.Window currentWindow = Microsoft.UI.Xaml.Window.Current; + public static Microsoft.UI.Xaml.Window CurrentWindow = Microsoft.UI.Xaml.Window.Current; #else - private static Windows.UI.Xaml.Window currentWindow = Windows.UI.Xaml.Window.Current; + public static Windows.UI.Xaml.Window CurrentWindow = Windows.UI.Xaml.Window.Current; #endif // Holder for test content to abstract Window.Current.Content public static FrameworkElement? ContentRoot { - get => currentWindow.Content as FrameworkElement; - set => currentWindow.Content = value; + get => CurrentWindow.Content as FrameworkElement; + set => CurrentWindow.Content = value; } // Abstract CoreApplication.MainView.DispatcherQueue @@ -57,7 +59,7 @@ public static DispatcherQueue DispatcherQueue #if !WINAPPSDK return CoreApplication.MainView.DispatcherQueue; #else - return currentWindow.DispatcherQueue; + return CurrentWindow.DispatcherQueue; #endif } } @@ -79,15 +81,15 @@ public App() protected override void OnLaunched(LaunchActivatedEventArgs e) { #if WINAPPSDK - currentWindow = new Window(); + CurrentWindow = new Window(); #endif // Do not repeat app initialization when the Window already has content, // just ensure that the window is active - if (currentWindow.Content is not Frame rootFrame) + if (CurrentWindow.Content is not Frame rootFrame) { // Create a Frame to act as the navigation context and navigate to the first page - currentWindow.Content = rootFrame = new Frame(); + CurrentWindow.Content = rootFrame = new Frame(); rootFrame.NavigationFailed += OnNavigationFailed; } @@ -95,7 +97,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e) ////Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI(); // Ensure the current window is active - currentWindow.Activate(); + CurrentWindow.Activate(); #if !WINAPPSDK Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(e.Arguments); diff --git a/common/CommunityToolkit.Labs.Tests.Shared/CommunityToolkit.Labs.Tests.Shared.projitems b/common/CommunityToolkit.Labs.Tests.Shared/CommunityToolkit.Labs.Tests.Shared.projitems index 9dad91eb3..211be684f 100644 --- a/common/CommunityToolkit.Labs.Tests.Shared/CommunityToolkit.Labs.Tests.Shared.projitems +++ b/common/CommunityToolkit.Labs.Tests.Shared/CommunityToolkit.Labs.Tests.Shared.projitems @@ -18,7 +18,14 @@ App.xaml + + + + + + + \ No newline at end of file diff --git a/common/CommunityToolkit.Labs.Tests.Shared/Input/InputHelpers.cs b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputHelpers.cs new file mode 100644 index 000000000..5917fbc47 --- /dev/null +++ b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputHelpers.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#if WINAPPSDK +using MainWindow = Microsoft.UI.Xaml.Window; +#else +using MainWindow = Windows.UI.Xaml.Window; +#endif + +namespace CommunityToolkit.Labs.Tests; + +public static class InputHelpers +{ + /// + /// Helper extension method to create a new chain for the current window. + /// + /// class for your application. + /// A new instance for that window. + public static InputSimulator InjectInput(this MainWindow window) + { + return new InputSimulator(window); + } + + public static Point CoordinatesToCenter(this UIElement parent, UIElement target) + { + var location = target.TransformToVisual(parent).TransformPoint(default(Point)); + return new(location.X + target.ActualSize.X / 2, location.Y + target.ActualSize.Y / 2); + } +} diff --git a/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.Bounds.cs b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.Bounds.cs new file mode 100644 index 000000000..06bfae09c --- /dev/null +++ b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.Bounds.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#if WINAPPSDK +using Windows.Win32; +using Windows.Win32.Foundation; +using Win32Rect = Windows.Win32.Foundation.RECT; +using Win32Point = System.Drawing.Point; +#endif + +namespace CommunityToolkit.Labs.Tests; + +//// This polyfill is needed as the WindowsAppSDK doesn't provide client based coordinates. See Issue: TODO: File bug currentWindow.Bounds should be the same between the two platforms. Should AppWindow also have Bounds? + +public partial class InputSimulator +{ +#if WINAPPSDK + private Rect Bounds + { + get + { + if (_currentWindowRef.TryGetTarget(out var currentWindow)) + { + var hWnd = (HWND)WinRT.Interop.WindowNative.GetWindowHandle(currentWindow); + + // Get client area position + Win32Point[] points = new Win32Point[1]; + PInvoke.MapWindowPoints(hWnd, HWND.Null, points); + + // TODO: Check LastError? + + // And size + if (points.Length == 1 && PInvoke.GetClientRect(hWnd, out Win32Rect size)) + { + return new Rect(points[0].X, points[0].Y, size.right - size.left, size.bottom - size.top); + } + } + + return default; + } + } +#else + private Rect Bounds => _currentWindowRef.TryGetTarget(out Window window) ? window.Bounds : default; +#endif + + private Point TranslatePointForWindow(Point point) + { + // 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...? + + // Get the top left screen coordinates of the app window rect. + var bounds = Bounds; // Don't double-retrieve the calculated property, TODO: Just make some point helpers (or use ones in Toolkit) + Point appBoundsTopLeft = new Point(bounds.Left, bounds.Top); + + // Create the point for input injection and calculate its screen location. + return new Point( + appBoundsTopLeft.X + point.X, + appBoundsTopLeft.Y + point.Y); + + } +} diff --git a/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.Touch.cs b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.Touch.cs new file mode 100644 index 000000000..27c0cf560 --- /dev/null +++ b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.Touch.cs @@ -0,0 +1,131 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Windows.UI.Input.Preview.Injection; + +namespace CommunityToolkit.Labs.Tests; + +public partial class InputSimulator +{ + public void StartTouch() + { + Assert.IsNotNull(_input); + + _input.InitializeTouchInjection( + InjectedInputVisualizationMode.Default); + } + + /// + /// Simulates a touch press on screen at the coordinates provided, in app-local coordinates. For instance use App.ContentRoot.CoordinatesTo(element). + /// + /// + /// + public uint TouchDown(Point point) + { + // Create a unique pointer ID for the injected touch pointer. + // Multiple input pointers would require more robust handling. + uint pointerId = _currentPointerId++; + + var injectionPoint = TranslatePointForWindow(point); + + // Create a touch data point for pointer down. + // Each element in the touch data list represents a single touch contact. + // For this example, we're mirroring a single mouse pointer. + List touchData = new() + { + new() + { + Contact = new InjectedInputRectangle + { + Left = 30, Top = 30, Bottom = 30, Right = 30 + }, + PointerInfo = new InjectedInputPointerInfo + { + PointerId = pointerId, + PointerOptions = + InjectedInputPointerOptions.PointerDown | + InjectedInputPointerOptions.InContact | + InjectedInputPointerOptions.New, + TimeOffsetInMilliseconds = 0, + PixelLocation = new InjectedInputPoint + { + PositionX = (int)injectionPoint.X , + PositionY = (int)injectionPoint.Y + } + }, + Pressure = 1.0, + TouchParameters = + InjectedInputTouchParameters.Pressure | + InjectedInputTouchParameters.Contact + } + }; + + // Inject the touch input. + _input.InjectTouchInput(touchData); + + return pointerId; + } + + public void TouchMove(uint pointerId, int cX, int cY) + { + // Create a touch data point for pointer up. + List touchData = new() + { + new() + { + Contact = new InjectedInputRectangle + { + Left = 30, Top = 30, Bottom = 30, Right = 30 + }, + PointerInfo = new InjectedInputPointerInfo + { + PointerId = pointerId, + PointerOptions = + InjectedInputPointerOptions.InRange | + InjectedInputPointerOptions.InContact, + TimeOffsetInMilliseconds = 0, + PixelLocation = new InjectedInputPoint + { + PositionX = (int)cX , + PositionY = (int)cY + } + }, + Pressure = 1.0, + TouchParameters = + InjectedInputTouchParameters.Pressure | + InjectedInputTouchParameters.Contact + } + }; + + // Inject the touch input. + _input.InjectTouchInput(touchData); + } + + public void TouchUp(uint pointerId) + { + Assert.IsNotNull(_input); + + // Create a touch data point for pointer up. + List touchData = new() + { + new() + { + PointerInfo = new InjectedInputPointerInfo + { + PointerId = pointerId, + PointerOptions = InjectedInputPointerOptions.PointerUp + } + } + }; + + // Inject the touch input. + _input.InjectTouchInput(touchData); + } + + public void StopTouch() + { + // Shut down the virtual input device. + _input.UninitializeTouchInjection(); + } +} diff --git a/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.cs b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.cs new file mode 100644 index 000000000..3ee24176a --- /dev/null +++ b/common/CommunityToolkit.Labs.Tests.Shared/Input/InputSimulator.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Windows.UI.Input.Preview.Injection; + +#if WINAPPSDK +using MainWindow = Microsoft.UI.Xaml.Window; +#else +using MainWindow = Windows.UI.Xaml.Window; +#endif + +namespace CommunityToolkit.Labs.Tests; + +public partial class InputSimulator +{ + private static InputInjector _input = InputInjector.TryCreate(); + private static uint _currentPointerId = 0; + + private WeakReference _currentWindowRef; + + /// + /// Create a new helper class for the current window. All positions provided to this API will use the client space of the provided window's top-left as an origin point. + /// + /// Window to simulate input on, used as a reference for client-space coordinates. + public InputSimulator(MainWindow currentWindow) + { + _currentWindowRef = new(currentWindow); + } +} diff --git a/common/CommunityToolkit.Labs.Tests.Shared/NativeMethods.txt b/common/CommunityToolkit.Labs.Tests.Shared/NativeMethods.txt new file mode 100644 index 000000000..cb43ad5ec --- /dev/null +++ b/common/CommunityToolkit.Labs.Tests.Shared/NativeMethods.txt @@ -0,0 +1,2 @@ +GetClientRect +MapWindowPoints diff --git a/common/Labs.Head.WinAppSdk.props b/common/Labs.Head.WinAppSdk.props index ddd2885d1..e6ec2707f 100644 --- a/common/Labs.Head.WinAppSdk.props +++ b/common/Labs.Head.WinAppSdk.props @@ -18,8 +18,8 @@ - - + + diff --git a/common/Labs.MultiTarget.props b/common/Labs.MultiTarget.props index 841cd5b20..8133f088c 100644 --- a/common/Labs.MultiTarget.props +++ b/common/Labs.MultiTarget.props @@ -31,7 +31,7 @@ - + diff --git a/global.json b/global.json index 462e64e31..0983b61c3 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,10 @@ { - "msbuild-sdks": - { - "MSBuild.Sdk.Extras":"3.0.23" - } -} \ No newline at end of file + "sdk": { + "version": "6.0.403", + "rollForward": "latestFeature" + }, + "msbuild-sdks": + { + "MSBuild.Sdk.Extras":"3.0.23" + } +} diff --git a/labs/SizerBase/src/SizerBase.xaml b/labs/SizerBase/src/SizerBase.xaml index 58f991fc3..440a35f95 100644 --- a/labs/SizerBase/src/SizerBase.xaml +++ b/labs/SizerBase/src/SizerBase.xaml @@ -32,7 +32,11 @@ -