Skip to content

Commit

Permalink
Merge pull request #5966 from bdach/is-prioritised-positional
Browse files Browse the repository at this point in the history
Make `KeyBindingContainer.Prioritised` work for positional input too
  • Loading branch information
smoogipoo authored Aug 17, 2023
2 parents 38aa774 + 9d3ce4a commit 55f4a81
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 11 deletions.
102 changes: 91 additions & 11 deletions osu.Framework.Tests/Visual/Input/TestSceneKeyBindingContainer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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;
Expand All @@ -25,7 +23,7 @@ public void TestTriggerWithNoKeyBindings()
bool pressedReceived = false;
bool releasedReceived = false;

TestKeyBindingContainer keyBindingContainer = null;
TestKeyBindingContainer keyBindingContainer = null!;

AddStep("add container", () =>
{
Expand Down Expand Up @@ -89,7 +87,7 @@ public void TestKeyHandledByOtherDrawableDoesNotTrigger()
List<TestAction> pressedActions = new List<TestAction>();
List<TestAction> releasedActions = new List<TestAction>();

TextBox textBox = null;
TextBox textBox = null!;

AddStep("add children", () =>
{
Expand Down Expand Up @@ -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", () =>
{
Expand Down Expand Up @@ -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<TestAction>
{
public Action<TestAction> Pressed;
public Action<TestAction> Repeated;
public Action<TestAction> Released;
public Action<TestAction>? Pressed;
public Action<TestAction>? Repeated;
public Action<TestAction>? Released;

public TestKeyBindingReceptor()
{
Expand All @@ -326,23 +376,53 @@ public void OnReleased(KeyBindingReleaseEvent<TestAction> e)
}
}

private partial class TestKeyBindingContainer : KeyBindingContainer<TestAction>
private partial class TestKeyBindingContainer : KeyBindingContainer<TestAction>, IKeyBindingHandler<TestAction>
{
protected override bool Prioritised { get; }

public Func<TestAction, bool>? Pressed;

public TestKeyBindingContainer(bool prioritised = false)
{
Prioritised = prioritised;
}

public override IEnumerable<IKeyBinding> 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<TestAction> e)
{
return Pressed?.Invoke(e.Action) == true;
}

public void OnReleased(KeyBindingReleaseEvent<TestAction> e)
{
}
}

private partial class InputBlockingDrawable : Drawable
{
protected override bool Handle(UIEvent e) => true;

public InputBlockingDrawable()
{
RelativeSizeAxes = Axes.Both;
}
}

private enum TestAction
{
ActionA,
ActionAB,
ActionEnter,
ActionControl
ActionControl,
ActionMouse4,
}
}
}
14 changes: 14 additions & 0 deletions osu.Framework/Input/Bindings/KeyBindingContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ internal override bool BuildNonPositionalInputQueue(List<Drawable> queue, bool a
return true;
}

internal override bool BuildPositionalInputQueue(Vector2 screenSpacePos, List<Drawable> queue)
{
if (!base.BuildPositionalInputQueue(screenSpacePos, queue))
return false;

if (Prioritised)
{
queue.Remove(this);
queue.Add(this);
}

return true;
}

/// <summary>
/// All input keys which are currently pressed and have reached this <see cref="KeyBindingContainer"/>.
/// </summary>
Expand Down

0 comments on commit 55f4a81

Please sign in to comment.