diff --git a/src/Avalonia.Base/Input/Gestures.cs b/src/Avalonia.Base/Input/Gestures.cs index d50abaa4b9..4437c8c2c0 100644 --- a/src/Avalonia.Base/Input/Gestures.cs +++ b/src/Avalonia.Base/Input/Gestures.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Interactivity; +using Avalonia.Platform; using Avalonia.VisualTree; namespace Avalonia.Input @@ -125,7 +126,8 @@ namespace Avalonia.Input e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right) { var point = e.GetCurrentPoint((IVisual)target); - var tapSize = new Size(4, 4); + var settings = AvaloniaLocator.Current.GetService(); + var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapRect = new Rect(s_lastPressPoint, new Size()) .Inflate(new Thickness(tapSize.Width, tapSize.Height)); diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index 055c9cf1fd..808efb3931 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -128,8 +128,8 @@ namespace Avalonia.Input if (source != null) { var settings = AvaloniaLocator.Current.GetService(); - var doubleClickTime = settings?.DoubleClickTime.TotalMilliseconds ?? 500; - var doubleClickSize = settings?.DoubleClickSize ?? new Size(4, 4); + var doubleClickTime = settings?.GetDoubleTapTime(PointerType.Mouse).TotalMilliseconds ?? 500; + var doubleClickSize = settings?.GetDoubleTapSize(PointerType.Mouse) ?? new Size(4, 4); if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) { diff --git a/src/Avalonia.Base/Input/PenDevice.cs b/src/Avalonia.Base/Input/PenDevice.cs index f5f0e90a45..31f34566be 100644 --- a/src/Avalonia.Base/Input/PenDevice.cs +++ b/src/Avalonia.Base/Input/PenDevice.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Avalonia.Input.Raw; using Avalonia.Platform; @@ -77,8 +78,8 @@ namespace Avalonia.Input { pointer.Capture(source); var settings = AvaloniaLocator.Current.GetService(); - var doubleClickTime = settings?.DoubleClickTime.TotalMilliseconds ?? 500; - var doubleClickSize = settings?.DoubleClickSize ?? new Size(4, 4); + var doubleClickTime = settings?.GetDoubleTapTime(PointerType.Pen).TotalMilliseconds ?? 500; + var doubleClickSize = settings?.GetDoubleTapSize(PointerType.Pen) ?? new Size(4, 4); if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) { diff --git a/src/Avalonia.Base/Input/TouchDevice.cs b/src/Avalonia.Base/Input/TouchDevice.cs index 1d5b1d6bbf..05b0a89e01 100644 --- a/src/Avalonia.Base/Input/TouchDevice.cs +++ b/src/Avalonia.Base/Input/TouchDevice.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Avalonia.Input.Raw; using Avalonia.Platform; @@ -59,16 +60,18 @@ namespace Avalonia.Input else { var settings = AvaloniaLocator.Current.GetRequiredService(); + var doubleClickTime = settings?.GetDoubleTapTime(PointerType.Touch).TotalMilliseconds ?? 500; + var doubleClickSize = settings?.GetDoubleTapSize(PointerType.Touch) ?? new Size(4, 4); if (!_lastClickRect.Contains(args.Position) - || ev.Timestamp - _lastClickTime > settings.TouchDoubleClickTime.TotalMilliseconds) + || ev.Timestamp - _lastClickTime > doubleClickTime) { _clickCount = 0; } ++_clickCount; _lastClickTime = ev.Timestamp; _lastClickRect = new Rect(args.Position, new Size()) - .Inflate(new Thickness(settings.TouchDoubleClickSize.Width / 2, settings.TouchDoubleClickSize.Height / 2)); + .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); } target.RaiseEvent(new PointerPressedEventArgs(target, pointer, diff --git a/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs b/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs new file mode 100644 index 0000000000..dd3e1a4cb1 --- /dev/null +++ b/src/Avalonia.Base/Platform/DefaultPlatformSettings.cs @@ -0,0 +1,30 @@ +using System; +using Avalonia.Input; + +namespace Avalonia.Platform +{ + /// + /// A default implementation of for platforms which don't have + /// an OS-specific implementation. + /// + public class DefaultPlatformSettings : IPlatformSettings + { + public Size GetTapSize(PointerType type) + { + return type switch + { + PointerType.Touch => new(10, 10), + _ => new(4, 4), + }; + } + public Size GetDoubleTapSize(PointerType type) + { + return type switch + { + PointerType.Touch => new(16, 16), + _ => new(4, 4), + }; + } + public TimeSpan GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(500); + } +} diff --git a/src/Avalonia.Base/Platform/IPlatformSettings.cs b/src/Avalonia.Base/Platform/IPlatformSettings.cs index 78d1817312..e7921883fd 100644 --- a/src/Avalonia.Base/Platform/IPlatformSettings.cs +++ b/src/Avalonia.Base/Platform/IPlatformSettings.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Input; using Avalonia.Metadata; namespace Avalonia.Platform @@ -6,18 +7,25 @@ namespace Avalonia.Platform [Unstable] public interface IPlatformSettings { - Size DoubleClickSize { get; } - - TimeSpan DoubleClickTime { get; } + /// + /// The size of the rectangle around the location of a pointer down that a pointer up + /// must occur within in order to register a tap gesture, in device-independent pixels. + /// + /// The pointer type. + Size GetTapSize(PointerType type); /// - /// Determines the size of the area within that you should click twice in order for a double click to be counted. + /// The size of the rectangle around the location of a pointer down that a pointer up + /// must occur within in order to register a double-tap gesture, in device-independent + /// pixels. /// - Size TouchDoubleClickSize { get; } + /// The pointer type. + Size GetDoubleTapSize(PointerType type); /// - /// Determines the time span that what will be used to determine the double-click. + /// Gets the maximum time that may occur between the first and second click of a double- + /// tap gesture. /// - TimeSpan TouchDoubleClickTime { get; } + TimeSpan GetDoubleTapTime(PointerType type); } } diff --git a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs index 5277435858..cd14b2d69a 100644 --- a/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs @@ -9,7 +9,7 @@ using Avalonia.Rendering; namespace Avalonia.DesignerSupport.Remote { - class PreviewerWindowingPlatform : IWindowingPlatform, IPlatformSettings + class PreviewerWindowingPlatform : IWindowingPlatform { static readonly IKeyboardDevice Keyboard = new KeyboardDevice(); private static IAvaloniaRemoteTransportConnection s_transport; @@ -51,7 +51,7 @@ namespace Avalonia.DesignerSupport.Remote .Bind().ToSingleton() .Bind().ToSingleton() .Bind().ToConstant(Keyboard) - .Bind().ToConstant(instance) + .Bind().ToSingleton() .Bind().ToConstant(threading) .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new DefaultRenderTimer(60)) @@ -60,12 +60,5 @@ namespace Avalonia.DesignerSupport.Remote .Bind().ToSingleton(); } - - public Size DoubleClickSize { get; } = new Size(2, 2); - public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); - - public Size TouchDoubleClickSize => new Size(16, 16); - - public TimeSpan TouchDoubleClickTime => DoubleClickTime; } } diff --git a/src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs b/src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs index 4fcec6fd52..8da10fa59b 100644 --- a/src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs +++ b/src/Avalonia.Headless/AvaloniaHeadlessPlatform.cs @@ -63,7 +63,7 @@ namespace Avalonia.Headless .Bind().ToConstant(new HeadlessPlatformThreadingInterface()) .Bind().ToSingleton() .Bind().ToSingleton() - .Bind().ToConstant(new HeadlessPlatformSettingsStub()) + .Bind().ToSingleton() .Bind().ToSingleton() .Bind().ToConstant(new KeyboardDevice()) .Bind().ToConstant(new RenderLoop()) diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs index 76948e9286..688b8e0398 100644 --- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs +++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs @@ -65,16 +65,6 @@ namespace Avalonia.Headless } } - class HeadlessPlatformSettingsStub : IPlatformSettings - { - public Size DoubleClickSize { get; } = new Size(2, 2); - public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); - - public Size TouchDoubleClickSize => new Size(16,16); - - public TimeSpan TouchDoubleClickTime => DoubleClickTime; - } - class HeadlessGlyphTypefaceImpl : IGlyphTypeface { public FontMetrics Metrics => new FontMetrics diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index 66d78cbb60..db6b6f57cd 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -14,7 +14,7 @@ using MicroCom.Runtime; namespace Avalonia.Native { - class AvaloniaNativePlatform : IPlatformSettings, IWindowingPlatform + class AvaloniaNativePlatform : IWindowingPlatform { private readonly IAvaloniaNativeFactory _factory; private AvaloniaNativePlatformOptions _options; @@ -26,16 +26,6 @@ namespace Avalonia.Native internal static readonly KeyboardDevice KeyboardDevice = new KeyboardDevice(); [CanBeNull] internal static Compositor Compositor { get; private set; } - public Size DoubleClickSize => new Size(4, 4); - - public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(500); //TODO - - /// - public Size TouchDoubleClickSize => new Size(16, 16); - - /// - public TimeSpan TouchDoubleClickTime => DoubleClickTime; - public static AvaloniaNativePlatform Initialize(IntPtr factory, AvaloniaNativePlatformOptions options) { var result = new AvaloniaNativePlatform(MicroComRuntime.CreateProxyFor(factory, true)); @@ -113,7 +103,7 @@ namespace Avalonia.Native .Bind().ToConstant(new CursorFactory(_factory.CreateCursorFactory())) .Bind().ToSingleton() .Bind().ToConstant(KeyboardDevice) - .Bind().ToConstant(this) + .Bind().ToSingleton() .Bind().ToConstant(this) .Bind().ToConstant(new ClipboardImpl(_factory.CreateClipboard())) .Bind().ToConstant(new DefaultRenderTimer(60)) diff --git a/src/Avalonia.Native/DoubleClickHelper.cs b/src/Avalonia.Native/DoubleClickHelper.cs index 7618d6976a..02e74d7d63 100644 --- a/src/Avalonia.Native/DoubleClickHelper.cs +++ b/src/Avalonia.Native/DoubleClickHelper.cs @@ -1,3 +1,4 @@ +using Avalonia.Input; using Avalonia.Platform; namespace Avalonia.Native @@ -13,7 +14,8 @@ namespace Avalonia.Native Point p) { var settings = AvaloniaLocator.Current.GetService(); - var doubleClickTime = settings.DoubleClickTime.TotalMilliseconds; + var doubleClickTime = settings?.GetDoubleTapTime(PointerType.Mouse).TotalMilliseconds ?? 500; + var doubleClickSize = settings?.GetDoubleTapSize(PointerType.Mouse) ?? new Size(4, 4); if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) { @@ -23,7 +25,7 @@ namespace Avalonia.Native ++_clickCount; _lastClickTime = timestamp; _lastClickRect = new Rect(p, new Size()) - .Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2)); + .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); return _clickCount == 2; } diff --git a/src/Avalonia.X11/Stubs.cs b/src/Avalonia.X11/Stubs.cs deleted file mode 100644 index f73512f1e8..0000000000 --- a/src/Avalonia.X11/Stubs.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Avalonia.Platform; - -namespace Avalonia.X11 -{ - class PlatformSettingsStub : IPlatformSettings - { - public Size DoubleClickSize { get; } = new Size(2, 2); - public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); - - /// - public Size TouchDoubleClickSize => new Size(16, 16); - - /// - public TimeSpan TouchDoubleClickTime => DoubleClickTime; - } -} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 381cdd74c3..96dc16e186 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -80,7 +80,7 @@ namespace Avalonia.X11 .Bind().ToFunc(() => KeyboardDevice) .Bind().ToConstant(new X11CursorFactory(Display)) .Bind().ToConstant(new X11Clipboard(this)) - .Bind().ToConstant(new PlatformSettingsStub()) + .Bind().ToSingleton() .Bind().ToConstant(new X11IconLoader()) .Bind().ToConstant(new LinuxMountedVolumeInfoProvider()) .Bind().ToConstant(new X11PlatformLifetimeEvents(this)); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs index 730eb0071d..d881a97af2 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs @@ -51,7 +51,7 @@ namespace Avalonia.LinuxFramebuffer .Bind().ToConstant(new RenderLoop()) .Bind().ToTransient() .Bind().ToConstant(new KeyboardDevice()) - .Bind().ToSingleton() + .Bind().ToSingleton() .Bind().ToSingleton(); Compositor = new Compositor( diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Stubs.cs b/src/Linux/Avalonia.LinuxFramebuffer/Stubs.cs index dd60d5f09d..c5c7c13c67 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Stubs.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Stubs.cs @@ -14,13 +14,4 @@ namespace Avalonia.LinuxFramebuffer public void Dispose() { } } } - internal class PlatformSettings : IPlatformSettings - { - public Size DoubleClickSize { get; } = new Size(4, 4); - public TimeSpan DoubleClickTime { get; } = new TimeSpan(0, 0, 0, 0, 500); - - public Size TouchDoubleClickSize => new Size(16,16); - - public TimeSpan TouchDoubleClickTime => DoubleClickTime; - } } diff --git a/src/Web/Avalonia.Web/WindowingPlatform.cs b/src/Web/Avalonia.Web/WindowingPlatform.cs index 7c2a84516b..29c797660f 100644 --- a/src/Web/Avalonia.Web/WindowingPlatform.cs +++ b/src/Web/Avalonia.Web/WindowingPlatform.cs @@ -45,13 +45,6 @@ namespace Avalonia.Web .Bind().ToSingleton(); } - public Size DoubleClickSize { get; } = new Size(2, 2); - - public TimeSpan DoubleClickTime { get; } = TimeSpan.FromMilliseconds(500); - - public Size TouchDoubleClickSize => new Size(16, 16); - - public TimeSpan TouchDoubleClickTime => DoubleClickTime; public void RunLoop(CancellationToken cancellationToken) { throw new NotSupportedException(); @@ -101,5 +94,25 @@ namespace Avalonia.Web { return AvaloniaLocator.Current.GetRequiredService(); } + + Size IPlatformSettings.GetTapSize(PointerType type) + { + return type switch + { + PointerType.Touch => new(10, 10), + _ => new(4, 4), + }; + } + + Size IPlatformSettings.GetDoubleTapSize(PointerType type) + { + return type switch + { + PointerType.Touch => new(16, 16), + _ => new(4, 4), + }; + } + + TimeSpan IPlatformSettings.GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(500); } } diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 3cdc3586dc..18977ec4c3 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -130,17 +130,6 @@ namespace Avalonia.Win32 internal static Compositor Compositor { get; private set; } - public Size DoubleClickSize => new Size( - UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CXDOUBLECLK), - UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDOUBLECLK)); - - public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(UnmanagedMethods.GetDoubleClickTime()); - - /// - public Size TouchDoubleClickSize => new Size(16,16); - - /// - public TimeSpan TouchDoubleClickTime => DoubleClickTime; public static void Initialize() { Initialize(new Win32PlatformOptions()); @@ -398,5 +387,25 @@ namespace Avalonia.Win32 SetProcessDPIAware(); } + + Size IPlatformSettings.GetTapSize(PointerType type) + { + return type switch + { + PointerType.Touch => new(10, 10), + _ => new(GetSystemMetrics(SystemMetric.SM_CXDRAG), GetSystemMetrics(SystemMetric.SM_CYDRAG)), + }; + } + + Size IPlatformSettings.GetDoubleTapSize(PointerType type) + { + return type switch + { + PointerType.Touch => new(16, 16), + _ => new(GetSystemMetrics(SystemMetric.SM_CXDOUBLECLK), GetSystemMetrics(SystemMetric.SM_CYDOUBLECLK)), + }; + } + + TimeSpan IPlatformSettings.GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(GetDoubleClickTime()); } } diff --git a/src/iOS/Avalonia.iOS/Platform.cs b/src/iOS/Avalonia.iOS/Platform.cs index 67d037f9e5..c2cf8c6f6c 100644 --- a/src/iOS/Avalonia.iOS/Platform.cs +++ b/src/iOS/Avalonia.iOS/Platform.cs @@ -28,32 +28,19 @@ namespace Avalonia.iOS public static EaglFeature GlFeature; public static DisplayLinkTimer Timer; internal static Compositor Compositor { get; private set; } - - class PlatformSettings : IPlatformSettings - { - /// - public Size TouchDoubleClickSize => new Size(10, 10); - - /// - public TimeSpan TouchDoubleClickTime => TimeSpan.FromMilliseconds(500); - - public Size DoubleClickSize => new Size(4, 4); - - public TimeSpan DoubleClickTime => TouchDoubleClickTime; - } public static void Register() { GlFeature ??= new EaglFeature(); Timer ??= new DisplayLinkTimer(); var keyboard = new KeyboardDevice(); - + AvaloniaLocator.CurrentMutable .Bind().ToConstant(GlFeature) .Bind().ToConstant(new CursorFactoryStub()) .Bind().ToConstant(new WindowingPlatformStub()) .Bind().ToConstant(new ClipboardImpl()) - .Bind().ToConstant(new PlatformSettings()) + .Bind().ToSingleton() .Bind().ToConstant(new PlatformIconLoaderStub()) .Bind().ToSingleton() .Bind().ToSingleton() diff --git a/tests/Avalonia.Base.UnitTests/Input/TouchDeviceTests.cs b/tests/Avalonia.Base.UnitTests/Input/TouchDeviceTests.cs index 7b7d547346..1070138221 100644 --- a/tests/Avalonia.Base.UnitTests/Input/TouchDeviceTests.cs +++ b/tests/Avalonia.Base.UnitTests/Input/TouchDeviceTests.cs @@ -209,7 +209,7 @@ namespace Avalonia.Input.UnitTests var unitTestApp = UnitTestApplication.Start( new TestServices(inputManager: new InputManager())); var iSettingsMock = new Mock(); - iSettingsMock.Setup(x => x.TouchDoubleClickTime).Returns(doubleClickTime); + iSettingsMock.Setup(x => x.GetDoubleTapTime(It.IsAny())).Returns(doubleClickTime); AvaloniaLocator.CurrentMutable.BindToSelf(this) .Bind().ToConstant(iSettingsMock.Object); return unitTestApp;