A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

134 lines
5.4 KiB

using Android.Graphics;
using Android.Views;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Media;
using Avalonia.Platform;
using System;
namespace Avalonia.Android.Platform.Specific.Helpers
{
public class AndroidTouchEventsHelper<TView> : IDisposable where TView : ITopLevelImpl, IAndroidView
{
private TView _view;
public bool HandleEvents { get; set; }
public AndroidTouchEventsHelper(TView view, Func<IInputRoot> getInputRoot, Func<MotionEvent, Point> getPointfunc)
{
this._view = view;
HandleEvents = true;
_getPointFunc = getPointfunc;
_getInputRoot = getInputRoot;
}
private DateTime _lastTouchMoveEventTime = DateTime.Now;
private Point? _lastTouchMovePoint;
private Func<MotionEvent, Point> _getPointFunc;
private Func<IInputRoot> _getInputRoot;
private Point _point;
public bool? DispatchTouchEvent(MotionEvent e, out bool callBase)
{
if (!HandleEvents)
{
callBase = true;
return null;
}
RawMouseEventType? mouseEventType = null;
var eventTime = DateTime.Now;
//Basic touch support
switch (e.Action)
{
case MotionEventActions.Move:
//may be bot flood the evnt system with too many event especially on not so powerfull mobile devices
if ((eventTime - _lastTouchMoveEventTime).TotalMilliseconds > 10)
{
mouseEventType = RawMouseEventType.Move;
}
break;
case MotionEventActions.Down:
mouseEventType = RawMouseEventType.LeftButtonDown;
break;
case MotionEventActions.Up:
mouseEventType = RawMouseEventType.LeftButtonUp;
break;
}
if (mouseEventType != null)
{
//if point is in view otherwise it's possible avalonia not to find the proper window to dispatch the event
_point = _getPointFunc(e);
double x = _view.View.GetX();
double y = _view.View.GetY();
double r = x + _view.View.Width;
double b = y + _view.View.Height;
if (x <= _point.X && r >= _point.X && y <= _point.Y && b >= _point.Y)
{
var inputRoot = _getInputRoot();
var mouseDevice = Avalonia.Android.Platform.Input.AndroidMouseDevice.Instance;
//in order the controls to work in a predictable way
//we need to generate mouse move before first mouse down event
//as this is the way buttons are working every time
//otherwise there is a problem sometimes
if (mouseEventType == RawMouseEventType.LeftButtonDown)
{
var me = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
RawMouseEventType.Move, _point, InputModifiers.None);
_view.Input(me);
}
var mouseEvent = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
mouseEventType.Value, _point, InputModifiers.LeftMouseButton);
_view.Input(mouseEvent);
if (e.Action == MotionEventActions.Move && mouseDevice.Captured == null)
{
if (_lastTouchMovePoint != null)
{
//raise mouse scroll event so the scrollers
//are moving with the cursor
double vectorX = _point.X - _lastTouchMovePoint.Value.X;
double vectorY = _point.Y - _lastTouchMovePoint.Value.Y;
//based on test correction of 0.02 is working perfect
double correction = 0.02;
var ps = AndroidPlatform.Instance.LayoutScalingFactor;
var mouseWheelEvent = new RawMouseWheelEventArgs(
mouseDevice,
(uint)eventTime.Ticks,
inputRoot,
_point,
new Vector(vectorX * correction / ps, vectorY * correction / ps), InputModifiers.LeftMouseButton);
_view.Input(mouseWheelEvent);
}
_lastTouchMovePoint = _point;
_lastTouchMoveEventTime = eventTime;
}
else if (e.Action == MotionEventActions.Down)
{
_lastTouchMovePoint = _point;
}
else
{
_lastTouchMovePoint = null;
}
}
}
callBase = true;
//if return false events for move and up are not received!!!
return e.Action != MotionEventActions.Up;
}
public void Dispose()
{
HandleEvents = false;
}
}
}