diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs index 6eddc8e1d8..24f3255b17 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelect.cs @@ -11,6 +11,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Mods; @@ -23,6 +24,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.Leaderboards; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; +using osu.Game.Screens.Select.Filter; using osu.Game.Tests.Resources; using osuTK.Input; using BeatmapCarousel = osu.Game.Screens.Select.BeatmapCarousel; @@ -430,6 +432,31 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("osu! cookie visible", () => this.ChildrenOfType().Single().Alpha, () => Is.Not.Zero); } + [Test] + public void TestDropdownKeyboardNavigation() + { + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + + BeatmapInfo? firstBeatmap = null; + AddStep("store first difficulty", () => firstBeatmap = Beatmap.Value.BeatmapInfo); + + AddStep("click sort dropdown", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType>().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddStep("press up arrow", () => InputManager.Key(Key.Up)); + AddStep("press up arrow", () => InputManager.Key(Key.Up)); + + AddStep("press enter", () => InputManager.Key(Key.Enter)); + + AddAssert("sort mode is length", () => this.ChildrenOfType>().Single().Current.Value, () => Is.EqualTo(SortMode.Length)); + AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(firstBeatmap)); + } + #endregion #region Footer diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index bbc826a7a7..16f5ab2a8b 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -54,7 +54,7 @@ namespace osu.Game.Graphics.UserInterface #region OsuDropdownMenu - public partial class OsuDropdownMenu : DropdownMenu + public partial class OsuDropdownMenu : DropdownMenu, IKeyBindingHandler { public override bool HandleNonPositionalInput => State == MenuState.Open; @@ -163,6 +163,35 @@ namespace osu.Game.Graphics.UserInterface protected override ScrollContainer CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction); + public bool OnPressed(KeyBindingPressEvent e) + { + // logic copied from https://github.com/ppy/osu-framework/blob/baf865f1fd9e677310e7e432a7c6af99db7db914/osu.Framework/Graphics/UserInterface/Dropdown.cs#L702-L717 + var visibleMenuItemsList = VisibleMenuItems.ToList(); + + if (visibleMenuItemsList.Count > 0) + { + var currentPreselected = PreselectedItem; + int targetPreselectionIndex = visibleMenuItemsList.IndexOf(currentPreselected); + + switch (e.Action) + { + case GlobalAction.SelectPrevious: + PreselectItem(targetPreselectionIndex - 1); + return true; + + case GlobalAction.SelectNext: + PreselectItem(targetPreselectionIndex + 1); + return true; + } + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + #region DrawableOsuDropdownMenuItem public partial class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem