Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,34 @@ public void TestTouchJudgedCircle()
checkPosition(TouchSource.Touch2);
}

[Test]
public void TestMousePositionPriority()
{
AddStep("move mouse and touch shortly after", () =>
{
InputManager.MoveMouseTo(getSanePositionForSource(TouchSource.Touch1));
InputManager.BeginTouch(new Touch(TouchSource.Touch2, getSanePositionForSource(TouchSource.Touch2)));
});

endTouch(TouchSource.Touch2);

checkPosition(TouchSource.Touch1);
}

[Test]
public void TestTouchInputPriorityAfterTimeout()
{
moveMouseTo(TouchSource.Touch1);
checkPosition(TouchSource.Touch1);

AddWaitStep("wait for mouse priority timeout to expire", 10);

beginTouch(TouchSource.Touch2);
endTouch(TouchSource.Touch2);

checkPosition(TouchSource.Touch2);
}

private void addHitCircleAt(TouchSource source)
{
AddStep($"Add circle at {source}", () =>
Expand All @@ -620,6 +648,9 @@ private void beginTouch(TouchSource source, Vector2? screenSpacePosition = null)
private void endTouch(TouchSource source, Vector2? screenSpacePosition = null) =>
AddStep($"Release touch for {source}", () => InputManager.EndTouch(new Touch(source, screenSpacePosition ??= getSanePositionForSource(source))));

private void moveMouseTo(TouchSource source) =>
AddStep($"Mouse mouse to {source} position", () => InputManager.MoveMouseTo(getSanePositionForSource(source)));

private Vector2 getSanePositionForSource(TouchSource source)
{
return new Vector2(
Expand Down
23 changes: 23 additions & 0 deletions osu.Game.Rulesets.Osu/OsuInputManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Input.StateChanges;
using osu.Framework.Lists;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Osu.Objects.Drawables;
Expand Down Expand Up @@ -60,13 +61,35 @@ private void load()
Add(new OsuTouchInputMapper(this) { RelativeSizeAxes = Axes.Both });
}

// see https://github.com/ppy/osu-framework/blob/0ee307ed781391e26d90199c6be6ad8b15a4fd9c/osu.Framework/Input/InputManager.cs#L538-L543
private const double mouse_move_debounce_time = 50;

private double? lastMouseMove;

private bool isRealMouseMoveEvent(UIEvent e) => e is MouseMoveEvent mouseMove
&& mouseMove.CurrentState.Mouse.Position != CurrentState.Mouse.Position // filter out IRequireHighFrequencyMousePosition events
&& mouseMove.CurrentState.Mouse.LastSource is not ISourcedFromTouch;

protected override bool Handle(UIEvent e)
{
if ((e is MouseMoveEvent || e is TouchMoveEvent) && !AllowUserCursorMovement) return false;

if (isRealMouseMoveEvent(e))
lastMouseMove = Clock.CurrentTime;

return base.Handle(e);
}

/// <summary>
/// Sets the cursor position from touch if it's allowed by the current state.
/// </summary>
/// <param name="position">The current position of a touch.</param>
internal void TrySetCursorPositionFromTouch(Vector2 position)
{
if (lastMouseMove == null || Clock.CurrentTime - lastMouseMove.Value > mouse_move_debounce_time)
new MousePositionAbsoluteInput { Position = position }.Apply(CurrentState, this);
Comment on lines +89 to +90
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignoring touch when there is a mouse event within the last 50 ms is fine (I would increase it to 100 ms). But what's even better is to check if a pen is hovering and ignore all touch input if so. SDL provides us with SDL_EVENT_PEN_PROXIMITY_IN and SDL_EVENT_PEN_PROXIMITY_OUT, but o!f is not currently handling those events.

Could have a global bool GameHost.IsPenDetected, similar to GameHost.OnScreenKeyboardOverlapsGameWindow.

}

private partial class OsuKeyBindingContainer : RulesetKeyBindingContainer
{
private bool allowGameplayInputs = true;
Expand Down
3 changes: 1 addition & 2 deletions osu.Game.Rulesets.Osu/UI/OsuTouchInputMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Framework.Input.StateChanges;
using osu.Game.Configuration;
using osuTK;

Expand Down Expand Up @@ -135,7 +134,7 @@ private void handleTouchMovement(TouchEvent touchEvent)
if (!osuInputManager.AllowUserCursorMovement)
return;

new MousePositionAbsoluteInput { Position = touchEvent.ScreenSpaceTouch.Position }.Apply(osuInputManager.CurrentState, osuInputManager);
osuInputManager.TrySetCursorPositionFromTouch(touchEvent.ScreenSpaceTouch.Position);
}

protected override void OnTouchUp(TouchUpEvent e)
Expand Down
Loading