Merge pull request #9194 from boswelja/rebind-song-select

Allow rebinding Song Select mods/random/options keys
This commit is contained in:
Dan Balasescu 2021-04-07 20:55:45 +09:00 committed by GitHub
commit 6eb809f4c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 157 additions and 66 deletions

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Tests
get get
{ {
if (content == null) if (content == null)
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); base.Content.Add(content = new OsuInputManager(new OsuRuleset().RulesetInfo));
return content; return content;
} }

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
SetContents(() => new TaikoInputManager(new RulesetInfo { ID = 1 }) SetContents(() => new TaikoInputManager(new TaikoRuleset().RulesetInfo)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = new Container Child = new Container

View File

@ -0,0 +1,35 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
{
public class TestSceneSongSelectFooter : OsuManualInputManagerTestScene
{
public TestSceneSongSelectFooter()
{
AddStep("Create footer", () =>
{
Footer footer;
AddRange(new Drawable[]
{
footer = new Footer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
});
footer.AddButton(new FooterButtonMods(), null);
footer.AddButton(new FooterButtonRandom
{
NextRandom = () => { },
PreviousRandom = () => { },
}, null);
footer.AddButton(new FooterButtonOptions(), null);
});
}
}
}

View File

@ -64,12 +64,20 @@ namespace osu.Game.Input.Bindings
protected override void ReloadMappings() protected override void ReloadMappings()
{ {
var defaults = DefaultKeyBindings.ToList();
if (ruleset != null && !ruleset.ID.HasValue) if (ruleset != null && !ruleset.ID.HasValue)
// if the provided ruleset is not stored to the database, we have no way to retrieve custom bindings. // if the provided ruleset is not stored to the database, we have no way to retrieve custom bindings.
// fallback to defaults instead. // fallback to defaults instead.
KeyBindings = DefaultKeyBindings; KeyBindings = defaults;
else else
KeyBindings = store.Query(ruleset?.ID, variant).ToList(); {
KeyBindings = store.Query(ruleset?.ID, variant)
// this ordering is important to ensure that we read entries from the database in the order
// enforced by DefaultKeyBindings. allow for song select to handle actions that may otherwise
// have been eaten by the music controller due to query order.
.OrderBy(b => defaults.FindIndex(d => (int)d.Action == b.IntAction)).ToList();
}
} }
} }
} }

View File

@ -27,7 +27,11 @@ namespace osu.Game.Input.Bindings
handler = game; handler = game;
} }
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings.Concat(InGameKeyBindings).Concat(AudioControlKeyBindings).Concat(EditorKeyBindings); public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings
.Concat(EditorKeyBindings)
.Concat(InGameKeyBindings)
.Concat(SongSelectKeyBindings)
.Concat(AudioControlKeyBindings);
public IEnumerable<KeyBinding> GlobalKeyBindings => new[] public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
{ {
@ -80,6 +84,14 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD),
}; };
public IEnumerable<KeyBinding> SongSelectKeyBindings => new[]
{
new KeyBinding(InputKey.F1, GlobalAction.ToggleModSelection),
new KeyBinding(InputKey.F2, GlobalAction.SelectNextRandom),
new KeyBinding(new[] { InputKey.Shift, InputKey.F2 }, GlobalAction.SelectPreviousRandom),
new KeyBinding(InputKey.F3, GlobalAction.ToggleBeatmapOptions)
};
public IEnumerable<KeyBinding> AudioControlKeyBindings => new[] public IEnumerable<KeyBinding> AudioControlKeyBindings => new[]
{ {
new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume), new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume),
@ -217,5 +229,18 @@ namespace osu.Game.Input.Bindings
[Description("Toggle in-game interface")] [Description("Toggle in-game interface")]
ToggleInGameInterface, ToggleInGameInterface,
// Song select keybindings
[Description("Toggle Mod Select")]
ToggleModSelection,
[Description("Random")]
SelectNextRandom,
[Description("Rewind")]
SelectPreviousRandom,
[Description("Beatmap Options")]
ToggleBeatmapOptions,
} }
} }

View File

@ -21,6 +21,7 @@ namespace osu.Game.Overlays.KeyBinding
{ {
Add(new DefaultBindingsSubsection(manager)); Add(new DefaultBindingsSubsection(manager));
Add(new AudioControlKeyBindingsSubsection(manager)); Add(new AudioControlKeyBindingsSubsection(manager));
Add(new SongSelectKeyBindingSubsection(manager));
Add(new InGameKeyBindingsSubsection(manager)); Add(new InGameKeyBindingsSubsection(manager));
Add(new EditorKeyBindingsSubsection(manager)); Add(new EditorKeyBindingsSubsection(manager));
} }
@ -36,6 +37,17 @@ namespace osu.Game.Overlays.KeyBinding
} }
} }
private class SongSelectKeyBindingSubsection : KeyBindingsSubsection
{
protected override string Header => "Song Select";
public SongSelectKeyBindingSubsection(GlobalActionContainer manager)
: base(null)
{
Defaults = manager.SongSelectKeyBindings;
}
}
private class InGameKeyBindingsSubsection : KeyBindingsSubsection private class InGameKeyBindingsSubsection : KeyBindingsSubsection
{ {
protected override string Header => "In Game"; protected override string Header => "In Game";

View File

@ -4,7 +4,6 @@
using System; using System;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -13,10 +12,12 @@ using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
using osu.Framework.Input.Bindings;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
public class FooterButton : OsuClickableContainer public class FooterButton : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
{ {
public const float SHEAR_WIDTH = 7.5f; public const float SHEAR_WIDTH = 7.5f;
@ -105,6 +106,7 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = SpriteText = new OsuSpriteText Child = SpriteText = new OsuSpriteText
{ {
AlwaysPresent = true,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
} }
@ -118,7 +120,7 @@ namespace osu.Game.Screens.Select
public Action Hovered; public Action Hovered;
public Action HoverLost; public Action HoverLost;
public Key? Hotkey; public GlobalAction? Hotkey;
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
{ {
@ -168,15 +170,17 @@ namespace osu.Game.Screens.Select
return base.OnClick(e); return base.OnClick(e);
} }
protected override bool OnKeyDown(KeyDownEvent e) public virtual bool OnPressed(GlobalAction action)
{ {
if (!e.Repeat && e.Key == Hotkey) if (action == Hotkey)
{ {
Click(); Click();
return true; return true;
} }
return base.OnKeyDown(e); return false;
} }
public virtual void OnReleased(GlobalAction action) { }
} }
} }

