diff --git a/src/Web/Avalonia.Web/Avalonia.Web.csproj b/src/Web/Avalonia.Web/Avalonia.Web.csproj
index cdfa095865..88b23cdad2 100644
--- a/src/Web/Avalonia.Web/Avalonia.Web.csproj
+++ b/src/Web/Avalonia.Web/Avalonia.Web.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs
index bd08940306..37614399ee 100644
--- a/src/Web/Avalonia.Web/AvaloniaView.cs
+++ b/src/Web/Avalonia.Web/AvaloniaView.cs
@@ -1,5 +1,9 @@
using System;
+using System.Collections.Generic;
+using System.Reflection;
using System.Runtime.InteropServices.JavaScript;
+
+using Avalonia.Collections.Pooled;
using Avalonia.Controls;
using Avalonia.Controls.Embedding;
using Avalonia.Controls.Platform;
@@ -18,6 +22,7 @@ namespace Avalonia.Web
[System.Runtime.Versioning.SupportedOSPlatform("browser")] // gets rid of callsite warnings
public partial class AvaloniaView : ITextInputMethodImpl
{
+ private static readonly PooledList s_intermediatePointsPooledList = new(ClearMode.Never);
private readonly BrowserTopLevelImpl _topLevelImpl;
private EmbeddableControlRoot _topLevel;
@@ -162,94 +167,84 @@ namespace Avalonia.Web
private bool OnPointerMove(JSObject args)
{
var pointerType = args.GetPropertyAsString("pointerType");
+ var point = ExtractRawPointerFromJSArgs(args);
+ var type = pointerType switch
+ {
+ "touch" => RawPointerEventType.TouchUpdate,
+ _ => RawPointerEventType.Move
+ };
- if (pointerType == "touch")
+ var coalescedEvents = new Lazy?>(() =>
{
- var x = args.GetPropertyAsDouble("clientX");
- var y = args.GetPropertyAsDouble("clientY");
- long identifier = args.GetPropertyAsInt32("identifier");
+ var points = InputHelper.GetCoalescedEvents(args);
+ s_intermediatePointsPooledList.Clear();
+ s_intermediatePointsPooledList.Capacity = points.Length - 1;
- return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchUpdate, new Point(x, y),
- GetModifiers(args), identifier);
- }
+ // Skip the last one, as it is already processed point.
+ for (var i = 0; i < points.Length - 1; i++)
+ {
+ var point = points[i];
+ s_intermediatePointsPooledList.Add(ExtractRawPointerFromJSArgs(point));
+ }
- var point = ExtractRawPointerFromJSArgs(args);
-
- return _topLevelImpl.RawPointerEvent(RawPointerEventType.Move, pointerType!, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
+ return s_intermediatePointsPooledList;
+ });
+
+ return _topLevelImpl.RawPointerEvent(type, pointerType!, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"), coalescedEvents);
}
private bool OnPointerDown(JSObject args)
{
- var pointerType = args.GetPropertyAsString("pointerType");
-
- if (pointerType == "touch")
- {
- var x = args.GetPropertyAsDouble("clientX");
- var y = args.GetPropertyAsDouble("clientY");
- long identifier = args.GetPropertyAsInt32("identifier");
-
- return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchBegin, new Point(x, y),
- GetModifiers(args), identifier);
- }
-
- var type = args.GetPropertyAsInt32("button") switch
+ var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
+ var type = pointerType switch
{
- 0 => RawPointerEventType.LeftButtonDown,
- 1 => RawPointerEventType.MiddleButtonDown,
- 2 => RawPointerEventType.RightButtonDown,
- 3 => RawPointerEventType.XButton1Down,
- 4 => RawPointerEventType.XButton2Down,
- // 5 => Pen eraser button,
- _ => RawPointerEventType.Move
+ "touch" => RawPointerEventType.TouchBegin,
+ _ => args.GetPropertyAsInt32("button") switch
+ {
+ 0 => RawPointerEventType.LeftButtonDown,
+ 1 => RawPointerEventType.MiddleButtonDown,
+ 2 => RawPointerEventType.RightButtonDown,
+ 3 => RawPointerEventType.XButton1Down,
+ 4 => RawPointerEventType.XButton2Down,
+ 5 => RawPointerEventType.XButton1Down, // should be pen eraser button,
+ _ => RawPointerEventType.Move
+ }
};
var point = ExtractRawPointerFromJSArgs(args);
-
- return _topLevelImpl.RawPointerEvent(type, pointerType!, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
+ return _topLevelImpl.RawPointerEvent(type, pointerType, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
}
private bool OnPointerUp(JSObject args)
{
var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
-
- if (pointerType == "touch")
+ var type = pointerType switch
{
- var x = args.GetPropertyAsDouble("clientX");
- var y = args.GetPropertyAsDouble("clientY");
- long identifier = args.GetPropertyAsInt32("identifier");
-
- return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(x, y),
- GetModifiers(args), identifier);
- }
-
- var type = args.GetPropertyAsInt32("button") switch
- {
- 0 => RawPointerEventType.LeftButtonUp,
- 1 => RawPointerEventType.MiddleButtonUp,
- 2 => RawPointerEventType.RightButtonUp,
- 3 => RawPointerEventType.XButton1Up,
- 4 => RawPointerEventType.XButton2Up,
- // 5 => Pen eraser button,
- _ => RawPointerEventType.Move
+ "touch" => RawPointerEventType.TouchEnd,
+ _ => args.GetPropertyAsInt32("button") switch
+ {
+ 0 => RawPointerEventType.LeftButtonUp,
+ 1 => RawPointerEventType.MiddleButtonUp,
+ 2 => RawPointerEventType.RightButtonUp,
+ 3 => RawPointerEventType.XButton1Up,
+ 4 => RawPointerEventType.XButton2Up,
+ 5 => RawPointerEventType.XButton1Up, // should be pen eraser button,
+ _ => RawPointerEventType.Move
+ }
};
var point = ExtractRawPointerFromJSArgs(args);
-
return _topLevelImpl.RawPointerEvent(type, pointerType, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
}
private bool OnPointerCancel(JSObject args)
{
var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
-
if (pointerType == "touch")
{
- var x = args.GetPropertyAsDouble("clientX");
- var y = args.GetPropertyAsDouble("clientY");
- long identifier = args.GetPropertyAsInt32("identifier");
-
- return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchCancel, new Point(x, y),
- GetModifiers(args), identifier);
+ var point = ExtractRawPointerFromJSArgs(args);
+ _topLevelImpl.RawPointerEvent(RawPointerEventType.TouchCancel, pointerType, point,
+ GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
}
return false;
diff --git a/src/Web/Avalonia.Web/BrowserTopLevelImpl.cs b/src/Web/Avalonia.Web/BrowserTopLevelImpl.cs
index 3c42deffd8..ed8f417870 100644
--- a/src/Web/Avalonia.Web/BrowserTopLevelImpl.cs
+++ b/src/Web/Avalonia.Web/BrowserTopLevelImpl.cs
@@ -64,35 +64,25 @@ namespace Avalonia.Web
Resized?.Invoke(newSize, PlatformResizeReason.User);
}
}
-
- public bool RawTouchEvent(RawPointerEventType type, Point p, RawInputModifiers modifiers, long touchPointId)
- {
- if (_inputRoot is { } && Input is { } input)
- {
- var args = new RawTouchEventArgs(_touchDevice, Timestamp, _inputRoot, type, p, modifiers,
- touchPointId);
-
- input.Invoke(args);
-
- return args.Handled;
- }
-
- return false;
- }
public bool RawPointerEvent(
RawPointerEventType eventType, string pointerType,
- RawPointerPoint p, RawInputModifiers modifiers, long touchPointId)
+ RawPointerPoint p, RawInputModifiers modifiers, long touchPointId,
+ Lazy?>? intermediatePoints = null)
{
if (_inputRoot is { }
&& Input is { } input)
{
var device = GetPointerDevice(pointerType);
var args = device is TouchDevice ?
- new RawTouchEventArgs(device, Timestamp, _inputRoot, eventType, p, modifiers, touchPointId) :
+ new RawTouchEventArgs(device, Timestamp, _inputRoot, eventType, p, modifiers, touchPointId)
+ {
+ IntermediatePoints = intermediatePoints
+ } :
new RawPointerEventArgs(device, Timestamp, _inputRoot, eventType, p, modifiers)
{
- RawPointerId = touchPointId
+ RawPointerId = touchPointId,
+ IntermediatePoints = intermediatePoints
};
input.Invoke(args);
diff --git a/src/Web/Avalonia.Web/Interop/InputHelper.cs b/src/Web/Avalonia.Web/Interop/InputHelper.cs
index 0100701714..904fa915a8 100644
--- a/src/Web/Avalonia.Web/Interop/InputHelper.cs
+++ b/src/Web/Avalonia.Web/Interop/InputHelper.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.InteropServices;
using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks;
@@ -47,6 +48,9 @@ internal static partial class InputHelper
[JSMarshalAs>]
Func input);
+ [JSImport("InputHelper.getCoalescedEvents", AvaloniaModule.MainModuleName)]
+ [return: JSMarshalAs>]
+ public static partial JSObject[] GetCoalescedEvents(JSObject pointerEvent);
[JSImport("InputHelper.clearInput", AvaloniaModule.MainModuleName)]
public static partial void ClearInputElement(JSObject htmlElement);
diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts
index f5a6c6e806..83e8ee7f1c 100644
--- a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts
+++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts
@@ -154,6 +154,10 @@ export class InputHelper {
};
}
+ public static getCoalescedEvents(pointerEvent: PointerEvent): PointerEvent[] {
+ return pointerEvent.getCoalescedEvents();
+ }
+
public static clearInput(inputElement: HTMLInputElement) {
inputElement.value = "";
}