From 1ad8e2ead87674183cf4e06ba1e8bd879169ec97 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Wed, 22 Feb 2023 19:47:09 +0000 Subject: [PATCH 1/2] Reset last used mouse buttons on pointer release --- src/Avalonia.Base/Input/MouseDevice.cs | 1 + src/Avalonia.Base/Input/PenDevice.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Avalonia.Base/Input/MouseDevice.cs b/src/Avalonia.Base/Input/MouseDevice.cs index e1c42c4ead..50980f1c3d 100644 --- a/src/Avalonia.Base/Input/MouseDevice.cs +++ b/src/Avalonia.Base/Input/MouseDevice.cs @@ -184,6 +184,7 @@ namespace Avalonia.Input source?.RaiseEvent(e); _pointer.Capture(null); + _lastMouseDownButton = default; return e.Handled; } diff --git a/src/Avalonia.Base/Input/PenDevice.cs b/src/Avalonia.Base/Input/PenDevice.cs index 98da83c1ce..285249a5f8 100644 --- a/src/Avalonia.Base/Input/PenDevice.cs +++ b/src/Avalonia.Base/Input/PenDevice.cs @@ -131,6 +131,7 @@ namespace Avalonia.Input source?.RaiseEvent(e); pointer.Capture(null); + _lastMouseDownButton = default; return e.Handled; } From a62096ed05432d4d439d8ce9d64740657445c8f0 Mon Sep 17 00:00:00 2001 From: Yoh Deadfall Date: Wed, 22 Feb 2023 20:12:55 +0000 Subject: [PATCH 2/2] Added test for mouse device --- .../Input/MouseDeviceTests.cs | 56 ++++++++++++++++++- .../Input/PointerTestsBase.cs | 17 ++++-- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/Input/MouseDeviceTests.cs b/tests/Avalonia.Base.UnitTests/Input/MouseDeviceTests.cs index 3d7dc66cc4..1bb1b4af73 100644 --- a/tests/Avalonia.Base.UnitTests/Input/MouseDeviceTests.cs +++ b/tests/Avalonia.Base.UnitTests/Input/MouseDeviceTests.cs @@ -1,13 +1,63 @@ using Avalonia.Controls; using Avalonia.Input; +using Avalonia.Input.Raw; using Avalonia.Media; +using Avalonia.Platform; using Avalonia.UnitTests; +using Moq; using Xunit; namespace Avalonia.Base.UnitTests.Input { public class MouseDeviceTests : PointerTestsBase { + [Fact] + public void Initial_Buttons_Are_Not_Set_Without_Corresponding_Mouse_Down() + { + using var scope = AvaloniaLocator.EnterScope(); + var settingsMock = new Mock(); + var threadingMock = new Mock(); + + threadingMock.Setup(x => x.CurrentThreadIsLoopThread).Returns(true); + + AvaloniaLocator.CurrentMutable.BindToSelf(this) + .Bind().ToConstant(settingsMock.Object); + + using var app = UnitTestApplication.Start( + new TestServices( + inputManager: new InputManager(), + threadingInterface: threadingMock.Object)); + + var renderer = RendererMocks.CreateRenderer(); + var device = new MouseDevice(); + var impl = CreateTopLevelImplMock(renderer.Object); + + var control = new Control(); + var root = CreateInputRoot(impl.Object, control); + + MouseButton button = default; + + root.PointerReleased += (s, e) => button = e.InitialPressMouseButton; + + var down = CreateRawPointerArgs(device, root, RawPointerEventType.LeftButtonDown); + var up = CreateRawPointerArgs(device, root, RawPointerEventType.LeftButtonUp); + + SetHit(renderer, control); + + impl.Object.Input!(up); + + Assert.Equal(MouseButton.None, button); + + impl.Object.Input!(down); + impl.Object.Input!(up); + + Assert.Equal(MouseButton.Left, button); + + impl.Object.Input!(up); + + Assert.Equal(MouseButton.None, button); + } + [Fact] public void Capture_Is_Transferred_To_Parent_When_Control_Removed() { @@ -37,7 +87,7 @@ namespace Avalonia.Base.UnitTests.Input impl.Object.Input!(CreateRawPointerMovedArgs(device, root)); Assert.NotNull(result); - + result.Capture(control); Assert.Same(control, result.Captured); @@ -67,8 +117,8 @@ namespace Avalonia.Base.UnitTests.Input }) } }); - - + + Point? result = null; root.PointerMoved += (_, a) => { diff --git a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs index 2d45c699f1..5915343764 100644 --- a/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs +++ b/tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs @@ -55,20 +55,29 @@ public abstract class PointerTestsBase return root; } + protected static RawPointerEventArgs CreateRawPointerArgs( + IPointerDevice pointerDevice, + IInputRoot root, + RawPointerEventType type, + Point? position = default) + { + return new RawPointerEventArgs(pointerDevice, 0, root, type, position ?? default, default); + } + protected static RawPointerEventArgs CreateRawPointerMovedArgs( IPointerDevice pointerDevice, IInputRoot root, - Point? positition = null) + Point? position = null) { return new RawPointerEventArgs(pointerDevice, 0, root, RawPointerEventType.Move, - positition ?? default, default); + position ?? default, default); } protected static PointerEventArgs CreatePointerMovedArgs( - IInputRoot root, IInputElement? source, Point? positition = null) + IInputRoot root, IInputElement? source, Point? position = null) { return new PointerEventArgs(InputElement.PointerMovedEvent, source, new Mock().Object, (Visual)root, - positition ?? default, default, PointerPointProperties.None, KeyModifiers.None); + position ?? default, default, PointerPointProperties.None, KeyModifiers.None); } protected static Mock CreatePointerDeviceMock(