Browse Source

Fix multitouch and add historical points support

pull/9278/head
Max Katz 4 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> </PropertyGroup>
<ItemGroup> <ItemGroup>
<SupportedPlatform Remove="@(SupportedPlatform)" />
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser" />
</ItemGroup> </ItemGroup>

113
src/Web/Avalonia.Web/AvaloniaView.cs

@ -1,5 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices.JavaScript; using System.Runtime.InteropServices.JavaScript;
using Avalonia.Collections.Pooled;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Embedding; using Avalonia.Controls.Embedding;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
@ -18,6 +22,7 @@ namespace Avalonia.Web
[System.Runtime.Versioning.SupportedOSPlatform("browser")] // gets rid of callsite warnings [System.Runtime.Versioning.SupportedOSPlatform("browser")] // gets rid of callsite warnings
public partial class AvaloniaView : ITextInputMethodImpl public partial class AvaloniaView : ITextInputMethodImpl
{ {
private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new(ClearMode.Never);
private readonly BrowserTopLevelImpl _topLevelImpl; private readonly BrowserTopLevelImpl _topLevelImpl;
private EmbeddableControlRoot _topLevel; private EmbeddableControlRoot _topLevel;
@ -162,94 +167,84 @@ namespace Avalonia.Web
private bool OnPointerMove(JSObject args) private bool OnPointerMove(JSObject args)
{ {
var pointerType = args.GetPropertyAsString("pointerType"); 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 points = InputHelper.GetCoalescedEvents(args);
var y = args.GetPropertyAsDouble("clientY"); s_intermediatePointsPooledList.Clear();
long identifier = args.GetPropertyAsInt32("identifier"); s_intermediatePointsPooledList.Capacity = points.Length - 1;
return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchUpdate, new Point(x, y), // Skip the last one, as it is already processed point.
GetModifiers(args), identifier); for (var i = 0; i < points.Length - 1; i++)
} {
var point = points[i];
s_intermediatePointsPooledList.Add(ExtractRawPointerFromJSArgs(point));
}
var point = ExtractRawPointerFromJSArgs(args); return s_intermediatePointsPooledList;
});
return _topLevelImpl.RawPointerEvent(RawPointerEventType.Move, pointerType!, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
return _topLevelImpl.RawPointerEvent(type, pointerType!, point, GetModifiers(args), args.GetPropertyAsInt32("pointerId"), coalescedEvents);
} }
private bool OnPointerDown(JSObject args) private bool OnPointerDown(JSObject args)
{ {
var pointerType = args.GetPropertyAsString("pointerType"); var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
var type = pointerType switch
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
{ {
0 => RawPointerEventType.LeftButtonDown, "touch" => RawPointerEventType.TouchBegin,
1 => RawPointerEventType.MiddleButtonDown, _ => args.GetPropertyAsInt32("button") switch
2 => RawPointerEventType.RightButtonDown, {
3 => RawPointerEventType.XButton1Down, 0 => RawPointerEventType.LeftButtonDown,
4 => RawPointerEventType.XButton2Down, 1 => RawPointerEventType.MiddleButtonDown,
// 5 => Pen eraser button, 2 => RawPointerEventType.RightButtonDown,
_ => RawPointerEventType.Move 3 => RawPointerEventType.XButton1Down,
4 => RawPointerEventType.XButton2Down,
5 => RawPointerEventType.XButton1Down, // should be pen eraser button,
_ => RawPointerEventType.Move
}
}; };
var point = ExtractRawPointerFromJSArgs(args); 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) private bool OnPointerUp(JSObject args)
{ {
var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse"; var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
var type = pointerType switch
if (pointerType == "touch")
{ {
var x = args.GetPropertyAsDouble("clientX"); "touch" => RawPointerEventType.TouchEnd,
var y = args.GetPropertyAsDouble("clientY"); _ => args.GetPropertyAsInt32("button") switch
long identifier = args.GetPropertyAsInt32("identifier"); {
0 => RawPointerEventType.LeftButtonUp,
return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(x, y), 1 => RawPointerEventType.MiddleButtonUp,
GetModifiers(args), identifier); 2 => RawPointerEventType.RightButtonUp,
} 3 => RawPointerEventType.XButton1Up,
4 => RawPointerEventType.XButton2Up,
var type = args.GetPropertyAsInt32("button") switch 5 => RawPointerEventType.XButton1Up, // should be pen eraser button,
{ _ => RawPointerEventType.Move
0 => RawPointerEventType.LeftButtonUp, }
1 => RawPointerEventType.MiddleButtonUp,
2 => RawPointerEventType.RightButtonUp,
3 => RawPointerEventType.XButton1Up,
4 => RawPointerEventType.XButton2Up,
// 5 => Pen eraser button,
_ => RawPointerEventType.Move
}; };
var point = ExtractRawPointerFromJSArgs(args); 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 OnPointerCancel(JSObject args) private bool OnPointerCancel(JSObject args)
{ {
var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse"; var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
if (pointerType == "touch") if (pointerType == "touch")
{ {
var x = args.GetPropertyAsDouble("clientX"); var point = ExtractRawPointerFromJSArgs(args);
var y = args.GetPropertyAsDouble("clientY"); _topLevelImpl.RawPointerEvent(RawPointerEventType.TouchCancel, pointerType, point,
long identifier = args.GetPropertyAsInt32("identifier"); GetModifiers(args), args.GetPropertyAsInt32("pointerId"));
return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchCancel, new Point(x, y),
GetModifiers(args), identifier);
} }
return false; return false;

26
src/Web/Avalonia.Web/BrowserTopLevelImpl.cs

@ -64,35 +64,25 @@ namespace Avalonia.Web
Resized?.Invoke(newSize, PlatformResizeReason.User); 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( public bool RawPointerEvent(
RawPointerEventType eventType, string pointerType, RawPointerEventType eventType, string pointerType,
RawPointerPoint p, RawInputModifiers modifiers, long touchPointId) RawPointerPoint p, RawInputModifiers modifiers, long touchPointId,
Lazy<IReadOnlyList<RawPointerPoint>?>? intermediatePoints = null)
{ {
if (_inputRoot is { } if (_inputRoot is { }
&& Input is { } input) && Input is { } input)
{ {
var device = GetPointerDevice(pointerType); var device = GetPointerDevice(pointerType);
var args = device is TouchDevice ? 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) new RawPointerEventArgs(device, Timestamp, _inputRoot, eventType, p, modifiers)
{ {
RawPointerId = touchPointId RawPointerId = touchPointId,
IntermediatePoints = intermediatePoints
}; };
input.Invoke(args); input.Invoke(args);

4
src/Web/Avalonia.Web/Interop/InputHelper.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.JavaScript; using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -47,6 +48,9 @@ internal static partial class InputHelper
[JSMarshalAs<JSType.Function<JSType.String, JSType.Boolean>>] [JSMarshalAs<JSType.Function<JSType.String, JSType.Boolean>>]
Func<string, bool> input); 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)] [JSImport("InputHelper.clearInput", AvaloniaModule.MainModuleName)]
public static partial void ClearInputElement(JSObject htmlElement); 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) { public static clearInput(inputElement: HTMLInputElement) {
inputElement.value = ""; inputElement.value = "";
} }

Loading…
Cancel
Save