diff --git a/osu.Framework/Input/InputManager.cs b/osu.Framework/Input/InputManager.cs index debc7cef14..9c42184ff0 100644 --- a/osu.Framework/Input/InputManager.cs +++ b/osu.Framework/Input/InputManager.cs @@ -128,7 +128,7 @@ public Drawable DraggedDrawable /// /// This collection should not be retained as a reference. The contents is not stable outside of local usage. /// - public SlimReadOnlyListWrapper PositionalInputQueue => buildPositionalInputQueue(CurrentState.Mouse.Position); + public SlimReadOnlyListWrapper PositionalInputQueue => buildPositionalInputQueue(!CurrentState.Mouse.IsPositionValid ? null : CurrentState.Mouse.Position); /// /// Contains all s in top-down order which are considered @@ -627,10 +627,13 @@ private SlimReadOnlyListWrapper buildNonPositionalInputQueue() private readonly List positionalInputQueue = new List(); - private SlimReadOnlyListWrapper buildPositionalInputQueue(Vector2 screenSpacePos) + private SlimReadOnlyListWrapper buildPositionalInputQueue(Vector2? screenSpacePos) { positionalInputQueue.Clear(); + if (screenSpacePos == null) + return positionalInputQueue.AsSlimReadOnly(); + if (this is UserInputManager) FrameStatistics.Increment(StatisticsCounterType.PositionalIQ); @@ -639,7 +642,7 @@ private SlimReadOnlyListWrapper buildPositionalInputQueue(Vector2 scre for (int i = 0; i < children.Count; i++) { if (ShouldBeConsideredForInput(children[i])) - children[i].BuildPositionalInputQueue(screenSpacePos, positionalInputQueue); + children[i].BuildPositionalInputQueue(screenSpacePos.Value, positionalInputQueue); } positionalInputQueue.Reverse(); @@ -959,16 +962,19 @@ protected virtual void HandleMousePositionChange(MousePositionChangeEvent e) var state = e.State; var mouse = state.Mouse; - foreach (var h in InputHandlers) + if (e.LastPosition != null) { - if (h.Enabled.Value && h is INeedsMousePositionFeedback handler) - handler.FeedbackMousePositionChange(mouse.Position, h == mouseSource); - } + foreach (var h in InputHandlers) + { + if (h.Enabled.Value && h is INeedsMousePositionFeedback handler) + handler.FeedbackMousePositionChange(mouse.Position, h == mouseSource); + } - handleMouseMove(state, e.LastPosition); + handleMouseMove(state, e.LastPosition.Value); - foreach (var manager in mouseButtonEventManagers.Values) - manager.HandlePositionChange(state, e.LastPosition); + foreach (var manager in mouseButtonEventManagers.Values) + manager.HandlePositionChange(state, e.LastPosition.Value); + } updateHoverEvents(state); } diff --git a/osu.Framework/Input/StateChanges/Events/MousePositionChangeEvent.cs b/osu.Framework/Input/StateChanges/Events/MousePositionChangeEvent.cs index 8b0958ab75..48b78ff2ee 100644 --- a/osu.Framework/Input/StateChanges/Events/MousePositionChangeEvent.cs +++ b/osu.Framework/Input/StateChanges/Events/MousePositionChangeEvent.cs @@ -9,9 +9,9 @@ namespace osu.Framework.Input.StateChanges.Events public class MousePositionChangeEvent : InputStateChangeEvent { /// - /// The last mouse position. + /// The last mouse position, or null if the event is invalidation of the mouse position state. /// - public readonly Vector2 LastPosition; + public readonly Vector2? LastPosition; public MousePositionChangeEvent(InputState state, IInput input, Vector2 lastPosition) : base(state, input) diff --git a/osu.Framework/Input/StateChanges/MouseInvalidatePositionInput.cs b/osu.Framework/Input/StateChanges/MouseInvalidatePositionInput.cs new file mode 100644 index 0000000000..206d066fa0 --- /dev/null +++ b/osu.Framework/Input/StateChanges/MouseInvalidatePositionInput.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Input.StateChanges.Events; +using osu.Framework.Input.States; + +namespace osu.Framework.Input.StateChanges +{ + /// + /// Denotes an invalidation of the current mouse position, + /// mainly used when a single remaining touch source is released, + /// or a hovering pen (e.g. Apple Pencil) leaves the screen area. + /// + public class MouseInvalidatePositionInput : IInput + { + public void Apply(InputState state, IInputStateChangeHandler handler) + { + var mouse = state.Mouse; + + if (mouse.IsPositionValid) + { + mouse.IsPositionValid = false; + mouse.LastSource = this; + handler.HandleInputStateChange(new MousePositionChangeEvent(state, this, mouse.Position)); + } + } + } +} diff --git a/osu.Framework/Input/StateChanges/MouseInvalidatePositionInputFromTouch.cs b/osu.Framework/Input/StateChanges/MouseInvalidatePositionInputFromTouch.cs new file mode 100644 index 0000000000..d4966013d7 --- /dev/null +++ b/osu.Framework/Input/StateChanges/MouseInvalidatePositionInputFromTouch.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Input.StateChanges.Events; + +namespace osu.Framework.Input.StateChanges +{ + public class MouseInvalidatePositionInputFromTouch : MouseInvalidatePositionInput, ISourcedFromTouch + { + public MouseInvalidatePositionInputFromTouch(TouchStateChangeEvent touchEvent) + { + TouchEvent = touchEvent; + } + + public TouchStateChangeEvent TouchEvent { get; } + } +}