From 980c900f43aa958e25d519e687a4a2e224d2399c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 30 Oct 2023 14:08:56 +0100 Subject: [PATCH] Add component for game-wide touch detection --- .../Navigation/TestSceneScreenNavigation.cs | 22 ++++++++++ osu.Game/Configuration/SessionStatics.cs | 10 ++++- osu.Game/Input/TouchInputInterceptor.cs | 41 +++++++++++++++++++ osu.Game/OsuGameBase.cs | 2 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Input/TouchInputInterceptor.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 9e743ef336..f4318da403 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -12,6 +12,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -835,6 +836,27 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("exit dialog is shown", () => Game.Dependencies.Get().CurrentDialog is ConfirmExitDialog); } + [Test] + public void TestTouchScreenDetection() + { + AddStep("touch logo", () => + { + var button = Game.ChildrenOfType().Single(); + var touch = new Touch(TouchSource.Touch1, button.ScreenSpaceDrawQuad.Centre); + InputManager.BeginTouch(touch); + InputManager.EndTouch(touch); + }); + AddAssert("touch screen detected active", () => Game.Dependencies.Get().Get(Static.TouchInputActive), () => Is.True); + + AddStep("click settings button", () => + { + var button = Game.ChildrenOfType().Last(); + InputManager.MoveMouseTo(button); + InputManager.Click(MouseButton.Left); + }); + AddAssert("touch screen detected inactive", () => Game.Dependencies.Get().Get(Static.TouchInputActive), () => Is.False); + } + private Func playToResults() { var player = playToCompletion(); diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 5e2f0c2128..0fc2076a7e 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Game.Graphics.UserInterface; +using osu.Game.Input; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Mods; @@ -24,6 +25,7 @@ namespace osu.Game.Configuration SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null); SetDefault(Static.LastModSelectPanelSamplePlaybackTime, (double?)null); SetDefault(Static.SeasonalBackgrounds, null); + SetDefault(Static.TouchInputActive, false); } /// @@ -63,6 +65,12 @@ namespace osu.Game.Configuration /// The last playback time in milliseconds of an on/off sample (from ). /// Used to debounce on/off sounds game-wide to avoid volume saturation, especially in activating mod presets with many mods. /// - LastModSelectPanelSamplePlaybackTime + LastModSelectPanelSamplePlaybackTime, + + /// + /// Whether the last positional input received was a touch input. + /// Used in touchscreen detection scenarios (). + /// + TouchInputActive, } } diff --git a/osu.Game/Input/TouchInputInterceptor.cs b/osu.Game/Input/TouchInputInterceptor.cs new file mode 100644 index 0000000000..377d3c6d9f --- /dev/null +++ b/osu.Game/Input/TouchInputInterceptor.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Input.Events; +using osu.Framework.Input.StateChanges; +using osu.Game.Configuration; +using osuTK; + +namespace osu.Game.Input +{ + /// + /// Intercepts all positional input events and sets the appropriate value + /// for consumption by particular game screens. + /// + public partial class TouchInputInterceptor : Component + { + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + + [Resolved] + private SessionStatics statics { get; set; } = null!; + + protected override bool Handle(UIEvent e) + { + switch (e) + { + case MouseEvent: + if (e.CurrentState.Mouse.LastSource is not ISourcedFromTouch) + statics.SetValue(Static.TouchInputActive, false); + break; + + case TouchEvent: + statics.SetValue(Static.TouchInputActive, true); + break; + } + + return false; + } + } +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 1f46eb0c0d..e4376d1c02 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -407,6 +407,8 @@ namespace osu.Game }) }); + base.Content.Add(new TouchInputInterceptor()); + KeyBindingStore = new RealmKeyBindingStore(realm, keyCombinationProvider); KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets);