From f0818c5d2dd49219c9254fa0359a6d40a0b6b483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Ku=C4=8Dera?= <10546952+miloush@users.noreply.github.com> Date: Wed, 1 Oct 2025 20:22:31 +0100 Subject: [PATCH] Do not recapture already captured element (#19740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Do not recapture already captured element * Recapture tests --------- Co-authored-by: Jan Kučera --- src/Avalonia.Base/Input/Pointer.cs | 7 +++++-- .../Input/PointerTests.cs | 17 +++++++++++++++++ .../Input/PointerTestsBase.cs | 12 ++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Input/Pointer.cs b/src/Avalonia.Base/Input/Pointer.cs index 7b98d6e3df..1f6741a09e 100644 --- a/src/Avalonia.Base/Input/Pointer.cs +++ b/src/Avalonia.Base/Input/Pointer.cs @@ -46,9 +46,12 @@ namespace Avalonia.Input private void Capture(IInputElement? control, bool platformInitiated) { - if (Captured is Visual v1) - v1.DetachedFromVisualTree -= OnCaptureDetached; var oldCapture = Captured; + if (oldCapture == control) + return; + + if (oldCapture is Visual v1) + v1.DetachedFromVisualTree -= OnCaptureDetached; Captured = control; if (!platformInitiated) diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs b/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs index 0bd23d64a9..912ce5b6a6 100644 --- a/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs +++ b/tests/Avalonia.Base.UnitTests/Input/PointerTests.cs @@ -36,5 +36,22 @@ namespace Avalonia.Base.UnitTests.Input pointer.Capture(null); Assert.True(receivers.SequenceEqual(new object[] { newCapture, newParent, el, root })); } + + [Fact] + public void Capture_Captured_ShouldNot_Call_Platform() + { + var pointer = new TestPointer(Pointer.GetNextFreeId(), PointerType.Mouse, true); + + Border capture = new Border(); + pointer.Capture(capture); + pointer.Capture(capture); + + Assert.Equal(1, pointer.PlatformCaptureCalled); + + pointer.Capture(null); + pointer.Capture(null); + + Assert.Equal(2, pointer.PlatformCaptureCalled); + } } } diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs index 95091be5f6..659ed1aaf1 100644 --- a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs +++ b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs @@ -16,6 +16,18 @@ namespace Avalonia.Base.UnitTests.Input; public abstract class PointerTestsBase : ScopedTestBase { + protected class TestPointer : Pointer + { + internal int PlatformCaptureCalled = 0; + + internal TestPointer(int id, PointerType type, bool isPrimary) : base(id, type, isPrimary) { } + + protected override void PlatformCapture(IInputElement? element) + { + PlatformCaptureCalled++; + } + } + private protected static void SetHit(Mock renderer, Control? hit) { renderer.Setup(x => x.HitTest(It.IsAny(), It.IsAny(), It.IsAny>()))