diff --git a/osu.Framework.Tests/Visual/Input/TestScenePassThroughInputManager.cs b/osu.Framework.Tests/Visual/Input/TestScenePassThroughInputManager.cs index 5893123a1f..e66cc72e4d 100644 --- a/osu.Framework.Tests/Visual/Input/TestScenePassThroughInputManager.cs +++ b/osu.Framework.Tests/Visual/Input/TestScenePassThroughInputManager.cs @@ -296,7 +296,11 @@ public void TestPenInputPassThrough() }); }); - AddStep("move pen to box", () => InputManager.MovePenTo(testInputManager)); + AddStep("move pen to box", () => InputManager.Input(new MousePositionAbsoluteInputFromPen + { + DeviceType = TabletPenDeviceType.Unknown, + Position = testInputManager.ScreenSpaceDrawQuad.Centre + })); AddAssert("ensure parent manager produced mouse", () => InputManager.CurrentState.Mouse.Position == testInputManager.ScreenSpaceDrawQuad.Centre); AddAssert("ensure pass-through produced mouse", () => testInputManager.CurrentState.Mouse.Position == testInputManager.ScreenSpaceDrawQuad.Centre); @@ -307,7 +311,10 @@ public void TestPenInputPassThrough() AddAssert("inner box received 1 pen event", () => inner.PenEvents, () => Is.EqualTo(1)); AddAssert("inner box received no mouse events", () => inner.MouseEvents, () => Is.EqualTo(0)); - AddStep("press pen", () => InputManager.PressPen()); + AddStep("press pen", () => InputManager.Input(new MouseButtonInputFromPen(true) + { + DeviceType = TabletPenDeviceType.Unknown, + })); AddAssert("ensure parent manager produced mouse", () => InputManager.CurrentState.Mouse.Buttons.Single() == MouseButton.Left); AddAssert("ensure pass-through produced mouse", () => testInputManager.CurrentState.Mouse.Buttons.Single() == MouseButton.Left); @@ -318,7 +325,10 @@ public void TestPenInputPassThrough() AddAssert("inner box received 2 pen events", () => inner.PenEvents, () => Is.EqualTo(2)); AddAssert("inner box received no mouse events", () => inner.MouseEvents, () => Is.EqualTo(0)); - AddStep("release pen", () => InputManager.ReleasePen()); + AddStep("release pen", () => InputManager.Input(new MouseButtonInputFromPen(false) + { + DeviceType = TabletPenDeviceType.Unknown, + })); AddAssert("ensure parent manager produced mouse", () => InputManager.CurrentState.Mouse.Buttons.HasAnyButtonPressed, () => Is.False); AddAssert("ensure pass-through produced mouse", () => testInputManager.CurrentState.Mouse.Buttons.HasAnyButtonPressed, () => Is.False); diff --git a/osu.Framework.Tests/Visual/Input/TestSceneTouchInput.cs b/osu.Framework.Tests/Visual/Input/TestSceneTouchInput.cs index 6e1e91d198..d87f0bcf2f 100644 --- a/osu.Framework.Tests/Visual/Input/TestSceneTouchInput.cs +++ b/osu.Framework.Tests/Visual/Input/TestSceneTouchInput.cs @@ -25,7 +25,7 @@ namespace osu.Framework.Tests.Visual.Input { public partial class TestSceneTouchInput : ManualInputManagerTestScene { - private static readonly TouchSource[] touch_sources = (TouchSource[])Enum.GetValues(typeof(TouchSource)); + private static readonly TouchSource[] touch_sources = Enum.GetValues().Take(10).ToArray(); private Container receptors; diff --git a/osu.Framework/Input/Handlers/Pen/PenHandler.cs b/osu.Framework/Input/Handlers/Pen/PenHandler.cs index 09df050a1c..bece39013f 100644 --- a/osu.Framework/Input/Handlers/Pen/PenHandler.cs +++ b/osu.Framework/Input/Handlers/Pen/PenHandler.cs @@ -31,13 +31,11 @@ public override bool Initialize(GameHost host) if (enabled.NewValue) { window.PenMove += handlePenMove; - window.PenTouch += handlePenTouch; window.PenButton += handlePenButton; } else { window.PenMove -= handlePenMove; - window.PenTouch -= handlePenTouch; window.PenButton -= handlePenButton; } }, true); @@ -58,11 +56,6 @@ private void handlePenMove(Vector2 position) }); } - private void handlePenTouch(bool pressed) - { - enqueueInput(new MouseButtonInputFromPen(pressed) { DeviceType = device_type }); - } - private void handlePenButton(TabletPenButton button, bool pressed) { enqueueInput(new TabletPenButtonInput(button, pressed)); diff --git a/osu.Framework/Input/States/TouchState.cs b/osu.Framework/Input/States/TouchState.cs index e99f9022ad..71556b6414 100644 --- a/osu.Framework/Input/States/TouchState.cs +++ b/osu.Framework/Input/States/TouchState.cs @@ -9,9 +9,14 @@ namespace osu.Framework.Input.States public class TouchState { /// - /// The maximum amount of touches this can handle. + /// The maximum amount of touches this can handle (excluding ). /// - public static readonly int MAX_TOUCH_COUNT = Enum.GetValues().Length; + public static readonly int MAX_TOUCH_COUNT = 10; + + /// + /// The maximum number of s. + /// + public static readonly int MAX_SOURCES_COUNT = Enum.GetValues().Length; /// /// The list of currently active touch sources. @@ -25,7 +30,7 @@ public class TouchState /// Using is recommended for retrieving /// logically correct values, as this may contain already stale values. /// - public readonly Vector2[] TouchPositions = new Vector2[MAX_TOUCH_COUNT]; + public readonly Vector2[] TouchPositions = new Vector2[MAX_SOURCES_COUNT]; /// /// Retrieves the current touch position of a specified . diff --git a/osu.Framework/Input/TouchSource.cs b/osu.Framework/Input/TouchSource.cs index f44942138a..5433200742 100644 --- a/osu.Framework/Input/TouchSource.cs +++ b/osu.Framework/Input/TouchSource.cs @@ -57,5 +57,10 @@ public enum TouchSource /// The tenth and last available touch source. /// Touch10, + + /// + /// A touch source that represents a pen/stylus. + /// + PenTouch, } } diff --git a/osu.Framework/Platform/SDL3/SDL3Window_Input.cs b/osu.Framework/Platform/SDL3/SDL3Window_Input.cs index 420ad1231a..c754090fa6 100644 --- a/osu.Framework/Platform/SDL3/SDL3Window_Input.cs +++ b/osu.Framework/Platform/SDL3/SDL3Window_Input.cs @@ -524,14 +524,29 @@ private void handleKeyboardEvent(SDL_KeyboardEvent evtKey) private void handleKeymapChangedEvent() => KeymapChanged?.Invoke(); + // pen input events should ultimately have its own input flow with code from InputManager to fall back to mouse input, + // but as the current structure of InputManager completely disallows that, synthesize touch input on pen events + // so it still works correctly for our use case (consider OsuTouchInputMapper in osu!). + private void handlePenMotionEvent(SDL_PenMotionEvent evtPenMotion) { - PenMove?.Invoke(new Vector2(evtPenMotion.x, evtPenMotion.y) * Scale); + var pos = new Vector2(evtPenMotion.x, evtPenMotion.y) * Scale; + + if (evtPenMotion.pen_state.HasFlagFast(SDL_PenInputFlags.SDL_PEN_INPUT_DOWN)) + TouchDown?.Invoke(new Touch(TouchSource.PenTouch, pos)); + else + PenMove?.Invoke(pos); } private void handlePenTouchEvent(SDL_PenTouchEvent evtPenTouch) { - PenTouch?.Invoke(evtPenTouch.down); + var pos = new Vector2(evtPenTouch.x, evtPenTouch.y) * Scale; + var touch = new Touch(TouchSource.PenTouch, pos); + + if (evtPenTouch.down) + TouchDown?.Invoke(touch); + else + TouchUp?.Invoke(touch); } /// @@ -741,11 +756,6 @@ private void updateConfineMode() /// public event Action? PenMove; - /// - /// Invoked when a pen touches (true) or lifts (false) from the tablet surface. - /// - public event Action? PenTouch; - /// /// Invoked when a pen button is pressed (true) or released (false). /// diff --git a/osu.Framework/Testing/Input/ManualInputManager.cs b/osu.Framework/Testing/Input/ManualInputManager.cs index 544b670440..4cb2d40827 100644 --- a/osu.Framework/Testing/Input/ManualInputManager.cs +++ b/osu.Framework/Testing/Input/ManualInputManager.cs @@ -128,12 +128,6 @@ public void Keys(PlatformAction action) public void MoveTouchTo(Touch touch) => Input(new TouchInput(touch, CurrentState.Touch.IsActive(touch.Source))); - public void MovePenTo(Drawable drawable, Vector2? offset = null, TabletPenDeviceType deviceType = TabletPenDeviceType.Unknown) - => MovePenTo(drawable.ToScreenSpace(drawable.LayoutRectangle.Centre) + (offset ?? Vector2.Zero), deviceType); - - public void MovePenTo(Vector2 position, TabletPenDeviceType deviceType = TabletPenDeviceType.Unknown) - => Input(new MousePositionAbsoluteInputFromPen { Position = position, DeviceType = deviceType }); - public new bool TriggerClick() => throw new InvalidOperationException($"To trigger a click via a {nameof(ManualInputManager)} use {nameof(Click)} instead."); @@ -171,9 +165,6 @@ public void Click(MouseButton button) public void PressMidiKey(MidiKey key, byte velocity) => Input(new MidiKeyInput(key, velocity, true)); public void ReleaseMidiKey(MidiKey key, byte velocity) => Input(new MidiKeyInput(key, velocity, false)); - public void PressPen(TabletPenDeviceType deviceType = TabletPenDeviceType.Unknown) => Input(new MouseButtonInputFromPen(true) { DeviceType = deviceType }); - public void ReleasePen(TabletPenDeviceType deviceType = TabletPenDeviceType.Unknown) => Input(new MouseButtonInputFromPen(false) { DeviceType = deviceType }); - public void PressTabletPenButton(TabletPenButton penButton) => Input(new TabletPenButtonInput(penButton, true)); public void ReleaseTabletPenButton(TabletPenButton penButton) => Input(new TabletPenButtonInput(penButton, false));