Merge pull request #9370 from peppy/song-select-key-repeat

This commit is contained in:
Dean Herbert 2020-06-26 23:09:02 +09:00 committed by GitHub
commit a4254802c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 5 deletions

View File

@ -17,11 +17,12 @@ using osu.Game.Rulesets;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelect
{
[TestFixture]
public class TestSceneBeatmapCarousel : OsuTestScene
public class TestSceneBeatmapCarousel : OsuManualInputManagerTestScene
{
private TestBeatmapCarousel carousel;
private RulesetStore rulesets;
@ -39,6 +40,43 @@ namespace osu.Game.Tests.Visual.SongSelect
this.rulesets = rulesets;
}
[Test]
public void TestKeyRepeat()
{
loadBeatmaps();
advanceSelection(false);
AddStep("press down arrow", () => InputManager.PressKey(Key.Down));
BeatmapInfo selection = null;
checkSelectionIterating(true);
AddStep("press up arrow", () => InputManager.PressKey(Key.Up));
checkSelectionIterating(true);
AddStep("release down arrow", () => InputManager.ReleaseKey(Key.Down));
checkSelectionIterating(true);
AddStep("release up arrow", () => InputManager.ReleaseKey(Key.Up));
checkSelectionIterating(false);
void checkSelectionIterating(bool isIterating)
{
for (int i = 0; i < 3; i++)
{
AddStep("store selection", () => selection = carousel.SelectedBeatmap);
if (isIterating)
AddUntilStep("selection changed", () => carousel.SelectedBeatmap != selection);
else
AddUntilStep("selection not changed", () => carousel.SelectedBeatmap == selection);
}
}
}
[Test]
public void TestRecommendedSelection()
{

View File

@ -19,6 +19,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Input.Bindings;
@ -301,6 +302,9 @@ namespace osu.Game.Screens.Select
private void selectNextDifficulty(int direction)
{
if (selectedBeatmap == null)
return;
var unfilteredDifficulties = selectedBeatmapSet.Children.Where(s => !s.Filtered.Value).ToList();
int index = unfilteredDifficulties.IndexOf(selectedBeatmap);
@ -452,32 +456,49 @@ namespace osu.Game.Screens.Select
/// </summary>
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 +507,44 @@ namespace osu.Game.Screens.Select
public void OnReleased(GlobalAction action)
{
switch (action)
{
case GlobalAction.SelectNext:
case GlobalAction.SelectPrevious:
endRepeatSelection(action);
break;
}
}
private ScheduledDelegate repeatDelegate;
private object lastRepeatSource;
/// <summary>
/// Begin repeating the specified selection action.
/// </summary>
/// <param name="action">The action to perform.</param>
/// <param name="source">The source of the action. Used in conjunction with <see cref="endRepeatSelection"/> to only cancel the correct action (most recently pressed key).</param>
private void beginRepeatSelection(Action action, object source)
{
endRepeatSelection();
lastRepeatSource = source;
repeatDelegate = this.BeginKeyRepeat(Scheduler, action);
}
private void endRepeatSelection(object source = null)
{
// only the most recent source should be able to cancel the current action.
if (source != null && !EqualityComparer<object>.Default.Equals(lastRepeatSource, source))
return;
repeatDelegate?.Cancel();
repeatDelegate = null;
lastRepeatSource = null;
}
#endregion
protected override void Update()
{
base.Update();