View File

@ -14,7 +14,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input; using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -57,7 +57,7 @@ namespace osu.Game.Screens.Select
lowMultiplierColour = colours.Red; lowMultiplierColour = colours.Red;
highMultiplierColour = colours.Green; highMultiplierColour = colours.Green;
Text = @"mods"; Text = @"mods";
Hotkey = Key.F1; Hotkey = GlobalAction.ToggleModSelection;
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -4,7 +4,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics; using osu.Game.Graphics;
using osuTK.Input; using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select
SelectedColour = colours.Blue; SelectedColour = colours.Blue;
DeselectedColour = SelectedColour.Opacity(0.5f); DeselectedColour = SelectedColour.Opacity(0.5f);
Text = @"options"; Text = @"options";
Hotkey = Key.F3; Hotkey = GlobalAction.ToggleBeatmapOptions;
} }
} }
} }

View File

@ -1,35 +1,23 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK.Input; using osu.Game.Input.Bindings;
using osuTK;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
public class FooterButtonRandom : FooterButton public class FooterButtonRandom : FooterButton
{ {
private readonly SpriteText secondaryText; public Action NextRandom { get; set; }
private bool secondaryActive; public Action PreviousRandom { get; set; }
public FooterButtonRandom() private bool rewindSearch;
{
TextContainer.Add(secondaryText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = @"rewind",
Alpha = 0,
});
// force both text sprites to always be present to avoid width flickering while they're being swapped out
SpriteText.AlwaysPresent = secondaryText.AlwaysPresent = true;
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
@ -37,34 +25,57 @@ namespace osu.Game.Screens.Select
SelectedColour = colours.Green; SelectedColour = colours.Green;
DeselectedColour = SelectedColour.Opacity(0.5f); DeselectedColour = SelectedColour.Opacity(0.5f);
Text = @"random"; Text = @"random";
Hotkey = Key.F2;
}
protected override bool OnKeyDown(KeyDownEvent e) Action = () =>
{ {
secondaryActive = e.ShiftPressed; if (rewindSearch)
updateText(); {
return base.OnKeyDown(e); const double fade_time = 500;
}
protected override void OnKeyUp(KeyUpEvent e) OsuSpriteText rewindSpriteText;
{
secondaryActive = e.ShiftPressed;
updateText();
base.OnKeyUp(e);
}
private void updateText() TextContainer.Add(rewindSpriteText = new OsuSpriteText
{ {
if (secondaryActive) Alpha = 0,
{ Text = @"rewind",
SpriteText.FadeOut(120, Easing.InQuad); AlwaysPresent = true, // make sure the button is sized large enough to always show this
secondaryText.FadeIn(120, Easing.InQuad); Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
rewindSpriteText.FadeOutFromOne(fade_time, Easing.In);
rewindSpriteText.MoveTo(Vector2.Zero).MoveTo(new Vector2(0, 10), fade_time, Easing.In);
rewindSpriteText.Expire();
SpriteText.FadeInFromZero(fade_time, Easing.In);
PreviousRandom.Invoke();
} }
else else
{ {
SpriteText.FadeIn(120, Easing.InQuad); NextRandom.Invoke();
secondaryText.FadeOut(120, Easing.InQuad); }
};
}
public override bool OnPressed(GlobalAction action)
{
rewindSearch = action == GlobalAction.SelectPreviousRandom;
if (action != GlobalAction.SelectNextRandom && action != GlobalAction.SelectPreviousRandom)
{
return false;
}
Click();
return true;
}
public override void OnReleased(GlobalAction action)
{
if (action == GlobalAction.SelectPreviousRandom)
{
rewindSearch = false;
} }
} }
} }

View File

@ -307,7 +307,11 @@ namespace osu.Game.Screens.Select
protected virtual IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() => new (FooterButton, OverlayContainer)[] protected virtual IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() => new (FooterButton, OverlayContainer)[]
{ {
(new FooterButtonMods { Current = Mods }, ModSelect), (new FooterButtonMods { Current = Mods }, ModSelect),
(new FooterButtonRandom { Action = triggerRandom }, null), (new FooterButtonRandom
{
NextRandom = () => Carousel.SelectNextRandom(),
PreviousRandom = Carousel.SelectPreviousRandom
}, null),
(new FooterButtonOptions(), BeatmapOptions) (new FooterButtonOptions(), BeatmapOptions)
}; };
@ -522,14 +526,6 @@ namespace osu.Game.Screens.Select
} }
} }
private void triggerRandom()
{
if (GetContainingInputManager().CurrentState.Keyboard.ShiftPressed)
Carousel.SelectPreviousRandom();
else
Carousel.SelectNextRandom();
}
public override void OnEntering(IScreen last) public override void OnEntering(IScreen last)
{ {
base.OnEntering(last); base.OnEntering(last);