Merge pull request #3739 from UselessToucan/fix_idle_tracker

Fix idle tracker
This commit is contained in:
Dean Herbert 2018-11-26 17:54:20 +09:00 committed by GitHub
commit 1ddb98e409
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 226 additions and 4 deletions

View File

@ -0,0 +1,135 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Input;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual
{
[TestFixture]
public class TestCaseIdleTracker : ManualInputManagerTestCase
{
private readonly IdleTrackingBox box1;
private readonly IdleTrackingBox box2;
private readonly IdleTrackingBox box3;
private readonly IdleTrackingBox box4;
public TestCaseIdleTracker()
{
Children = new Drawable[]
{
box1 = new IdleTrackingBox(1000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Red,
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
},
box2 = new IdleTrackingBox(2000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Green,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
},
box3 = new IdleTrackingBox(3000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Blue,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
},
box4 = new IdleTrackingBox(4000)
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Orange,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
},
};
}
[Test]
public void TestNudge()
{
AddStep("move mouse to top left", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre));
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle");
AddStep("nudge mouse", () => InputManager.MoveMouseTo(box1.ScreenSpaceDrawQuad.Centre + new Vector2(1)));
AddAssert("check not idle", () => !box1.IsIdle);
AddAssert("check idle", () => box2.IsIdle);
AddAssert("check idle", () => box3.IsIdle);
AddAssert("check idle", () => box4.IsIdle);
}
[Test]
public void TestMovement()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(box2.ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => box1.IsIdle);
AddAssert("check not idle", () => !box2.IsIdle);
AddAssert("check idle", () => box3.IsIdle);
AddAssert("check idle", () => box4.IsIdle);
AddStep("move mouse", () => InputManager.MoveMouseTo(box3.ScreenSpaceDrawQuad.Centre));
AddStep("move mouse", () => InputManager.MoveMouseTo(box4.ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => box1.IsIdle);
AddAssert("check not idle", () => !box2.IsIdle);
AddAssert("check idle", () => !box3.IsIdle);
AddAssert("check idle", () => !box4.IsIdle);
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle");
}
[Test]
public void TestTimings()
{
AddStep("move mouse", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.Centre));
AddAssert("check not idle", () => !box1.IsIdle && !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box1.IsIdle, "Wait for idle");
AddAssert("check not idle", () => !box2.IsIdle && !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box2.IsIdle, "Wait for idle");
AddAssert("check not idle", () => !box3.IsIdle && !box4.IsIdle);
AddUntilStep(() => box3.IsIdle, "Wait for idle");
AddUntilStep(() => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle, "Wait for all idle");
}
private class IdleTrackingBox : CompositeDrawable
{
private readonly IdleTracker idleTracker;
public bool IsIdle => idleTracker.IsIdle.Value;
public IdleTrackingBox(double timeToIdle)
{
Box box;
Alpha = 0.6f;
Scale = new Vector2(0.6f);
InternalChildren = new Drawable[]
{
idleTracker = new IdleTracker(timeToIdle),
box = new Box
{
Colour = Color4.White,
RelativeSizeAxes = Axes.Both,
},
};
idleTracker.IsIdle.BindValueChanged(idle => box.Colour = idle ? Color4.White : Color4.Black, true);
}
}
}
}

View File

@ -0,0 +1,71 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
namespace osu.Game.Input
{
/// <summary>
/// Track whether the end-user is in an idle state, based on their last interaction with the game.
/// </summary>
public class IdleTracker : Component, IKeyBindingHandler<PlatformAction>, IHandleGlobalInput
{
private readonly double timeToIdle;
private double lastInteractionTime;
protected double TimeSpentIdle => Clock.CurrentTime - lastInteractionTime;
/// <summary>
/// Whether the user is currently in an idle state.
/// </summary>
public IBindable<bool> IsIdle => isIdle;
private readonly BindableBool isIdle = new BindableBool();
/// <summary>
/// Intstantiate a new <see cref="IdleTracker"/>.
/// </summary>
/// <param name="timeToIdle">The length in milliseconds until an idle state should be assumed.</param>
public IdleTracker(double timeToIdle)
{
this.timeToIdle = timeToIdle;
RelativeSizeAxes = Axes.Both;
}
protected override void Update()
{
base.Update();
isIdle.Value = TimeSpentIdle > timeToIdle;
}
public bool OnPressed(PlatformAction action) => updateLastInteractionTime();
public bool OnReleased(PlatformAction action) => updateLastInteractionTime();
protected override bool Handle(UIEvent e)
{
switch (e)
{
case KeyDownEvent _:
case KeyUpEvent _:
case MouseDownEvent _:
case MouseUpEvent _:
case MouseMoveEvent _:
return updateLastInteractionTime();
default:
return base.Handle(e);
}
}
private bool updateLastInteractionTime()
{
lastInteractionTime = Clock.CurrentTime;
return false;
}
}
}

View File

@ -26,6 +26,7 @@
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
@ -88,6 +89,8 @@ private Intro intro
public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
private IdleTracker idleTracker;
public readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
private OsuScreen screenStack;
@ -316,6 +319,7 @@ protected override void LoadComplete()
},
mainContent = new Container { RelativeSizeAxes = Axes.Both },
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
idleTracker = new IdleTracker(6000)
});
loadComponentSingleFile(screenStack = new Loader(), d =>
@ -373,6 +377,7 @@ protected override void LoadComplete()
Depth = -6,
}, overlayContent.Add);
dependencies.Cache(idleTracker);
dependencies.Cache(settings);
dependencies.Cache(onscreenDisplay);
dependencies.Cache(social);

View File

@ -8,12 +8,14 @@
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Logging;
using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using osuTK;
@ -26,6 +28,8 @@ public class ButtonSystem : Container, IStateful<ButtonSystemState>, IKeyBinding
{
public event Action<ButtonSystemState> StateChanged;
private readonly IBindable<bool> isIdle = new BindableBool();
public Action OnEdit;
public Action OnExit;
public Action OnDirect;
@ -102,12 +106,22 @@ public ButtonSystem()
private OsuGame game;
[BackgroundDependencyLoader(true)]
private void load(AudioManager audio, OsuGame game)
private void load(AudioManager audio, OsuGame game, IdleTracker idleTracker)
{
this.game = game;
isIdle.ValueChanged += updateIdleState;
if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle);
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
}
private void updateIdleState(bool isIdle)
{
if (isIdle && State != ButtonSystemState.Exit)
State = ButtonSystemState.Initial;
}
public bool OnPressed(GlobalAction action)
{
switch (action)
@ -266,9 +280,6 @@ private void updateLogoState(ButtonSystemState lastState = ButtonSystemState.Ini
protected override void Update()
{
//if (OsuGame.IdleTime > 6000 && State != MenuState.Exit)
// State = MenuState.Initial;
base.Update();
if (logo != null)