Browse Source

implement touch via pointer events only.

pull/9278/head
Dan Walmsley 4 years ago
parent
commit
985e4cf2ab
  1. 108
      src/Web/Avalonia.Web/AvaloniaView.cs
  2. 11
      src/Web/Avalonia.Web/BrowserTopLevelImpl.cs
  3. 14
      src/Web/Avalonia.Web/Interop/InputHelper.cs
  4. 68
      src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts

108
src/Web/Avalonia.Web/AvaloniaView.cs

@ -52,13 +52,13 @@ namespace Avalonia.Web
}
_containerElement = hostContent.GetPropertyAsJSObject("host")
?? throw new InvalidOperationException("Host cannot be null");
?? throw new InvalidOperationException("Host cannot be null");
_canvas = hostContent.GetPropertyAsJSObject("canvas")
?? throw new InvalidOperationException("Canvas cannot be null");
?? throw new InvalidOperationException("Canvas cannot be null");
_nativeControlsContainer = hostContent.GetPropertyAsJSObject("nativeHost")
?? throw new InvalidOperationException("NativeHost cannot be null");
?? throw new InvalidOperationException("NativeHost cannot be null");
_inputElement = hostContent.GetPropertyAsJSObject("inputElement")
?? throw new InvalidOperationException("InputElement cannot be null");
?? throw new InvalidOperationException("InputElement cannot be null");
_splash = DomHelper.GetElementById("avalonia-splash");
@ -96,9 +96,8 @@ namespace Avalonia.Web
OnCompositionUpdate,
OnCompositionEnd);
InputHelper.SubscribePointerEvents(_containerElement, OnPointerMove, OnPointerDown, OnPointerUp, OnWheel);
InputHelper.SubscribeTouchEvents(_containerElement, OnTouchStart, OnTouchEnd, OnTouchCancel, OnTouchMove);
InputHelper.SubscribePointerEvents(_containerElement, OnPointerMove, OnPointerDown, OnPointerUp,
OnPointerCancel, OnWheel);
var skiaOptions = AvaloniaLocator.Current.GetService<SkiaOptions>();
@ -119,7 +118,12 @@ namespace Avalonia.Web
_context.SetResourceCacheLimit(skiaOptions?.MaxGpuResourceSizeBytes ?? 32 * 1024 * 1024);
}
_topLevelImpl.Surfaces = new[] { new BrowserSkiaSurface(_context, _jsGlInfo, ColorType, new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi, GRSurfaceOrigin.BottomLeft) };
_topLevelImpl.Surfaces = new[]
{
new BrowserSkiaSurface(_context, _jsGlInfo, ColorType,
new PixelSize((int)_canvasSize.Width, (int)_canvasSize.Height), _dpi,
GRSurfaceOrigin.BottomLeft)
};
}
else
{
@ -137,48 +141,8 @@ namespace Avalonia.Web
DomHelper.ObserveSize(host, null, OnSizeChanged);
CanvasHelper.RequestAnimationFrame(_canvas, true);
InputHelper.FocusElement(_containerElement);
}
private void OnTouchStart(JSObject arg, JSObject touch)
{
var x = touch.GetPropertyAsDouble("clientX");
var y = touch.GetPropertyAsDouble("clientY");
long identifier = touch.GetPropertyAsInt32("identifier");
_topLevelImpl.RawTouchEvent(RawPointerEventType.TouchBegin, new Point(x, y),
GetTouchModifiers(arg), identifier);
}
private void OnTouchEnd(JSObject arg, JSObject touch)
{
var x = touch.GetPropertyAsDouble("clientX");
var y = touch.GetPropertyAsDouble("clientY");
long identifier = touch.GetPropertyAsInt32("identifier");
_topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(x, y),
GetTouchModifiers(arg), identifier);
}
private void OnTouchCancel(JSObject arg, JSObject touch)
{
var x = touch.GetPropertyAsDouble("clientX");
var y = touch.GetPropertyAsDouble("clientY");
long identifier = touch.GetPropertyAsInt32("identifier");
_topLevelImpl.RawTouchEvent(RawPointerEventType.TouchCancel, new Point(x, y),
GetTouchModifiers(arg), identifier);
}
private void OnTouchMove(JSObject arg, JSObject touch)
{
var x = touch.GetPropertyAsDouble("clientX");
var y = touch.GetPropertyAsDouble("clientY");
long identifier = touch.GetPropertyAsInt32("identifier");
_topLevelImpl.RawTouchEvent(RawPointerEventType.TouchUpdate, new Point(x, y),
GetTouchModifiers(arg), identifier);
InputHelper.FocusElement(_containerElement);
}
private static RawInputModifiers GetTouchModifiers(JSObject e)
@ -214,9 +178,16 @@ namespace Avalonia.Web
private bool OnPointerMove(JSObject args)
{
var pointerType = args.GetPropertyAsString("pointerType");
if (pointerType == "touch")
return false;
{
var x = args.GetPropertyAsDouble("clientX");
var y = args.GetPropertyAsDouble("clientY");
long identifier = args.GetPropertyAsInt32("identifier");
return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchUpdate, new Point(x, y),
GetTouchModifiers(args), identifier);
}
var point = ExtractRawPointerFromJSArgs(args);
@ -228,7 +199,14 @@ namespace Avalonia.Web
var pointerType = args.GetPropertyAsString("pointerType");
if (pointerType == "touch")
return false;
{
var x = args.GetPropertyAsDouble("clientX");
var y = args.GetPropertyAsDouble("clientY");
long identifier = args.GetPropertyAsInt32("identifier");
return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchBegin, new Point(x, y),
GetTouchModifiers(args), identifier);
}
var type = args.GetPropertyAsInt32("button") switch
{
@ -251,7 +229,14 @@ namespace Avalonia.Web
var pointerType = args.GetPropertyAsString("pointerType") ?? "mouse";
if (pointerType == "touch")
return false;
{
var x = args.GetPropertyAsDouble("clientX");
var y = args.GetPropertyAsDouble("clientY");
long identifier = args.GetPropertyAsInt32("identifier");
return _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(x, y),
GetTouchModifiers(args), identifier);
}
var type = args.GetPropertyAsInt32("button") switch
{
@ -268,6 +253,23 @@ namespace Avalonia.Web
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),
GetTouchModifiers(args), identifier);
}
return false;
}
private bool OnWheel(JSObject args)
{

11
src/Web/Avalonia.Web/BrowserTopLevelImpl.cs

@ -65,12 +65,19 @@ namespace Avalonia.Web
}
}
public void RawTouchEvent(RawPointerEventType type, Point p, RawInputModifiers modifiers, long touchPointId)
public bool RawTouchEvent(RawPointerEventType type, Point p, RawInputModifiers modifiers, long touchPointId)
{
if (_inputRoot is { } && Input is { } input)
{
input.Invoke(new RawTouchEventArgs(_touchDevice, Timestamp, _inputRoot, type, p, modifiers, touchPointId));
var args = new RawTouchEventArgs(_touchDevice, Timestamp, _inputRoot, type, p, modifiers,
touchPointId);
input.Invoke(args);
return args.Handled;
}
return false;
}
public bool RawPointerEvent(

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

@ -36,19 +36,9 @@ internal static partial class InputHelper
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Boolean>>]
Func<JSObject, bool> pointerUp,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Boolean>>]
Func<JSObject, bool> pointerCancel,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Boolean>>]
Func<JSObject, bool> wheel);
[JSImport("InputHelper.subscribeTouchEvents", AvaloniaModule.MainModuleName)]
public static partial void SubscribeTouchEvents(
JSObject htmlElement,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Object>>]
Action<JSObject, JSObject> touchStart,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Object>>]
Action<JSObject, JSObject> touchEnd,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Object>>]
Action<JSObject, JSObject> touchCancel,
[JSMarshalAs<JSType.Function<JSType.Object, JSType.Object>>]
Action<JSObject, JSObject> touchMove);
[JSImport("InputHelper.subscribeInputEvents", AvaloniaModule.MainModuleName)]

