From 1eda1edc045016f079685657b4939b8291ab0d57 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 17 Oct 2018 20:53:09 +0100 Subject: [PATCH 1/2] implement previewer interactions for mouse and keyboard. --- .../Remote/Server/RemoteServerTopLevelImpl.cs | 142 +++++++++++++++++- src/Avalonia.DesignerSupport/Remote/Stubs.cs | 4 +- src/Avalonia.Remote.Protocol/InputMessages.cs | 6 + 3 files changed, 149 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index 1795f28f7f..0024644e7e 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -4,11 +4,15 @@ using System.Runtime.InteropServices; using Avalonia.Controls.Embedding.Offscreen; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Input; +using Avalonia.Input.Raw; using Avalonia.Layout; using Avalonia.Platform; using Avalonia.Remote.Protocol; +using Avalonia.Remote.Protocol.Input; using Avalonia.Remote.Protocol.Viewport; using Avalonia.Threading; +using InputModifiers = Avalonia.Input.InputModifiers; +using Key = Avalonia.Input.Key; using PixelFormat = Avalonia.Platform.PixelFormat; using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat; @@ -33,6 +37,65 @@ namespace Avalonia.Controls.Remote.Server _transport.OnMessage += OnMessage; } + private static RawMouseEventType GetAvaloniaEventType (Avalonia.Remote.Protocol.Input.MouseButton button, bool pressed) + { + switch (button) + { + case Avalonia.Remote.Protocol.Input.MouseButton.Left: + return pressed ? RawMouseEventType.LeftButtonDown : RawMouseEventType.LeftButtonUp; + + case Avalonia.Remote.Protocol.Input.MouseButton.Middle: + return pressed ? RawMouseEventType.MiddleButtonDown : RawMouseEventType.MiddleButtonUp; + + case Avalonia.Remote.Protocol.Input.MouseButton.Right: + return pressed ? RawMouseEventType.RightButtonDown : RawMouseEventType.RightButtonUp; + + default: + return RawMouseEventType.Move; + } + } + + private static InputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers) + { + var result = InputModifiers.None; + + foreach(var modifier in modifiers) + { + switch (modifier) + { + case Avalonia.Remote.Protocol.Input.InputModifiers.Control: + result |= InputModifiers.Control; + break; + + case Avalonia.Remote.Protocol.Input.InputModifiers.Alt: + result |= InputModifiers.Alt; + break; + + case Avalonia.Remote.Protocol.Input.InputModifiers.Shift: + result |= InputModifiers.Shift; + break; + + case Avalonia.Remote.Protocol.Input.InputModifiers.Windows: + result |= InputModifiers.Windows; + break; + + case Avalonia.Remote.Protocol.Input.InputModifiers.LeftMouseButton: + result |= InputModifiers.LeftMouseButton; + break; + + case Avalonia.Remote.Protocol.Input.InputModifiers.MiddleMouseButton: + result |= InputModifiers.MiddleMouseButton; + break; + + case Avalonia.Remote.Protocol.Input.InputModifiers.RightMouseButton: + result |= InputModifiers.RightMouseButton; + break; + } + } + + return result; + } + protected virtual void OnMessage(IAvaloniaRemoteTransportConnection transport, object obj) { lock (_lock) @@ -51,8 +114,9 @@ namespace Avalonia.Controls.Remote.Server { _dpi = new Vector(renderInfo.DpiX, renderInfo.DpiY); _invalidated = true; - RenderIfNeeded(); } + + Dispatcher.UIThread.Post(RenderIfNeeded); } if (obj is ClientSupportedPixelFormatsMessage supportedFormats) { @@ -91,6 +155,80 @@ namespace Avalonia.Controls.Remote.Server _pendingAllocation = allocated; } } + if(obj is PointerMovedEventMessage pointer) + { + Dispatcher.UIThread.Post(() => + { + Input?.Invoke(new RawMouseEventArgs( + MouseDevice, + 0, + InputRoot, + RawMouseEventType.Move, + new Point(pointer.X, pointer.Y), + GetAvaloniaInputModifiers(pointer.Modifiers))); + }, DispatcherPriority.Input); + } + if(obj is PointerPressedEventMessage pressed) + { + Dispatcher.UIThread.Post(() => + { + Input?.Invoke(new RawMouseEventArgs( + MouseDevice, + 0, + InputRoot, + GetAvaloniaEventType(pressed.Button, true), + new Point(pressed.X, pressed.Y), + GetAvaloniaInputModifiers(pressed.Modifiers))); + }, DispatcherPriority.Input); + } + if (obj is PointerPressedEventMessage released) + { + Dispatcher.UIThread.Post(() => + { + Input?.Invoke(new RawMouseEventArgs( + MouseDevice, + 0, + InputRoot, + GetAvaloniaEventType(released.Button, false), + new Point(released.X, released.Y), + GetAvaloniaInputModifiers(released.Modifiers))); + }, DispatcherPriority.Input); + } + if(obj is ScrollEventMessage scroll) + { + Dispatcher.UIThread.Post(() => + { + Input?.Invoke(new RawMouseWheelEventArgs( + MouseDevice, + 0, + InputRoot, + new Point(scroll.X, scroll.Y), + new Vector(scroll.DeltaX, scroll.DeltaY), + GetAvaloniaInputModifiers(scroll.Modifiers))); + }, DispatcherPriority.Input); + } + if(obj is KeyEventMessage key) + { + Dispatcher.UIThread.Post(() => + { + Input?.Invoke(new RawKeyEventArgs( + KeyboardDevice, + 0, + key.IsDown ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, + (Key)key.Key, + GetAvaloniaInputModifiers(key.Modifiers))); + }, DispatcherPriority.Input); + } + if(obj is TextInputEventMessage text) + { + Dispatcher.UIThread.Post(() => + { + Input?.Invoke(new RawTextInputEventArgs( + KeyboardDevice, + 0, + text.Text)); + }, DispatcherPriority.Input); + } } } @@ -184,5 +322,7 @@ namespace Avalonia.Controls.Remote.Server } public override IMouseDevice MouseDevice { get; } = new MouseDevice(); + + public IKeyboardDevice KeyboardDevice { get; } = new KeyboardDevice(); } } diff --git a/src/Avalonia.DesignerSupport/Remote/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs index 43f0e0a95e..3a97b0d799 100644 --- a/src/Avalonia.DesignerSupport/Remote/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Reactive.Disposables; @@ -20,7 +20,7 @@ namespace Avalonia.DesignerSupport.Remote public IPlatformHandle Handle { get; } public Size MaxClientSize { get; } public Size ClientSize { get; } - public double Scaling { get; } + public double Scaling { get; } = 1.0; public IEnumerable Surfaces { get; } public Action Input { get; set; } public Action Paint { get; set; } diff --git a/src/Avalonia.Remote.Protocol/InputMessages.cs b/src/Avalonia.Remote.Protocol/InputMessages.cs index e612eb3730..6b8cdebbcc 100644 --- a/src/Avalonia.Remote.Protocol/InputMessages.cs +++ b/src/Avalonia.Remote.Protocol/InputMessages.cs @@ -75,4 +75,10 @@ namespace Avalonia.Remote.Protocol.Input public Key Key { get; set; } } + [AvaloniaRemoteMessageGuid("C174102E-7405-4594-916F-B10B8248A17D")] + public class TextInputEventMessage : InputEventMessageBase + { + public string Text { get; set; } + } + } From bab421a8e026ece68cbd45ad00af88ab932c9794 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 17 Oct 2018 21:09:00 +0100 Subject: [PATCH 2/2] fix keyboard input --- .../Remote/Server/RemoteServerTopLevelImpl.cs | 8 +++++++- .../Remote/PreviewerWindowingPlatform.cs | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index 0024644e7e..257e3e9c2a 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -35,6 +35,8 @@ namespace Avalonia.Controls.Remote.Server { _transport = transport; _transport.OnMessage += OnMessage; + + KeyboardDevice = AvaloniaLocator.Current.GetService(); } private static RawMouseEventType GetAvaloniaEventType (Avalonia.Remote.Protocol.Input.MouseButton button, bool pressed) @@ -209,6 +211,8 @@ namespace Avalonia.Controls.Remote.Server } if(obj is KeyEventMessage key) { + Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); + Dispatcher.UIThread.Post(() => { Input?.Invoke(new RawKeyEventArgs( @@ -221,6 +225,8 @@ namespace Avalonia.Controls.Remote.Server } if(obj is TextInputEventMessage text) { + Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); + Dispatcher.UIThread.Post(() => { Input?.Invoke(new RawTextInputEventArgs( @@ -323,6 +329,6 @@ namespace Avalonia.Controls.Remote.Server public override IMouseDevice MouseDevice { get; } = new MouseDevice(); - public IKeyboardDevice KeyboardDevice { get; } = new KeyboardDevice(); + public IKeyboardDevice KeyboardDevice { get; } } } diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs index 20acc30118..3b6d071583 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs @@ -57,7 +57,8 @@ namespace Avalonia.DesignerSupport.Remote .Bind().ToConstant(threading) .Bind().ToSingleton() .Bind().ToConstant(instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToSingleton(); }