29 private readonly Dictionary<int, TapState> _activeTaps =
new();
30 private readonly HashSet<int> _activeContacts =
new();
31 private bool _isMultiTouchSequence;
35 private bool _isDisposed;
54 public event EventHandler<TappedEventArgs>?
Tapped;
68 _touchInput = touchInput ??
throw new ArgumentNullException(nameof(touchInput));
69 _touchInput.TouchBegan += OnTouchBegan;
70 _touchInput.TouchMoved += OnTouchMoved;
71 _touchInput.TouchEnded += OnTouchEnded;
76 _activeContacts.Add(e.
Touch.Id);
78 if (_activeContacts.Count > 1)
80 _isMultiTouchSequence =
true;
85 if (!_isMultiTouchSequence)
89 private void OnTouchMoved(
object? sender, TouchEventArgs e)
91 if (!_activeTaps.TryGetValue(e.Touch.Id, out var state))
97 var dx = e.Touch.Position.X - state.StartPosition.X;
98 var dy = e.Touch.Position.Y - state.StartPosition.Y;
99 var distance = Math.Sqrt(dx * dx + dy * dy);
102 _activeTaps[e.Touch.Id] = state with {
Cancelled =
true };
105 private void OnTouchEnded(
object? sender, TouchEventArgs e)
107 _activeContacts.Remove(e.Touch.Id);
109 if (_isMultiTouchSequence)
111 _activeTaps.Remove(e.Touch.Id);
112 if (_activeContacts.Count == 0)
113 _isMultiTouchSequence =
false;
117 if (!_activeTaps.TryGetValue(e.Touch.Id, out var state))
120 _activeTaps.Remove(e.Touch.Id);
123 if (state.Cancelled || e.Touch.Phase ==
TouchPhase.Cancelled)
126 var dx = e.Touch.Position.X - state.StartPosition.X;
127 var dy = e.Touch.Position.Y - state.StartPosition.Y;
128 var distance = Math.Sqrt(dx * dx + dy * dy);
129 var elapsed = HighResTimer.GetDuration(state.StartTick, e.Tick);
133 !(CompetingSwipeRecognizer?.WouldRecognize(distance, elapsed) ??
false))
135 Tapped?.Invoke(
this,
new TappedEventArgs(e.Touch.Id, state.StartPosition));
145 if (_isDisposed)
return;
148 _touchInput.TouchBegan -= OnTouchBegan;
149 _touchInput.TouchMoved -= OnTouchMoved;
150 _touchInput.TouchEnded -= OnTouchEnded;
154 internal void Reset()
157 _activeContacts.Clear();
158 _isMultiTouchSequence =
false;
161 private record
struct TapState(Point StartPosition, long StartTick, bool
Cancelled)
168 public TapState(Point startPosition,
long startTick) : this(startPosition, startTick, false) { }