diff --git a/osu.Framework.Tests/Visual/Input/TestSceneKeyBindingContainer.cs b/osu.Framework.Tests/Visual/Input/TestSceneKeyBindingContainer.cs index 7a9a1b294c..6ec0f93c37 100644 --- a/osu.Framework.Tests/Visual/Input/TestSceneKeyBindingContainer.cs +++ b/osu.Framework.Tests/Visual/Input/TestSceneKeyBindingContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using NUnit.Framework; @@ -25,7 +23,7 @@ public void TestTriggerWithNoKeyBindings() bool pressedReceived = false; bool releasedReceived = false; - TestKeyBindingContainer keyBindingContainer = null; + TestKeyBindingContainer keyBindingContainer = null!; AddStep("add container", () => { @@ -89,7 +87,7 @@ public void TestKeyHandledByOtherDrawableDoesNotTrigger() List pressedActions = new List(); List releasedActions = new List(); - TextBox textBox = null; + TextBox textBox = null!; AddStep("add children", () => { @@ -218,7 +216,7 @@ public void TestKeyRepeatDoesntFireWhenNotAlive() int pressedReceived = 0; int repeatedReceived = 0; bool releasedReceived = false; - TestKeyBindingReceptor receptor = null; + TestKeyBindingReceptor receptor = null!; AddStep("add container", () => { @@ -299,11 +297,63 @@ public void TestKeyCombinationRepeatEvents() AddStep("release B", () => InputManager.ReleaseKey(Key.B)); } + [Test] + public void TestPrioritisedNonPositionalInput([Values] bool prioritised) + { + bool containerReceivedInput = false; + + AddStep("create content", () => + { + containerReceivedInput = false; + + Child = new TestKeyBindingContainer(prioritised) + { + Pressed = a => containerReceivedInput = a == TestAction.ActionA, + Child = new InputBlockingDrawable() + }; + }); + + AddStep("trigger action", () => InputManager.Key(Key.A)); + + if (prioritised) + AddAssert("container received input", () => containerReceivedInput); + else + AddAssert("container did not receive input", () => !containerReceivedInput); + } + + [Test] + public void TestPrioritisedPositionalInput([Values] bool prioritised) + { + bool containerReceivedInput = false; + + Drawable receptor = null!; + + AddStep("create content", () => + { + containerReceivedInput = false; + + Child = new TestKeyBindingContainer(prioritised) + { + RelativeSizeAxes = Axes.Both, + Pressed = a => containerReceivedInput = a == TestAction.ActionMouse4, + Child = receptor = new InputBlockingDrawable() + }; + }); + + AddStep("hover receptor", () => InputManager.MoveMouseTo(receptor)); + AddStep("trigger action", () => InputManager.Click(MouseButton.Button4)); + + if (prioritised) + AddAssert("container received input", () => containerReceivedInput); + else + AddAssert("container did not receive input", () => !containerReceivedInput); + } + private partial class TestKeyBindingReceptor : Drawable, IKeyBindingHandler { - public Action Pressed; - public Action Repeated; - public Action Released; + public Action? Pressed; + public Action? Repeated; + public Action? Released; public TestKeyBindingReceptor() { @@ -326,15 +376,44 @@ public void OnReleased(KeyBindingReleaseEvent e) } } - private partial class TestKeyBindingContainer : KeyBindingContainer + private partial class TestKeyBindingContainer : KeyBindingContainer, IKeyBindingHandler { + protected override bool Prioritised { get; } + + public Func? Pressed; + + public TestKeyBindingContainer(bool prioritised = false) + { + Prioritised = prioritised; + } + public override IEnumerable DefaultKeyBindings => new IKeyBinding[] { new KeyBinding(InputKey.A, TestAction.ActionA), new KeyBinding(new KeyCombination(InputKey.A, InputKey.B), TestAction.ActionAB), new KeyBinding(InputKey.Enter, TestAction.ActionEnter), - new KeyBinding(InputKey.Control, TestAction.ActionControl) + new KeyBinding(InputKey.Control, TestAction.ActionControl), + new KeyBinding(InputKey.ExtraMouseButton4, TestAction.ActionMouse4), }; + + public bool OnPressed(KeyBindingPressEvent e) + { + return Pressed?.Invoke(e.Action) == true; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + + private partial class InputBlockingDrawable : Drawable + { + protected override bool Handle(UIEvent e) => true; + + public InputBlockingDrawable() + { + RelativeSizeAxes = Axes.Both; + } } private enum TestAction @@ -342,7 +421,8 @@ private enum TestAction ActionA, ActionAB, ActionEnter, - ActionControl + ActionControl, + ActionMouse4, } } } diff --git a/osu.Framework/Input/Bindings/KeyBindingContainer.cs b/osu.Framework/Input/Bindings/KeyBindingContainer.cs index 2c8b4158f5..e0ef932c4e 100644 --- a/osu.Framework/Input/Bindings/KeyBindingContainer.cs +++ b/osu.Framework/Input/Bindings/KeyBindingContainer.cs @@ -94,6 +94,20 @@ internal override bool BuildNonPositionalInputQueue(List queue, bool a return true; } + internal override bool BuildPositionalInputQueue(Vector2 screenSpacePos, List queue) + { + if (!base.BuildPositionalInputQueue(screenSpacePos, queue)) + return false; + + if (Prioritised) + { + queue.Remove(this); + queue.Add(this); + } + + return true; + } + /// /// All input keys which are currently pressed and have reached this . ///