Remove global action container input queue workaround

As described in #24248, the workaround employed by
`GlobalActionContainer`, wherein it tried to handle actions with
priority before its children by being placed in front of the children
and not _actually containing_ said children, is blocking the resolution
of some rather major input handling issues that allow key releases to be
received by deparented drawables.

To resolve, migrate `GlobalActionContainer` to use `Prioritised`, which
can be done without regressing certain mouse button flows after
ppy/osu-framework#5966.
This commit is contained in:
Bartłomiej Dach 2023-08-06 17:40:55 +02:00
parent aa5680a8aa
commit 5454d1caa1
No known key found for this signature in database
3 changed files with 25 additions and 36 deletions

View File

@ -3,33 +3,26 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Localisation; using osu.Game.Localisation;
namespace osu.Game.Input.Bindings namespace osu.Game.Input.Bindings
{ {
public partial class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalKeyboardInput public partial class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalKeyboardInput, IKeyBindingHandler<GlobalAction>
{ {
private readonly Drawable? handler; private readonly IKeyBindingHandler<GlobalAction>? handler;
private InputManager? parentInputManager;
public GlobalActionContainer(OsuGameBase? game) public GlobalActionContainer(OsuGameBase? game)
: base(matchingMode: KeyCombinationMatchingMode.Modifiers) : base(matchingMode: KeyCombinationMatchingMode.Modifiers)
{ {
if (game is IKeyBindingHandler<GlobalAction>) if (game is IKeyBindingHandler<GlobalAction> h)
handler = game; handler = h;
} }
protected override void LoadComplete() protected override bool Prioritised => true;
{
base.LoadComplete();
parentInputManager = GetContainingInputManager();
}
// IMPORTANT: Take care when changing order of the items in the enumerable. // IMPORTANT: Take care when changing order of the items in the enumerable.
// It is used to decide the order of precedence, with the earlier items having higher precedence. // It is used to decide the order of precedence, with the earlier items having higher precedence.
@ -161,20 +154,9 @@ protected override void LoadComplete()
new KeyBinding(InputKey.F3, GlobalAction.MusicPlay) new KeyBinding(InputKey.F3, GlobalAction.MusicPlay)
}; };
protected override IEnumerable<Drawable> KeyBindingInputQueue public bool OnPressed(KeyBindingPressEvent<GlobalAction> e) => handler?.OnPressed(e) == true;
{
get
{
// To ensure the global actions are handled with priority, this GlobalActionContainer is actually placed after game content.
// It does not contain children as expected, so we need to forward the NonPositionalInputQueue from the parent input manager to correctly
// allow the whole game to handle these actions.
// An eventual solution to this hack is to create localised action containers for individual components like SongSelect, but this will take some rearranging. public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) => handler?.OnReleased(e);
var inputQueue = parentInputManager?.NonPositionalInputQueue ?? base.KeyBindingInputQueue;
return handler != null ? inputQueue.Prepend(handler) : inputQueue;
}
}
} }
public enum GlobalAction public enum GlobalAction

View File

@ -392,17 +392,18 @@ private void load(ReadableKeyCombinationProvider keyCombinationProvider, Framewo
{ {
SafeAreaOverrideEdges = SafeAreaOverrideEdges, SafeAreaOverrideEdges = SafeAreaOverrideEdges,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = CreateScalingContainer().WithChildren(new Drawable[] Child = CreateScalingContainer().WithChild(globalBindings = new GlobalActionContainer(this)
{ {
(GlobalCursorDisplay = new GlobalCursorDisplay Children = new Drawable[]
{ {
RelativeSizeAxes = Axes.Both (GlobalCursorDisplay = new GlobalCursorDisplay
}).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) {
{ RelativeSizeAxes = Axes.Both
RelativeSizeAxes = Axes.Both }).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor)
}), {
// to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything. RelativeSizeAxes = Axes.Both
globalBindings = new GlobalActionContainer(this) }),
}
}) })
}); });

View File

@ -57,7 +57,13 @@ protected OsuManualInputManagerTestScene()
} }
if (CreateNestedActionContainer) if (CreateNestedActionContainer)
mainContent.Add(new GlobalActionContainer(null)); {
var globalActionContainer = new GlobalActionContainer(null)
{
Child = mainContent
};
mainContent = globalActionContainer;
}
base.Content.AddRange(new Drawable[] base.Content.AddRange(new Drawable[]
{ {