瀏覽代碼

Added high precision input handling

Krzysztof Krysiński 1 月之前
父節點
當前提交
c8065ca839

+ 19 - 10
src/PixiEditor/Models/Controllers/InputDevice/MouseInputFilter.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
 using Avalonia.Input;
 using Drawie.Backend.Core.Numerics;
 using Drawie.Numerics;
@@ -16,12 +17,11 @@ internal class MouseInputFilter
 
     private Dictionary<MouseButton, bool> buttonStates = new()
     {
-        [MouseButton.Left] = false,
-        [MouseButton.Right] = false,
-        [MouseButton.Middle] = false,
+        [MouseButton.Left] = false, [MouseButton.Right] = false, [MouseButton.Middle] = false,
     };
 
     public void MouseDownInlet(object args) => MouseDownInlet((MouseOnCanvasEventArgs)args);
+
     public void MouseDownInlet(MouseOnCanvasEventArgs args)
     {
         var button = args.Button;
@@ -35,9 +35,15 @@ internal class MouseInputFilter
         OnMouseDown?.Invoke(this, args);
     }
 
-    public void MouseMoveInlet(object args) => OnMouseMove?.Invoke(this, ((MouseOnCanvasEventArgs)args));
+    public void MouseMoveInlet(object args)
+    {
+        MouseOnCanvasEventArgs argsTyped = (MouseOnCanvasEventArgs)args;
+        OnMouseMove?.Invoke(this, argsTyped);
+    }
+
     public void MouseUpInlet(object args) => MouseUpInlet(((MouseOnCanvasEventArgs)args));
     public void MouseUpInlet(object? sender, Point p, MouseButton button) => MouseUpInlet(button);
+
     public void MouseUpInlet(MouseOnCanvasEventArgs args)
     {
         if (args.Button is MouseButton.XButton1 or MouseButton.XButton2 or MouseButton.None)
@@ -53,13 +59,16 @@ internal class MouseInputFilter
 
     public void DeactivatedInlet(object? sender, EventArgs e)
     {
-        MouseOnCanvasEventArgs argsLeft = new(MouseButton.Left, PointerType.Mouse, VecD.Zero, KeyModifiers.None, 0, PointerPointProperties.None, 1);
+        MouseOnCanvasEventArgs argsLeft = new(MouseButton.Left, PointerType.Mouse, VecD.Zero, KeyModifiers.None, 0,
+            PointerPointProperties.None, 1);
         MouseUpInlet(argsLeft);
-        
-        MouseOnCanvasEventArgs argsMiddle = new(MouseButton.Middle, PointerType.Mouse, VecD.Zero, KeyModifiers.None, 0, PointerPointProperties.None, 1);
+
+        MouseOnCanvasEventArgs argsMiddle = new(MouseButton.Middle, PointerType.Mouse, VecD.Zero, KeyModifiers.None, 0,
+            PointerPointProperties.None, 1);
         MouseUpInlet(argsMiddle);
-        
-        MouseOnCanvasEventArgs argsRight = new(MouseButton.Right, PointerType.Mouse, VecD.Zero, KeyModifiers.None, 0, PointerPointProperties.None, 1);
+
+        MouseOnCanvasEventArgs argsRight = new(MouseButton.Right, PointerType.Mouse, VecD.Zero, KeyModifiers.None, 0,
+            PointerPointProperties.None, 1);
         MouseUpInlet(argsRight);
     }
 }

+ 24 - 4
src/PixiEditor/Models/Controllers/InputDevice/MouseOnCanvasEventArgs.cs

@@ -9,22 +9,42 @@ internal class MouseOnCanvasEventArgs : EventArgs
 {
     public MouseButton Button { get; }
     public PointerType PointerType { get; }
-    public VecD PositionOnCanvas { get; }
     public KeyModifiers KeyModifiers { get; }
+    public PointerPosition Point { get; }
     public bool Handled { get; set; }
     public int ClickCount { get; set; } = 1;
-    public PointerPointProperties Properties { get; }
     public double ViewportScale { get; set; }
+    public IReadOnlyList<PointerPosition> IntermediatePoints { get; set; }
 
     public MouseOnCanvasEventArgs(MouseButton button, PointerType type, VecD positionOnCanvas, KeyModifiers keyModifiers, int clickCount,
         PointerPointProperties properties, double viewportScale)
     {
         Button = button;
-        PositionOnCanvas = positionOnCanvas;
+        Point = new PointerPosition(positionOnCanvas, properties);
         KeyModifiers = keyModifiers;
         ClickCount = clickCount;
-        Properties = properties;
         PointerType = type;
         ViewportScale = viewportScale;
     }
+
+    public static MouseOnCanvasEventArgs FromIntermediatePoint(MouseOnCanvasEventArgs args, PointerPosition point)
+    {
+        return new MouseOnCanvasEventArgs(args.Button, args.PointerType, point.PositionOnCanvas, args.KeyModifiers, args.ClickCount,
+            point.Properties, args.ViewportScale)
+        {
+            Handled = args.Handled,
+        };
+    }
+}
+
+struct PointerPosition
+{
+    public VecD PositionOnCanvas { get; set; }
+    public PointerPointProperties Properties { get; set; }
+
+    public PointerPosition(VecD positionOnCanvas, PointerPointProperties properties)
+    {
+        PositionOnCanvas = positionOnCanvas;
+        Properties = properties;
+    }
 }

