diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs index 610a882e1f35..3e534e0d3777 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs @@ -11,7 +11,7 @@ namespace Uno.UI.Runtime.Skia { - public class GtkHost + public class GtkHost : ISkiaHost { private readonly string[] _args; private Func _appBuilder; @@ -20,6 +20,13 @@ public class GtkHost public static Gtk.Window Window => _window; + static GtkHost() + { + ApiExtensibility.Register(typeof(Windows.UI.Core.ICoreWindowExtension), o => new GtkUIElementPointersSupport(o)); + ApiExtensibility.Register(typeof(Windows.UI.ViewManagement.IApplicationViewExtension), o => new GtkApplicationViewExtension(o)); + ApiExtensibility.Register(typeof(IApplicationExtension), o => new GtkApplicationExtension(o)); + } + public GtkHost(Func appBuilder, string[] args) { _args = args; @@ -30,10 +37,6 @@ public void Run() { Gtk.Application.Init(); - ApiExtensibility.Register(typeof(Windows.UI.Core.ICoreWindowExtension), o => new GtkUIElementPointersSupport(o)); - ApiExtensibility.Register(typeof(Windows.UI.ViewManagement.IApplicationViewExtension), o => new GtkApplicationViewExtension(o)); - ApiExtensibility.Register(typeof(IApplicationExtension), o => new GtkApplicationExtension(o)); - _window = new Gtk.Window("Uno Host"); _window.SetDefaultSize(1024, 800); _window.SetPosition(Gtk.WindowPosition.Center); @@ -92,7 +95,13 @@ public void Run() _window.ShowAll(); - WUX.Application.Start(_ => _appBuilder(), _args); + void CreateApp(ApplicationInitializationCallbackParams _) + { + var app = _appBuilder(); + app.Host = this; + } + + WUX.Application.Start(CreateApp, _args); Gtk.Application.Run(); } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs index 942b6e3641ca..dc8a0200d879 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs @@ -10,23 +10,35 @@ namespace Uno.UI.Skia.Platform { - public class WpfHost : FrameworkElement + public class WpfHost : FrameworkElement, WinUI.ISkiaHost { private readonly bool designMode; - private readonly Func _appBuilder; private WriteableBitmap bitmap; private bool ignorePixelScaling; - public WpfHost(Func appBuilder) + static WpfHost() { ApiExtensibility.Register(typeof(Windows.UI.Core.ICoreWindowExtension), o => new WpfUIElementPointersSupport(o)); ApiExtensibility.Register(typeof(Windows.UI.ViewManagement.IApplicationViewExtension), o => new WpfApplicationViewExtension(o)); ApiExtensibility.Register(typeof(WinUI.IApplicationExtension), o => new WpfApplicationExtension(o)); + } + + [ThreadStatic] private static WpfHost _current; + public static WpfHost Current => _current; + + public WpfHost(Func appBuilder) + { + _current = this; designMode = DesignerProperties.GetIsInDesignMode(this); - _appBuilder = appBuilder; - WinUI.Application.Start(_ => appBuilder()); + void CreateApp(WinUI.ApplicationInitializationCallbackParams _) + { + var app = appBuilder(); + app.Host = this; + } + + WinUI.Application.Start(CreateApp); WinUI.Window.Current.InvalidateRender += () => InvalidateVisual(); diff --git a/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfUIElementPointersSupport.cs b/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfUIElementPointersSupport.cs index 3f89b651ed58..0ad7af40c57e 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfUIElementPointersSupport.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfUIElementPointersSupport.cs @@ -1,5 +1,15 @@ using System; +using Windows.Devices.Input; using Windows.UI.Core; +using Uno.Extensions; +using Uno.Logging; +using MouseEventArgs = System.Windows.Input.MouseEventArgs; +using WpfApplication = System.Windows.Application; +using WpfWindow = System.Windows.Window; +using System.Threading; +using System.Windows.Input; +using Windows.UI.Input; +using MouseDevice = System.Windows.Input.MouseDevice; namespace Uno.UI.Skia.Platform { @@ -7,11 +17,218 @@ public class WpfUIElementPointersSupport : ICoreWindowExtension { private CoreWindow _owner; private ICoreWindowEvents _ownerEvents; + private WpfWindow _mainWpfWindow; + private WpfHost _host; + + private static int _currentFrameId; public WpfUIElementPointersSupport(object owner) { _owner = (CoreWindow)owner; _ownerEvents = (ICoreWindowEvents)owner; + + _mainWpfWindow = WpfApplication.Current.MainWindow; + _host = WpfHost.Current; + + _host.MouseEnter += HostOnMouseEnter; + _host.MouseLeave += HostOnMouseLeave; + _host.MouseMove += HostOnMouseMove; + _host.MouseDown += HostOnMouseDown; + _host.MouseUp += HostOnMouseUp; + _host.MouseWheel += HostOnMouseWheel; + + } + + private static uint GetNextFrameId() => (uint)Interlocked.Increment(ref _currentFrameId); + + private static PointerPointProperties BuildPointerProperties(MouseEventArgs args, int wheelDelta = 0) + { + var properties = new PointerPointProperties + { + IsLeftButtonPressed = args.LeftButton == MouseButtonState.Pressed, + IsRightButtonPressed = args.RightButton == MouseButtonState.Pressed, + IsPrimary = true + }; + + if (wheelDelta != 0) + { + properties.MouseWheelDelta = -wheelDelta / 10; + } + + return properties; + } + + private static PointerDevice GetPointerDevice(MouseEventArgs args) + { + return args.Device switch + { + MouseDevice _ => PointerDevice.For(PointerDeviceType.Mouse), + StylusDevice _ => PointerDevice.For(PointerDeviceType.Pen), + TouchDevice _ => PointerDevice.For(PointerDeviceType.Touch), + _ => PointerDevice.For(PointerDeviceType.Mouse), + }; + } + + private void HostOnMouseEnter(object sender, MouseEventArgs args) + { + try + { + var position = args.GetPosition(_host); + + _ownerEvents.RaisePointerEntered( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: GetNextFrameId(), + timestamp: (uint)args.Timestamp, + device: GetPointerDevice(args), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(position.X, position.Y), + position: new Windows.Foundation.Point(position.X, position.Y), + isInContact: false, + properties: BuildPointerProperties(args) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerEntered", e); + } + } + + private void HostOnMouseLeave(object sender, MouseEventArgs args) + { + try + { + var position = args.GetPosition(_host); + + _ownerEvents.RaisePointerExited( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: GetNextFrameId(), + timestamp: (uint)args.Timestamp, + device: GetPointerDevice(args), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(position.X, position.Y), + position: new Windows.Foundation.Point(position.X, position.Y), + isInContact: false, + properties: BuildPointerProperties(args) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerExited", e); + } + } + + private void HostOnMouseMove(object sender, MouseEventArgs args) + { + try + { + var position = args.GetPosition(_host); + + _ownerEvents.RaisePointerMoved( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: GetNextFrameId(), + timestamp: (uint)args.Timestamp, + device: GetPointerDevice(args), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(position.X, position.Y), + position: new Windows.Foundation.Point(position.X, position.Y), + isInContact: false, + properties: BuildPointerProperties(args) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerMoved", e); + } + } + + private void HostOnMouseDown(object sender, MouseButtonEventArgs args) + { + try + { + var position = args.GetPosition(_host); + + _ownerEvents.RaisePointerPressed( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: GetNextFrameId(), + timestamp: (uint)args.Timestamp, + device: GetPointerDevice(args), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(position.X, position.Y), + position: new Windows.Foundation.Point(position.X, position.Y), + isInContact: false, + properties: BuildPointerProperties(args) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerPressed", e); + } + } + + private void HostOnMouseUp(object sender, MouseButtonEventArgs args) + { + try + { + var position = args.GetPosition(_host); + + _ownerEvents.RaisePointerReleased( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: GetNextFrameId(), + timestamp: (uint)args.Timestamp, + device: GetPointerDevice(args), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(position.X, position.Y), + position: new Windows.Foundation.Point(position.X, position.Y), + isInContact: false, + properties: BuildPointerProperties(args) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerReleased", e); + } + } + + private void HostOnMouseWheel(object sender, MouseWheelEventArgs args) + { + try + { + var position = args.GetPosition(_host); + + _ownerEvents.RaisePointerWheelChanged( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: GetNextFrameId(), + timestamp: (uint)args.Timestamp, + device: GetPointerDevice(args), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(position.X, position.Y), + position: new Windows.Foundation.Point(position.X, position.Y), + isInContact: false, + properties: BuildPointerProperties(args, args.Delta) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerWheelChanged", e); + } } } } diff --git a/src/Uno.UI/UI/Xaml/Application.Skia.cs b/src/Uno.UI/UI/Xaml/Application.Skia.cs index 961a7b9d0cca..596ede569b8b 100644 --- a/src/Uno.UI/UI/Xaml/Application.Skia.cs +++ b/src/Uno.UI/UI/Xaml/Application.Skia.cs @@ -21,6 +21,8 @@ public partial class Application : IApplicationEvents private static string[] _args; private readonly IApplicationExtension _coreWindowExtension; + internal ISkiaHost Host { get; set; } + public Application() { if (!ApiExtensibility.CreateInstance(this, out _coreWindowExtension)) @@ -77,6 +79,9 @@ internal interface IApplicationExtension internal interface IApplicationEvents { + } + internal interface ISkiaHost + { } } diff --git a/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs b/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs index 54577c26ca2d..f2387503a203 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs @@ -74,7 +74,7 @@ private void CoreWindow_PointerReleased(CoreWindow sender, PointerEventArgs args var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); if (UIElement.PointerCapture.TryGet(pointer, out var capture)) { - foreach(var target in capture.Targets) + foreach(var target in capture.Targets.ToArray()) { var pointerArgs = new PointerRoutedEventArgs(args, pointer, target.Element); target.Element.OnNativePointerUp(pointerArgs);