diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index e174c46610..6611955cce 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -452,32 +452,49 @@ namespace osu.Game.Screens.Select
///
public void ScrollToSelected() => scrollPositionCache.Invalidate();
+ #region Key / button selection logic
+
protected override bool OnKeyDown(KeyDownEvent e)
{
switch (e.Key)
{
case Key.Left:
- SelectNext(-1, true);
+ if (!e.Repeat)
+ beginRepeatSelection(() => SelectNext(-1, true), e.Key);
return true;
case Key.Right:
- SelectNext(1, true);
+ if (!e.Repeat)
+ beginRepeatSelection(() => SelectNext(1, true), e.Key);
return true;
}
return false;
}
+ protected override void OnKeyUp(KeyUpEvent e)
+ {
+ switch (e.Key)
+ {
+ case Key.Left:
+ case Key.Right:
+ endRepeatSelection(e.Key);
+ break;
+ }
+
+ base.OnKeyUp(e);
+ }
+
public bool OnPressed(GlobalAction action)
{
switch (action)
{
case GlobalAction.SelectNext:
- SelectNext(1, false);
+ beginRepeatSelection(() => SelectNext(1, false), action);
return true;
case GlobalAction.SelectPrevious:
- SelectNext(-1, false);
+ beginRepeatSelection(() => SelectNext(-1, false), action);
return true;
}
@@ -486,8 +503,46 @@ namespace osu.Game.Screens.Select
public void OnReleased(GlobalAction action)
{
+ switch (action)
+ {
+ case GlobalAction.SelectNext:
+ case GlobalAction.SelectPrevious:
+ endRepeatSelection(action);
+ break;
+ }
}
+ private const double repeat_interval = 120;
+
+ private ScheduledDelegate repeatDelegate;
+ private object lastRepeatSource;
+
+ ///
+ /// Begin repeating the specified selection action.
+ ///
+ /// The action to perform.
+ /// The source of the action. Used in conjunction with to only cancel the correct action (most recently pressed key).
+ private void beginRepeatSelection(Action action, object source)
+ {
+ endRepeatSelection();
+
+ lastRepeatSource = source;
+ Scheduler.Add(repeatDelegate = new ScheduledDelegate(action, Time.Current, repeat_interval));
+ }
+
+ private void endRepeatSelection(object source = null)
+ {
+ // only the most recent source should be able to cancel the current action.
+ if (source != null && !EqualityComparer