+ 19 - 5
src/PixiEditor/Models/DocumentModels/ChangeExecutionController.cs

@@ -181,8 +181,22 @@ internal class ChangeExecutionController
 
     public void MouseMoveInlet(MouseOnCanvasEventArgs args)
     {
-        VecD newCanvasPos = args.PositionOnCanvas;
+        if (args.IntermediatePoints != null)
+        {
+            foreach (var point in args.IntermediatePoints)
+            {
+                MouseOnCanvasEventArgs arg = MouseOnCanvasEventArgs.FromIntermediatePoint(args, point);
+                MouseMoveInlet(arg);
+            }
+        }
+
+        VecD newCanvasPos = args.Point.PositionOnCanvas;
         //update internal state
+        ProcessMove(args, newCanvasPos);
+    }
+
+    private void ProcessMove(MouseOnCanvasEventArgs args, VecD newCanvasPos)
+    {
         VecI newPixelPos = (VecI)newCanvasPos.Floor();
         bool pixelPosChanged = false;
         if (lastPixelPos != newPixelPos)
@@ -367,13 +381,13 @@ internal class ChangeExecutionController
         VecD vecDir = new VecD(dir.X, dir.Y);
         VecD dirNormalized = vecDir.Length > 0 ? vecDir.Normalize() : lastPointerInfo.MovementDirection;
 
-        float pressure = args.Properties.Pressure;
+        float pressure = args.Point.Properties.Pressure;
         if (args.PointerType == PointerType.Mouse)
         {
-            pressure = args.Properties.Pressure > 0 ? 1 : 0;
+            pressure = args.Point.Properties.Pressure > 0 ? 1 : 0;
         }
 
-        return new PointerInfo(currentPoint, pressure, args.Properties.Twist,
-            new VecD(args.Properties.XTilt, args.Properties.YTilt), dirNormalized);
+        return new PointerInfo(currentPoint, pressure, args.Point.Properties.Twist,
+            new VecD(args.Point.Properties.XTilt, args.Point.Properties.YTilt), dirNormalized);
     }
 }

+ 2 - 1
src/PixiEditor/Models/DocumentModels/Public/DocumentEventsModule.cs

@@ -37,9 +37,10 @@ internal class DocumentEventsModule
     public void OnCanvasLeftMouseButtonDown(MouseOnCanvasEventArgs args) => Internals.ChangeController.LeftMouseButtonDownInlet(args);
     public void OnCanvasMouseMove(MouseOnCanvasEventArgs args)
     {
-        DocumentsHandler.CoordinatesString = $"X: {(int)args.PositionOnCanvas.X} Y: {(int)args.PositionOnCanvas.Y}";
+        DocumentsHandler.CoordinatesString = $"X: {(int)args.Point.PositionOnCanvas.X} Y: {(int)args.Point.PositionOnCanvas.Y}";
         Internals.ChangeController.MouseMoveInlet(args);
     }
+
     public void OnCanvasLeftMouseButtonUp(VecD argsPositionOnCanvas) => Internals.ChangeController.LeftMouseButtonUpInlet(argsPositionOnCanvas);
     public void OnOpacitySliderDragStarted() => Internals.ChangeController.OpacitySliderDragStartedInlet();
     public void OnOpacitySliderDragged(float newValue) => Internals.ChangeController.OpacitySliderDraggedInlet(newValue);

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/ColorPickerToolExecutor.cs

@@ -45,7 +45,7 @@ internal class ColorPickerToolExecutor : UpdateableChangeExecutor
         string? customOutput = windowHandler?.ActiveWindow is IViewport viewport ? viewport.RenderOutputName : null;
         customOutput = customOutput == "DEFAULT" ? null : customOutput;
 
