1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-13 20:33:35 +08:00

Fix song select dropdowns not being navigable with keyboard (#37158)

- Closes https://github.com/ppy/osu/issues/31684

Uses the global action variant of up and down for dropdown menus. It is
already used in multiplayer/playlist room/beatmap navigation and
gameplay menu overlays.

Comment wording is derived from:

https://github.com/ppy/osu/blob/fc817627e56b7db1c46e2f00fc9a3bd14af51211/osu.Game/Graphics/UserInterface/FocusedTextBox.cs#L73-L74
This commit is contained in:
Joseph Madamba
2026-04-01 04:59:47 -07:00
committed by GitHub
Unverified
parent 279effe23c
commit 556be552c3
2 changed files with 57 additions and 1 deletions
@@ -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<OsuLogo>().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<ShearedDropdown<SortMode>>().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<ShearedDropdown<SortMode>>().Single().Current.Value, () => Is.EqualTo(SortMode.Length));
AddAssert("beatmap not changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(firstBeatmap));
}
#endregion
#region Footer
+30 -1
View File
@@ -54,7 +54,7 @@ namespace osu.Game.Graphics.UserInterface
#region OsuDropdownMenu
public partial class OsuDropdownMenu : DropdownMenu
public partial class OsuDropdownMenu : DropdownMenu, IKeyBindingHandler<GlobalAction>
{
public override bool HandleNonPositionalInput => State == MenuState.Open;
@@ -163,6 +163,35 @@ namespace osu.Game.Graphics.UserInterface
protected override ScrollContainer<Drawable> CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction);
public bool OnPressed(KeyBindingPressEvent<GlobalAction> 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<GlobalAction> e)
{
}
#region DrawableOsuDropdownMenuItem
public partial class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem