Skip to content

Commit

Permalink
Fix DoubleTapped on touch (#7213)
Browse files Browse the repository at this point in the history
DoubleTapped now can be triggered by touch
Fixed DoubleTapped triggering logic, previously it could be triggered only when you click twice, didn't work when you click 4 times,6, etc.
Fixed Tapped to be triggered only once when you double-click, now it triggers Tapped once and DoubleTapped once instead of triggering Tapped two times and DoubleTapped once.Matches UWP behaviour.
  • Loading branch information
Takoooooo authored Dec 22, 2021
1 parent a9900df commit 1fbcd61
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 20 deletions.
18 changes: 12 additions & 6 deletions src/Avalonia.Input/Gestures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Avalonia.Input
{
public static class Gestures
{
private static bool s_isDoubleTapped = false;
public static readonly RoutedEvent<TappedEventArgs> TappedEvent = RoutedEvent.Register<TappedEventArgs>(
"Tapped",
RoutingStrategies.Bubble,
Expand Down Expand Up @@ -81,20 +82,23 @@ private static void PointerPressed(RoutedEventArgs ev)
var e = (PointerPressedEventArgs)ev;
var visual = (IVisual)ev.Source;

#pragma warning disable CS0618 // Type or member is obsolete
var clickCount = e.ClickCount;
#pragma warning restore CS0618 // Type or member is obsolete
if (clickCount <= 1)
if (e.ClickCount <= 1)
{
s_isDoubleTapped = false;
s_lastPress.SetTarget(ev.Source);
}
else if (clickCount == 2 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
else if (e.ClickCount % 2 == 0 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
if (s_lastPress.TryGetTarget(out var target) && target == e.Source)
{
s_isDoubleTapped = true;
e.Source.RaiseEvent(new TappedEventArgs(DoubleTappedEvent, e));
}
}
else
{
s_isDoubleTapped = false;
}
}
}

Expand All @@ -112,7 +116,9 @@ private static void PointerReleased(RoutedEventArgs ev)
{
e.Source.RaiseEvent(new TappedEventArgs(RightTappedEvent, e));
}
else
//s_isDoubleTapped needed here to prevent invoking Tapped event when DoubleTapped is called.
//This behaviour matches UWP behaviour.
else if (s_isDoubleTapped == false)
{
e.Source.RaiseEvent(new TappedEventArgs(TappedEvent, e));
}
Expand Down
9 changes: 4 additions & 5 deletions src/Avalonia.Input/PointerEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public enum MouseButton

public class PointerPressedEventArgs : PointerEventArgs
{
private readonly int _obsoleteClickCount;
private readonly int _clickCount;

public PointerPressedEventArgs(
IInteractive source,
Expand All @@ -123,15 +123,14 @@ public PointerPressedEventArgs(
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
int obsoleteClickCount = 1)
int clickCount = 1)
: base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers)
{
_obsoleteClickCount = obsoleteClickCount;
_clickCount = clickCount;
}

[Obsolete("Use DoubleTapped event or Gestures.DoubleRightTapped attached event")]
public int ClickCount => _obsoleteClickCount;
public int ClickCount => _clickCount;

[Obsolete("Use PointerPressedEventArgs.GetCurrentPoint(this).Properties")]
public MouseButton MouseButton => Properties.PointerUpdateKind.GetMouseButton();
Expand Down
44 changes: 35 additions & 9 deletions src/Avalonia.Input/TouchDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Avalonia.Input.Raw;
using Avalonia.VisualTree;
using Avalonia.Platform;

namespace Avalonia.Input
{
Expand All @@ -16,7 +16,9 @@ public class TouchDevice : IInputDevice, IDisposable
{
private readonly Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>();
private bool _disposed;

private int _clickCount;
private Rect _lastClickRect;
private ulong _lastClickTime;
KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) =>
(KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask);

Expand All @@ -27,10 +29,10 @@ RawInputModifiers GetModifiers(RawInputModifiers modifiers, bool isLeftButtonDow
rv |= RawInputModifiers.LeftMouseButton;
return rv;
}

public void ProcessRawEvent(RawInputEventArgs ev)
{
if(_disposed)
if (_disposed)
return;
var args = (RawTouchEventArgs)ev;
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer))
Expand All @@ -43,16 +45,40 @@ public void ProcessRawEvent(RawInputEventArgs ev)
PointerType.Touch, _pointers.Count == 0);
pointer.Capture(hit);
}


var target = pointer.Captured ?? args.Root;
if (args.Type == RawPointerEventType.TouchBegin)
{
if (_pointers.Count > 1)
{
_clickCount = 1;
_lastClickTime = 0;
_lastClickRect = new Rect();
}
else
{
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
if (settings == null)
{
throw new Exception("IPlatformSettings can not be null");
}
if (!_lastClickRect.Contains(args.Position)
|| ev.Timestamp - _lastClickTime > settings.DoubleClickTime.TotalMilliseconds)
{
_clickCount = 0;
}
++_clickCount;
_lastClickTime = ev.Timestamp;
_lastClickRect = new Rect(args.Position, new Size())
.Inflate(new Thickness(16, 16));
}

target.RaiseEvent(new PointerPressedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, true),
PointerUpdateKind.LeftButtonPressed),
GetKeyModifiers(args.InputModifiers)));
GetKeyModifiers(args.InputModifiers), _clickCount));
}

if (args.Type == RawPointerEventType.TouchEnd)
Expand Down Expand Up @@ -84,19 +110,19 @@ public void ProcessRawEvent(RawInputEventArgs ev)
GetKeyModifiers(args.InputModifiers)));
}


}

public void Dispose()
{
if(_disposed)
if (_disposed)
return;
var values = _pointers.Values.ToList();
_pointers.Clear();
_disposed = true;
foreach (var p in values)
p.Dispose();
}

}
}
Loading

0 comments on commit 1fbcd61

Please sign in to comment.