68
src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts

@ -95,6 +95,7 @@ export class InputHelper {
pointerMoveCallback: (args: PointerEvent) => boolean,
pointerDownCallback: (args: PointerEvent) => boolean,
pointerUpCallback: (args: PointerEvent) => boolean,
pointerCancelCallback: (args: PointerEvent) => boolean,
wheelCallback: (args: WheelEvent) => boolean
) {
const pointerMoveHandler = (args: PointerEvent) => {
@ -112,6 +113,11 @@ export class InputHelper {
args.preventDefault();
};
const pointerCancelHandler = (args: PointerEvent) => {
pointerCancelCallback(args);
args.preventDefault();
};
const wheelHandler = (args: WheelEvent) => {
wheelCallback(args);
args.preventDefault();
@ -121,75 +127,17 @@ export class InputHelper {
element.addEventListener("pointerdown", pointerDownHandler);
element.addEventListener("pointerup", pointerUpHandler);
element.addEventListener("wheel", wheelHandler);
element.addEventListener("pointercancel", pointerCancelHandler);
return () => {
element.removeEventListener("pointerover", pointerMoveHandler);
element.removeEventListener("pointerdown", pointerDownHandler);
element.removeEventListener("pointerup", pointerUpHandler);
element.removeEventListener("pointercancel", pointerCancelHandler);
element.removeEventListener("wheel", wheelHandler);
};
}
public static subscribeTouchEvents(
element: HTMLInputElement,
touchStartCallback: (args: TouchEvent, touch: Touch) => void,
touchEndCallback: (args: TouchEvent, touch: Touch) => void,
touchCancelCallback: (args: TouchEvent, touch: Touch) => void,
touchMoveCallback: (args: TouchEvent, touch: Touch) => void
) {
const touchStartHandler = (args: TouchEvent) => {
for (let i = 0; i < args.changedTouches.length; i++) {
const touch = args.changedTouches.item(i);
if (touch) {
touchStartCallback(args, touch);
}
}
args.preventDefault();
};
const touchEndHandler = (args: TouchEvent) => {
for (let i = 0; i < args.changedTouches.length; i++) {
const touch = args.changedTouches.item(i);
if (touch) {
touchEndCallback(args, touch);
}
}
args.preventDefault();
};
const touchCancelHandler = (args: TouchEvent) => {
for (let i = 0; i < args.changedTouches.length; i++) {
const touch = args.changedTouches.item(i);
if (touch) {
touchCancelCallback(args, touch);
}
}
args.preventDefault();
};
const touchMoveHandler = (args: TouchEvent) => {
for (let i = 0; i < args.changedTouches.length; i++) {
const touch = args.changedTouches.item(i);
if (touch) {
touchMoveCallback(args, touch);
}
}
args.preventDefault();
};
element.addEventListener("touchstart", touchStartHandler);
element.addEventListener("touchend", touchEndHandler);
element.addEventListener("touchcancel", touchCancelHandler);
element.addEventListener("touchmove", touchMoveHandler);
return () => {
element.removeEventListener("touchstart", touchStartHandler);
element.removeEventListener("touchend", touchEndHandler);
element.removeEventListener("touchcancel", touchCancelHandler);
element.removeEventListener("touchmove", touchMoveHandler);
};
}
public static subscribeInputEvents(
element: HTMLInputElement,
inputCallback: (value: string) => boolean

Loading…
Cancel
Save