Browse Source

Fix multitouch and add historical points support

pull/9278/head
Max Katz 3 years ago
parent
commit
5f5d596b1c
  1. 1
      src/Web/Avalonia.Web/Avalonia.Web.csproj
  2. 113
      src/Web/Avalonia.Web/AvaloniaView.cs
  3. 26
      src/Web/Avalonia.Web/BrowserTopLevelImpl.cs
  4. 4
      src/Web/Avalonia.Web/Interop/InputHelper.cs
  5. 4
      src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts

1
src/Web/Avalonia.Web/Avalonia.Web.csproj

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Remove="@(SupportedPlatform)" />
<SupportedPlatform Include="browser" />
</ItemGroup>

113
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<RawPointerPoint> 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<IReadOnlyList<RawPointerPoint>?>(() =>
{
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;

26
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<IReadOnlyList<RawPointerPoint>?>? 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);

4
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<JSType.Function<JSType.String, JSType.Boolean>>]
Func<string, bool> input);
[JSImport("InputHelper.getCoalescedEvents", AvaloniaModule.MainModuleName)]
[return: JSMarshalAs<JSType.Array<JSType.Object>>]
public static partial JSObject[] GetCoalescedEvents(JSObject pointerEvent);
[JSImport("InputHelper.clearInput", AvaloniaModule.MainModuleName)]
public static partial void ClearInputElement(JSObject htmlElement);

4
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 = "";
}

Loading…
Cancel
Save