diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 521d097fb9..88b482ab4c 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -48,6 +48,7 @@ using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Options; using osu.Game.Tests.Beatmaps.IO; +using osu.Game.Tests.Resources; using osu.Game.Utils; using osuTK; using osuTK.Input; @@ -202,6 +203,38 @@ namespace osu.Game.Tests.Visual.Navigation TextBox filterControlTextBox() => songSelect.ChildrenOfType().Single(); } + [Test] + public void TestSongSelectRandomRewindButton() + { + Guid? originalSelection = null; + TestPlaySongSelect songSelect = null; + + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); + + AddStep("Add two beatmaps", () => + { + Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo(8)); + Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo(8)); + }); + + AddUntilStep("wait for selected", () => + { + originalSelection = Game.Beatmap.Value.BeatmapInfo.ID; + return !Game.Beatmap.IsDefault; + }); + + AddStep("hit random", () => + { + InputManager.MoveMouseTo(Game.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("wait for selection changed", () => Game.Beatmap.Value.BeatmapInfo.ID, () => Is.Not.EqualTo(originalSelection)); + + AddStep("hit random rewind", () => InputManager.Click(MouseButton.Right)); + AddUntilStep("wait for selection reverted", () => Game.Beatmap.Value.BeatmapInfo.ID, () => Is.EqualTo(originalSelection)); + } + [Test] public void TestSongSelectScrollHandling() { diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index e1b8de89fa..f0f5864e32 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -97,8 +97,9 @@ namespace osu.Game.Database /// 44 2024-11-22 Removed several properties from BeatmapInfo which did not need to be persisted to realm. /// 45 2024-12-23 Change beat snap divisor adjust defaults to be Ctrl+Scroll instead of Ctrl+Shift+Scroll, if not already changed by user. /// 46 2024-12-26 Change beat snap divisor bindings to match stable directionality ¯\_(ツ)_/¯. + /// 47 2025-01-21 Remove right mouse button binding for absolute scroll. Never use mouse buttons (or scroll) for global actions. /// - private const int schema_version = 46; + private const int schema_version = 47; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. @@ -1239,6 +1240,17 @@ namespace osu.Game.Database break; } + + case 47: + { + var keyBindings = migration.NewRealm.All(); + + var existingBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.AbsoluteScrollSongList); + if (existingBinding != null && existingBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.MouseRight })) + migration.NewRealm.Remove(existingBinding); + + break; + } } Logger.Log($"Migration completed in {stopwatch.ElapsedMilliseconds}ms"); diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 6c130ff309..599ca6d6c1 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -205,7 +205,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.BackSpace, GlobalAction.DeselectAllMods), new KeyBinding(new[] { InputKey.Control, InputKey.Up }, GlobalAction.IncreaseModSpeed), new KeyBinding(new[] { InputKey.Control, InputKey.Down }, GlobalAction.DecreaseModSpeed), - new KeyBinding(new[] { InputKey.MouseRight }, GlobalAction.AbsoluteScrollSongList), + new KeyBinding(InputKey.None, GlobalAction.AbsoluteScrollSongList), }; private static IEnumerable audioControlKeyBindings => new[] diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 7e3c26a1ba..a807fc6a34 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -1181,14 +1181,7 @@ namespace osu.Game.Screens.Select switch (e.Action) { case GlobalAction.AbsoluteScrollSongList: - // The default binding for absolute scroll is right mouse button. - // To avoid conflicts with context menus, disallow absolute scroll completely if it looks like things will fall over. - if (e.CurrentState.Mouse.Buttons.Contains(MouseButton.Right) - && GetContainingInputManager()!.HoveredDrawables.OfType().Any()) - return false; - - ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); - absoluteScrolling = true; + beginAbsoluteScrolling(e); return true; } @@ -1200,11 +1193,32 @@ namespace osu.Game.Screens.Select switch (e.Action) { case GlobalAction.AbsoluteScrollSongList: - absoluteScrolling = false; + endAbsoluteScrolling(); break; } } + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.Button == MouseButton.Right) + { + // To avoid conflicts with context menus, disallow absolute scroll if it looks like things will fall over. + if (GetContainingInputManager()!.HoveredDrawables.OfType().Any()) + return false; + + beginAbsoluteScrolling(e); + } + + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (e.Button == MouseButton.Right) + endAbsoluteScrolling(); + base.OnMouseUp(e); + } + protected override bool OnMouseMove(MouseMoveEvent e) { if (absoluteScrolling) @@ -1216,6 +1230,14 @@ namespace osu.Game.Screens.Select return base.OnMouseMove(e); } + private void beginAbsoluteScrolling(UIEvent e) + { + ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); + absoluteScrolling = true; + } + + private void endAbsoluteScrolling() => absoluteScrolling = false; + #endregion protected override ScrollbarContainer CreateScrollbar(Direction direction) diff --git a/osu.Game/Screens/SelectV2/Carousel.cs b/osu.Game/Screens/SelectV2/Carousel.cs index a07022b32f..ec1bf6b7c0 100644 --- a/osu.Game/Screens/SelectV2/Carousel.cs +++ b/osu.Game/Screens/SelectV2/Carousel.cs @@ -493,15 +493,7 @@ namespace osu.Game.Screens.SelectV2 switch (e.Action) { case GlobalAction.AbsoluteScrollSongList: - - // The default binding for absolute scroll is right mouse button. - // To avoid conflicts with context menus, disallow absolute scroll completely if it looks like things will fall over. - if (e.CurrentState.Mouse.Buttons.Contains(MouseButton.Right) - && GetContainingInputManager()!.HoveredDrawables.OfType().Any()) - return false; - - ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); - absoluteScrolling = true; + beginAbsoluteScrolling(e); return true; } @@ -513,11 +505,32 @@ namespace osu.Game.Screens.SelectV2 switch (e.Action) { case GlobalAction.AbsoluteScrollSongList: - absoluteScrolling = false; + endAbsoluteScrolling(); break; } } + protected override bool OnMouseDown(MouseDownEvent e) + { + if (e.Button == MouseButton.Right) + { + // To avoid conflicts with context menus, disallow absolute scroll if it looks like things will fall over. + if (GetContainingInputManager()!.HoveredDrawables.OfType().Any()) + return false; + + beginAbsoluteScrolling(e); + } + + return base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (e.Button == MouseButton.Right) + endAbsoluteScrolling(); + base.OnMouseUp(e); + } + protected override bool OnMouseMove(MouseMoveEvent e) { if (absoluteScrolling) @@ -529,6 +542,14 @@ namespace osu.Game.Screens.SelectV2 return base.OnMouseMove(e); } + private void beginAbsoluteScrolling(UIEvent e) + { + ScrollToAbsolutePosition(e.CurrentState.Mouse.Position); + absoluteScrolling = true; + } + + private void endAbsoluteScrolling() => absoluteScrolling = false; + #endregion }