-        colorsViewModel.PrimaryColor = document.PickColor(args.PositionOnCanvas, scope, includeReference, includeCanvas, document.AnimationHandler.ActiveFrameBindable, document.ReferenceLayerHandler.IsTopMost, customOutput);
+        colorsViewModel.PrimaryColor = document.PickColor(args.Point.PositionOnCanvas, scope, includeReference, includeCanvas, document.AnimationHandler.ActiveFrameBindable, document.ReferenceLayerHandler.IsTopMost, customOutput);
     }
 
     public override void OnPixelPositionChange(VecI pos, MouseOnCanvasEventArgs args)

+ 3 - 3
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/SimpleShapeToolExecutor.cs

@@ -137,15 +137,15 @@ internal abstract class SimpleShapeToolExecutor : UpdateableChangeExecutor,
     {
         if (ActiveMode == ShapeToolMode.Preview)
         {
-            PrecisePositionChangePreviewMode(args.PositionOnCanvas);
+            PrecisePositionChangePreviewMode(args.Point.PositionOnCanvas);
         }
         else if (ActiveMode == ShapeToolMode.Drawing)
         {
-            PrecisePositionChangeDrawingMode(args.PositionOnCanvas);
+            PrecisePositionChangeDrawingMode(args.Point.PositionOnCanvas);
         }
         else if (ActiveMode == ShapeToolMode.Transform)
         {
-            PrecisePositionChangeTransformMode(args.PositionOnCanvas);
+            PrecisePositionChangeTransformMode(args.Point.PositionOnCanvas);
         }
     }
 

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedExecutor.cs

@@ -166,7 +166,7 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
             }
         }
 
-        var topMostWithinClick = QueryLayers<IStructureMemberHandler>(args.PositionOnCanvas);
+        var topMostWithinClick = QueryLayers<IStructureMemberHandler>(args.Point.PositionOnCanvas);
 
         var orderedBySize = topMostWithinClick
             .Where(x => x.TightBounds is not null)

+ 1 - 1
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/VectorPathToolExecutor.cs

@@ -127,7 +127,7 @@ internal class VectorPathToolExecutor : UpdateableChangeExecutor, IPathExecutorF
         }
 
         VecD mouseSnap =
-            document.SnappingHandler.SnappingController.GetSnapPoint(args.PositionOnCanvas, out string snapXAxis,
+            document.SnappingHandler.SnappingController.GetSnapPoint(args.Point.PositionOnCanvas, out string snapXAxis,
                 out string snapYAxis);
         HighlightSnapping(snapXAxis, snapYAxis);
 

+ 5 - 5
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/VectorTextToolExecutor.cs

@@ -125,9 +125,9 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
 
     public override void OnLeftMouseButtonDown(MouseOnCanvasEventArgs args)
     {
-        var topMostWithinClick = QueryLayers<IVectorLayerHandler>(args.PositionOnCanvas);
+        var topMostWithinClick = QueryLayers<IVectorLayerHandler>(args.Point.PositionOnCanvas);
 
-        clickPos = args.PositionOnCanvas;
+        clickPos = args.Point.PositionOnCanvas;
         var firstLayer = topMostWithinClick.FirstOrDefault();
         args.Handled = firstLayer != null;
         if (firstLayer is not IVectorLayerHandler layerHandler || layerHandler.GetShapeData(document.AnimationHandler.ActiveFrameTime) is not TextVectorData)
@@ -152,7 +152,7 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
                         toolbar.Spacing);
                 }
 
-                document.TextOverlayHandler.SetCursorPosition(args.PositionOnCanvas);
+                document.TextOverlayHandler.SetCursorPosition(args.Point.PositionOnCanvas);
             }, false);
     }
 
