10 changed files with 257 additions and 13 deletions
@ -0,0 +1,60 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Input |
|||
{ |
|||
public class Pointer : IPointer, IDisposable |
|||
{ |
|||
public Pointer(int id, PointerType type, bool isPrimary, IInputElement implicitlyCaptured) |
|||
{ |
|||
Id = id; |
|||
Type = type; |
|||
IsPrimary = isPrimary; |
|||
ImplicitlyCaptured = implicitlyCaptured; |
|||
if (ImplicitlyCaptured != null) |
|||
ImplicitlyCaptured.DetachedFromVisualTree += OnImplicitCaptureDetached; |
|||
} |
|||
|
|||
public int Id { get; } |
|||
|
|||
public void Capture(IInputElement control) |
|||
{ |
|||
if (Captured != null) |
|||
Captured.DetachedFromVisualTree -= OnCaptureDetached; |
|||
Captured = control; |
|||
if (Captured != null) |
|||
Captured.DetachedFromVisualTree += OnCaptureDetached; |
|||
} |
|||
|
|||
IInputElement GetNextCapture(IVisual parent) => |
|||
parent as IInputElement ?? parent.GetVisualAncestors().OfType<IInputElement>().FirstOrDefault(); |
|||
|
|||
private void OnCaptureDetached(object sender, VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
Capture(GetNextCapture(e.Parent)); |
|||
} |
|||
|
|||
private void OnImplicitCaptureDetached(object sender, VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
ImplicitlyCaptured.DetachedFromVisualTree -= OnImplicitCaptureDetached; |
|||
ImplicitlyCaptured = GetNextCapture(e.Parent); |
|||
if (ImplicitlyCaptured != null) |
|||
ImplicitlyCaptured.DetachedFromVisualTree += OnImplicitCaptureDetached; |
|||
} |
|||
|
|||
public IInputElement Captured { get; private set; } |
|||
public IInputElement ImplicitlyCaptured { get; private set; } |
|||
public IInputElement GetEffectiveCapture() => Captured ?? ImplicitlyCaptured; |
|||
|
|||
public PointerType Type { get; } |
|||
public bool IsPrimary { get; } |
|||
public void Dispose() |
|||
{ |
|||
if (ImplicitlyCaptured != null) |
|||
ImplicitlyCaptured.DetachedFromVisualTree -= OnImplicitCaptureDetached; |
|||
if (Captured != null) |
|||
Captured.DetachedFromVisualTree -= OnCaptureDetached; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Avalonia.Input.Raw; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Input |
|||
{ |
|||
/// <summary>
|
|||
/// Handles raw touch events
|
|||
/// This class is supposed to be used on per-toplevel basis, don't event try to have a global instance
|
|||
/// </summary>
|
|||
public class TouchDevice : IInputDevice |
|||
{ |
|||
Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>(); |
|||
|
|||
static InputModifiers GetModifiers(InputModifiers modifiers, bool left) |
|||
{ |
|||
var mask = (InputModifiers)0x7fffffff ^ InputModifiers.LeftMouseButton ^ InputModifiers.MiddleMouseButton ^ |
|||
InputModifiers.RightMouseButton; |
|||
modifiers &= mask; |
|||
if (left) |
|||
modifiers |= InputModifiers.LeftMouseButton; |
|||
return modifiers; |
|||
} |
|||
|
|||
public void ProcessRawEvent(RawInputEventArgs ev) |
|||
{ |
|||
var args = (RawTouchEventArgs)ev; |
|||
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer)) |
|||
{ |
|||
if (args.Type == RawMouseEventType.TouchEnd) |
|||
return; |
|||
var hit = args.Root.InputHitTest(args.Position); |
|||
|
|||
_pointers[args.TouchPointId] = pointer = new Pointer(PointerIds.Next(), |
|||
PointerType.Touch, _pointers.Count == 0, hit); |
|||
} |
|||
|
|||
|
|||
var target = pointer.GetEffectiveCapture() ?? args.Root; |
|||
if (args.Type == RawMouseEventType.TouchBegin) |
|||
{ |
|||
var modifiers = GetModifiers(args.InputModifiers, pointer.IsPrimary); |
|||
target.RaiseEvent(new PointerPressedEventArgs(target, pointer, |
|||
args.Root, args.Position, new PointerPointProperties(modifiers), |
|||
modifiers)); |
|||
} |
|||
|
|||
if (args.Type == RawMouseEventType.TouchEnd) |
|||
{ |
|||
_pointers.Remove(args.TouchPointId); |
|||
var modifiers = GetModifiers(args.InputModifiers, false); |
|||
using (pointer) |
|||
{ |
|||
target.RaiseEvent(new PointerReleasedEventArgs(target, pointer, |
|||
args.Root, args.Position, new PointerPointProperties(modifiers), |
|||
modifiers, pointer.IsPrimary ? MouseButton.Left : MouseButton.None)); |
|||
} |
|||
} |
|||
|
|||
if (args.Type == RawMouseEventType.TouchUpdate) |
|||
{ |
|||
var modifiers = GetModifiers(args.InputModifiers, pointer.IsPrimary); |
|||
target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root, |
|||
args.Position, new PointerPointProperties(modifiers), modifiers)); |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
using System; |
|||
using Avalonia.Interactivity; |
|||
|
|||
namespace Avalonia.Input.TouchGestureRecognizers |
|||
{ |
|||
/* |
|||
public class TapGestureRecognizer : ITouchGestureRecognizer |
|||
{ |
|||
long _started; |
|||
Point _startPoint; |
|||
const double Distance = 20; |
|||
const long MaxTapDuration = 500; |
|||
TouchGestureRecognizerResult ITouchGestureRecognizer.RecognizeGesture(IInputElement owner, TouchEventArgs args) |
|||
{ |
|||
if (args.Route == RoutingStrategies.Tunnel) |
|||
return TouchGestureRecognizerResult.Continue; |
|||
|
|||
// Multi-touch sequence
|
|||
if(args.Touches.Count > 1) |
|||
return TouchGestureRecognizerResult.Reject; |
|||
// Sequence started, save the start time
|
|||
if(args.Type == TouchEventType.TouchBegin) |
|||
{ |
|||
_started = args.Timestamp; |
|||
var pos = args.Touches[0].GetPosition(owner); |
|||
if (pos == null) |
|||
return TouchGestureRecognizerResult.Reject; |
|||
_startPoint = pos.Value; |
|||
return TouchGestureRecognizerResult.Continue; |
|||
} |
|||
|
|||
if(args.Type == TouchEventType.TouchEnd) |
|||
{ |
|||
var pos = args.RemovedTouches[0].GetPosition(owner); |
|||
if (pos == null) |
|||
return TouchGestureRecognizerResult.Reject; |
|||
var endPoint = pos.Value; |
|||
|
|||
if(Math.Abs(endPoint.X - _startPoint.X) < Distance |
|||
&& Math.Abs(endPoint.Y - _startPoint.Y) < Distance |
|||
&& (args.Timestamp - _started) < MaxTapDuration) |
|||
{ |
|||
((Interactive)args.RemovedTouches[0].InitialTarget).RaiseEvent( |
|||
new RoutedEventArgs(Gestures.TappedEvent)); |
|||
return TouchGestureRecognizerResult.Accept; |
|||
} |
|||
else |
|||
return TouchGestureRecognizerResult.Reject; |
|||
} |
|||
return TouchGestureRecognizerResult.Continue; |
|||
} |
|||
|
|||
public void Cancel() |
|||
{ |
|||
_started = 0; |
|||
_startPoint = default; |
|||
} |
|||
} |
|||
*/ |
|||
} |
|||
Loading…
Reference in new issue