@@ -160,10 +160,10 @@ internal class VectorTextToolExecutor : UpdateableChangeExecutor, ITextOverlayEv
     {
         if (document.TextOverlayHandler.IsActive && internals.ChangeController.LeftMousePressed && string.IsNullOrEmpty(lastText))
         {
-            double distance = Math.Abs(clickPos.Y - args.PositionOnCanvas.Y);
+            double distance = Math.Abs(clickPos.Y - args.Point.PositionOnCanvas.Y);
             if (!wasDrawingSize && distance < 10) return;
             wasDrawingSize = true;
-            position = new VecD(position.X, args.PositionOnCanvas.Y);
+            position = new VecD(position.X, args.Point.PositionOnCanvas.Y);
             document.TextOverlayHandler.Position = position;
             document.TextOverlayHandler.PreviewSize = true;
             var textData = ConstructTextData(lastText);

+ 29 - 5
src/PixiEditor/ViewModels/SubViewModels/IoViewModel.cs

@@ -22,6 +22,7 @@ using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors.Features;
 using PixiEditor.ViewModels.Document;
 using PixiEditor.ViewModels.Tools.Tools;
 using PixiEditor.Views;
+using SharpHook;
 
 namespace PixiEditor.ViewModels.SubViewModels;
 #nullable enable
@@ -52,8 +53,12 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         MouseWheelCommand = new RelayCommand<ScrollOnCanvasEventArgs>(mouseFilter.MouseWheelInlet);
         PreviewMouseMiddleButtonCommand = new RelayCommand(OnMiddleMouseButton);
         Owner.LayoutSubViewModel.LayoutManager.WindowFloated += OnLayoutManagerOnWindowFloated;
-        // TODO: Implement mouse capturing
-        //GlobalMouseHook.Instance.OnMouseUp += mouseFilter.MouseUpInlet;
+
+        //var hook = new EventLoopGlobalHook();
+
+        //hook.MouseMoved += (s, args) => mouseFilter.PumpMouseMove(args.Data.X, args.Data.Y);
+
+        //hook.RunAsync();
 
         mouseFilter.OnMouseDown += OnMouseDown;
         mouseFilter.OnMouseMove += OnMouseMove;
@@ -69,6 +74,25 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         Owner.AttachedToWindow += AttachWindowEvents;
     }
 
+    /*
+    private MouseOnCanvasEventArgs CreateMoveArgs(SharpHook.MouseHookEventArgs data)
+    {
+        MouseButton btn = data.Data.Button switch
+        {
+            SharpHook.Data.MouseButton.Button1 => MouseButton.Left,
+            SharpHook.Data.MouseButton.Button2 => MouseButton.Right,
+            SharpHook.Data.MouseButton.Button3 => MouseButton.Middle,
+            _ => MouseButton.None
+        };
+
+        return new MouseOnCanvasEventArgs(
+            btn,
+            PointerType.Mouse,
+            new VecD(data.Data.X, data.Data.Y),
+            KeyModifiers.None,
+            data.Data.Clicks, new PointerPointProperties(), 1);
+    }*/
+
     public void AttachWindowEvents(MainWindow mainWindow)
     {
         mainWindow.KeyDown += MainWindowKeyDown;
@@ -236,14 +260,14 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         activeDocument.EventInlet.OnCanvasLeftMouseButtonDown(args);
         if (args.Handled) return;
 
-        Owner.ToolsSubViewModel.UseToolEventInlet(args.PositionOnCanvas, args.Button);
+        Owner.ToolsSubViewModel.UseToolEventInlet(args.Point.PositionOnCanvas, args.Button);
 
         if (args.Button == MouseButton.Right)
         {
             HandleRightSwapColor();
         }
 
-        Analytics.SendUseTool(Owner.ToolsSubViewModel.ActiveTool, args.PositionOnCanvas, activeDocument.SizeBindable);
+        Analytics.SendUseTool(Owner.ToolsSubViewModel.ActiveTool, args.Point.PositionOnCanvas, activeDocument.SizeBindable);
     }
 
     private bool HandleRightMouseDown()
@@ -372,7 +396,7 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
         if (button == MouseButton.Left || rightCanUp)
         {
             Owner.DocumentManagerSubViewModel.ActiveDocument.EventInlet
-                .OnCanvasLeftMouseButtonUp(args.PositionOnCanvas);
+                .OnCanvasLeftMouseButtonUp(args.Point.PositionOnCanvas);
         }
 
         drawingWithRight = null;

+ 11 - 1
src/PixiEditor/Views/Main/ViewportControls/Viewport.axaml.cs

@@ -574,11 +574,21 @@ internal partial class Viewport : UserControl, INotifyPropertyChanged
             return;
         Point pos = e.GetPosition(Scene);
         VecD conv = Scene.ToZoomboxSpace(new VecD(pos.X, pos.Y));
-
         MouseButton mouseButton = e.GetMouseButton(this);
 
         MouseOnCanvasEventArgs parameter = new(mouseButton, e.Pointer.Type, conv, e.KeyModifiers, 0, e.GetCurrentPoint(this).Properties, Scene.Scale);
 
+        var intermediate = e.GetIntermediatePoints(this);
+        List<PointerPosition> intermediatePositions = new();
+        foreach (var point in intermediate)
+        {
+            Point interPos = point.Position;
+            VecD interConv = Scene.ToZoomboxSpace(new VecD(interPos.X, interPos.Y));
+            intermediatePositions.Add(new PointerPosition(interConv, point.Properties));
+        }
+
+        parameter.IntermediatePoints = intermediatePositions;
+
         if (MouseMoveCommand.CanExecute(parameter))
             MouseMoveCommand.Execute(parameter);
     }