-
Notifications
You must be signed in to change notification settings - Fork 425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bring back SDL2 by default, lock SDL3 behind environment variable #6292
Conversation
Using `using SDL.SDL3` to fix namespace conflicts.
Edit: Nevermind, I think I was thinking about a prior version of my changes. Nothing's actually changed in this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested to boot fine on Android, and Windows SDL2 & SDL3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Readable key combinations don't work on SDL2. Can be easily fixed in an ugly way as the SDL3 and SDL2 enums are compatible.
diff --git a/osu.Framework/Platform/SDL3/SDL3ReadableKeyCombinationProvider.cs b/osu.Framework/Platform/SDL3/SDL3ReadableKeyCombinationProvider.cs
index 126a73e56..9d8d81dab 100644
--- a/osu.Framework/Platform/SDL3/SDL3ReadableKeyCombinationProvider.cs
+++ b/osu.Framework/Platform/SDL3/SDL3ReadableKeyCombinationProvider.cs
@@ -11,9 +11,25 @@ namespace osu.Framework.Platform.SDL3
{
public class SDL3ReadableKeyCombinationProvider : ReadableKeyCombinationProvider
{
+ private static SDL_Keycode getKeyFromScancode(SDL_Scancode scancode)
+ {
+ if (FrameworkEnvironment.UseSDL3)
+ return SDL_GetKeyFromScancode(scancode);
+
+ return (SDL_Keycode)global::SDL2.SDL.SDL_GetKeyFromScancode((global::SDL2.SDL.SDL_Scancode)scancode);
+ }
+
+ private static string? getKeyName(SDL_Keycode keycode)
+ {
+ if (FrameworkEnvironment.UseSDL3)
+ return SDL_GetKeyName(keycode);
+
+ return global::SDL2.SDL.SDL_GetKeyName((global::SDL2.SDL.SDL_Keycode)keycode);
+ }
+
protected override string GetReadableKey(InputKey key)
{
- var keycode = SDL_GetKeyFromScancode(key.ToScancode());
+ var keycode = getKeyFromScancode(key.ToScancode());
// early return if unknown. probably because key isn't a keyboard key, or doesn't map to an `SDL_Scancode`.
if (keycode == SDL_Keycode.SDLK_UNKNOWN)
@@ -25,7 +41,7 @@ protected override string GetReadableKey(InputKey key)
if (TryGetNameFromKeycode(keycode, out name))
return name;
- name = SDL_GetKeyName(keycode);
+ name = getKeyName(keycode);
// fall back if SDL couldn't find a name.
if (string.IsNullOrEmpty(name))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Although it's a bit messy, I think this is fine for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be split into multiple files containing the same partial class. Makes removal easier and better separates the SDL2 and generic implementation. (Plus the future SDL3 impl for #6291.)
The SDL2 impl should then use window is (not) SDL2WindowsWindow
:-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto for Native.Input
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried to do this in 6f0702a, I hope it's what you intended as I'm unsure whether the wndproc handler can truly be shared between the two so I just assumed that it can.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Native.Input
isn't sdl2/sdl3 specific and it's internal
. I'm trying to avoid making too many changes and just followed the two steps in the PR description that can be verified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wndproc handler doesn't work for raw input on windows. I meant to split out the code so that the SDL2 part can just be deleted. Best illustrated by the below diff. With it, the changes of WindowsMouseHandler.cs
relative to master
is the smallest. There's no SDL3 code yet so that partial is removed.
Expected final diff to master:
diff --git a/osu.Framework/Platform/Windows/WindowsMouseHandler.cs b/osu.Framework/Platform/Windows/WindowsMouseHandler.cs
index b74535b78..4abe150a6 100644
--- a/osu.Framework/Platform/Windows/WindowsMouseHandler.cs
+++ b/osu.Framework/Platform/Windows/WindowsMouseHandler.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Runtime.Versioning;
@@ -12,16 +12,22 @@ namespace osu.Framework.Platform.Windows
/// This is done to better handle quirks of some devices.
/// </summary>
[SupportedOSPlatform("windows")]
- internal class WindowsMouseHandler : MouseHandler
+ internal partial class WindowsMouseHandler : MouseHandler
{
- private WindowsWindow window = null!;
+ private IWindowsWindow window = null!;
+
+ public override bool IsActive => Enabled.Value;
public override bool Initialize(GameHost host)
{
- if (!(host.Window is WindowsWindow desktopWindow))
+ if (host.Window is not IWindowsWindow windowsWindow)
return false;
- window = desktopWindow;
+ window = windowsWindow;
+
+ if (window is SDL2WindowsWindow)
+ initialiseSDL2(host);
+
return base.Initialize(host);
}
Diff
diff --git a/osu.Framework/Platform/Windows/WindowsMouseHandler.cs b/osu.Framework/Platform/Windows/WindowsMouseHandler.cs
index ef2cdcaad..4abe150a6 100644
--- a/osu.Framework/Platform/Windows/WindowsMouseHandler.cs
+++ b/osu.Framework/Platform/Windows/WindowsMouseHandler.cs
@@ -1,14 +1,8 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
-using System.Drawing;
using System.Runtime.Versioning;
-using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Input.Handlers.Mouse;
-using osu.Framework.Input.StateChanges;
-using osu.Framework.Platform.Windows.Native;
-using osu.Framework.Statistics;
using osuTK;
namespace osu.Framework.Platform.Windows
@@ -20,17 +14,7 @@ namespace osu.Framework.Platform.Windows
[SupportedOSPlatform("windows")]
internal partial class WindowsMouseHandler : MouseHandler
{
- private static readonly GlobalStatistic<ulong> statistic_relative_events = GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Relative events");
- private static readonly GlobalStatistic<ulong> statistic_absolute_events = GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Absolute events");
- private static readonly GlobalStatistic<ulong> statistic_dropped_touch_inputs = GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Dropped native touch inputs");
-
- private static readonly GlobalStatistic<ulong> statistic_inputs_with_extra_information =
- GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Native inputs with ExtraInformation");
-
- private const int raw_input_coordinate_space = 65535;
-
private IWindowsWindow window = null!;
- private bool handlerBound;
public override bool IsActive => Enabled.Value;
@@ -40,9 +24,9 @@ public override bool Initialize(GameHost host)
return false;
window = windowsWindow;
- handlerBound = window is SDL2WindowsWindow
- ? bindHandlerSDL2(host)
- : bindHandlerSDL3(host);
+
+ if (window is SDL2WindowsWindow)
+ initialiseSDL2(host);
return base.Initialize(host);
}
@@ -52,108 +36,5 @@ public override void FeedbackMousePositionChange(Vector2 position, bool isSelfFe
window.LastMousePosition = position;
base.FeedbackMousePositionChange(position, isSelfFeedback);
}
-
- protected override void HandleMouseMoveRelative(Vector2 delta)
- {
- if (handlerBound)
- {
- // When bound, relative movement is reported via the WndProc handler below.
- return;
- }
-
- base.HandleMouseMoveRelative(delta);
- }
-
- private unsafe IntPtr onWndProcSDL2(IntPtr userData, IntPtr hWnd, uint message, ulong wParam, long lParam)
- {
- if (!Enabled.Value)
- return IntPtr.Zero;
-
- if (message != Native.Input.WM_INPUT)
- return IntPtr.Zero;
-
- if (Native.Input.IsTouchEvent(Native.Input.GetMessageExtraInfo()))
- {
- // sometimes GetMessageExtraInfo returns 0, so additionally, mouse.ExtraInformation is checked below.
- // touch events are handled by TouchHandler
- statistic_dropped_touch_inputs.Value++;
- return IntPtr.Zero;
- }
-
- int payloadSize = sizeof(RawInputData);
-
- Native.Input.GetRawInputData((IntPtr)lParam, RawInputCommand.Input, out var data, ref payloadSize, sizeof(RawInputHeader));
-
- if (data.Header.Type != RawInputType.Mouse)
- return IntPtr.Zero;
-
- var mouse = data.Mouse;
-
- // `ExtraInformation` doesn't have the MI_WP_SIGNATURE set, so we have to rely solely on the touch flag.
- if (Native.Input.HasTouchFlag(mouse.ExtraInformation))
- {
- statistic_dropped_touch_inputs.Value++;
- return IntPtr.Zero;
- }
-
- //TODO: this isn't correct.
- if (mouse.ExtraInformation > 0)
- {
- statistic_inputs_with_extra_information.Value++;
-
- // i'm not sure if there is a valid case where we need to handle packets with this present
- // but the osu!tablet fires noise events with non-zero values, which we want to ignore.
- // return IntPtr.Zero;
- }
-
- var position = new Vector2(mouse.LastX, mouse.LastY);
- float sensitivity = (float)Sensitivity.Value;
-
- if (mouse.Flags.HasFlagFast(RawMouseFlags.MoveAbsolute))
- {
- var screenRect = mouse.Flags.HasFlagFast(RawMouseFlags.VirtualDesktop) ? Native.Input.VirtualScreenRect : new Rectangle(window.Position, window.ClientSize);
-
- Vector2 screenSize = new Vector2(screenRect.Width, screenRect.Height);
-
- if (mouse.LastX == 0 && mouse.LastY == 0)
- {
- // not sure if this is the case for all tablets, but on osu!tablet these can appear and are noise.
- return IntPtr.Zero;
- }
-
- // i am not sure what this 64 flag is, but it's set on the osu!tablet at very least.
- // using it here as a method of determining where the coordinate space is incorrect.
- if (((int)mouse.Flags & 64) == 0)
- {
- position /= raw_input_coordinate_space;
- position *= screenSize;
- }
-
- if (Sensitivity.Value != 1)
- {
- // apply absolute sensitivity adjustment from the centre of the screen area.
- Vector2 halfScreenSize = (screenSize / 2);
-
- position -= halfScreenSize;
- position *= (float)Sensitivity.Value;
- position += halfScreenSize;
- }
-
- // map from screen to client coordinate space.
- // not using Window's PointToClient implementation to keep floating point precision here.
- position -= new Vector2(window.Position.X, window.Position.Y);
- position *= window.Scale;
-
- PendingInputs.Enqueue(new MousePositionAbsoluteInput { Position = position });
- statistic_absolute_events.Value++;
- }
- else
- {
- PendingInputs.Enqueue(new MousePositionRelativeInput { Delta = new Vector2(mouse.LastX, mouse.LastY) * sensitivity });
- statistic_relative_events.Value++;
- }
-
- return IntPtr.Zero;
- }
}
}
diff --git a/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL2.cs b/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL2.cs
index bd13d7b17..2d941ec17 100644
--- a/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL2.cs
+++ b/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL2.cs
@@ -2,15 +2,30 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Drawing;
+using osu.Framework.Extensions.EnumExtensions;
+using osu.Framework.Input.StateChanges;
+using osu.Framework.Platform.Windows.Native;
+using osu.Framework.Statistics;
+using osuTK;
using static SDL2.SDL;
namespace osu.Framework.Platform.Windows
{
internal partial class WindowsMouseHandler
{
+ private static readonly GlobalStatistic<ulong> statistic_relative_events = GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Relative events");
+ private static readonly GlobalStatistic<ulong> statistic_absolute_events = GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Absolute events");
+ private static readonly GlobalStatistic<ulong> statistic_dropped_touch_inputs = GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Dropped native touch inputs");
+
+ private static readonly GlobalStatistic<ulong> statistic_inputs_with_extra_information =
+ GlobalStatistics.Get<ulong>(StatisticGroupFor<WindowsMouseHandler>(), "Native inputs with ExtraInformation");
+
+ private const int raw_input_coordinate_space = 65535;
+
private SDL_WindowsMessageHook sdl2Callback = null!;
- private bool bindHandlerSDL2(GameHost host)
+ private void initialiseSDL2(GameHost host)
{
// ReSharper disable once ConvertClosureToMethodGroup
sdl2Callback = (ptr, wnd, u, param, l) => onWndProcSDL2(ptr, wnd, u, param, l);
@@ -19,8 +34,109 @@ private bool bindHandlerSDL2(GameHost host)
{
host.InputThread.Scheduler.Add(() => SDL_SetWindowsMessageHook(enabled.NewValue ? sdl2Callback : null, IntPtr.Zero));
}, true);
+ }
+
+ protected override void HandleMouseMoveRelative(Vector2 delta)
+ {
+ if (window is SDL2WindowsWindow)
+ {
+ // on SDL2, relative movement is reported via the WndProc handler below.
+ return;
+ }
+
+ base.HandleMouseMoveRelative(delta);
+ }
+
+ private unsafe IntPtr onWndProcSDL2(IntPtr userData, IntPtr hWnd, uint message, ulong wParam, long lParam)
+ {
+ if (!Enabled.Value)
+ return IntPtr.Zero;
+
+ if (message != Native.Input.WM_INPUT)
+ return IntPtr.Zero;
+
+ if (Native.Input.IsTouchEvent(Native.Input.GetMessageExtraInfo()))
+ {
+ // sometimes GetMessageExtraInfo returns 0, so additionally, mouse.ExtraInformation is checked below.
+ // touch events are handled by TouchHandler
+ statistic_dropped_touch_inputs.Value++;
+ return IntPtr.Zero;
+ }
+
+ int payloadSize = sizeof(RawInputData);
+
+ Native.Input.GetRawInputData((IntPtr)lParam, RawInputCommand.Input, out var data, ref payloadSize, sizeof(RawInputHeader));
+
+ if (data.Header.Type != RawInputType.Mouse)
+ return IntPtr.Zero;
+
+ var mouse = data.Mouse;
+
+ // `ExtraInformation` doesn't have the MI_WP_SIGNATURE set, so we have to rely solely on the touch flag.
+ if (Native.Input.HasTouchFlag(mouse.ExtraInformation))
+ {
+ statistic_dropped_touch_inputs.Value++;
+ return IntPtr.Zero;
+ }
+
+ //TODO: this isn't correct.
+ if (mouse.ExtraInformation > 0)
+ {
+ statistic_inputs_with_extra_information.Value++;
+
+ // i'm not sure if there is a valid case where we need to handle packets with this present
+ // but the osu!tablet fires noise events with non-zero values, which we want to ignore.
+ // return IntPtr.Zero;
+ }
+
+ var position = new Vector2(mouse.LastX, mouse.LastY);
+ float sensitivity = (float)Sensitivity.Value;
+
+ if (mouse.Flags.HasFlagFast(RawMouseFlags.MoveAbsolute))
+ {
+ var screenRect = mouse.Flags.HasFlagFast(RawMouseFlags.VirtualDesktop) ? Native.Input.VirtualScreenRect : new Rectangle(window.Position, window.ClientSize);
+
+ Vector2 screenSize = new Vector2(screenRect.Width, screenRect.Height);
+
+ if (mouse.LastX == 0 && mouse.LastY == 0)
+ {
+ // not sure if this is the case for all tablets, but on osu!tablet these can appear and are noise.
+ return IntPtr.Zero;
+ }
+
+ // i am not sure what this 64 flag is, but it's set on the osu!tablet at very least.
+ // using it here as a method of determining where the coordinate space is incorrect.
+ if (((int)mouse.Flags & 64) == 0)
+ {
+ position /= raw_input_coordinate_space;
+ position *= screenSize;
+ }
+
+ if (Sensitivity.Value != 1)
+ {
+ // apply absolute sensitivity adjustment from the centre of the screen area.
+ Vector2 halfScreenSize = (screenSize / 2);
+
+ position -= halfScreenSize;
+ position *= (float)Sensitivity.Value;
+ position += halfScreenSize;
+ }
+
+ // map from screen to client coordinate space.
+ // not using Window's PointToClient implementation to keep floating point precision here.
+ position -= new Vector2(window.Position.X, window.Position.Y);
+ position *= window.Scale;
+
+ PendingInputs.Enqueue(new MousePositionAbsoluteInput { Position = position });
+ statistic_absolute_events.Value++;
+ }
+ else
+ {
+ PendingInputs.Enqueue(new MousePositionRelativeInput { Delta = new Vector2(mouse.LastX, mouse.LastY) * sensitivity });
+ statistic_relative_events.Value++;
+ }
- return true;
+ return IntPtr.Zero;
}
}
}
diff --git a/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL3.cs b/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL3.cs
deleted file mode 100644
index 0d67175e3..000000000
--- a/osu.Framework/Platform/Windows/WindowsMouseHandler_SDL3.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-namespace osu.Framework.Platform.Windows
-{
- internal partial class WindowsMouseHandler
- {
- private bool bindHandlerSDL3(GameHost host)
- {
- return false;
- }
- }
-}
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using osu.Framework.Platform.SDL3; | ||
using static SDL.SDL3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dunno how i feel about this
I think this looks OK. @smoogipoo as discussed, can we add an SDL2 / SDL3 string here? |
@bdach not sure if you want to give this a quick run on linux and make sure all is well? as for iOS i don't really have the energy to test it but i'm sure we'll find out from @frenzibyte if it's failing at some point before next release, worst case. |
For linux I've tested that it runs and supports window modes with:
But note that this is via XWayland, not a true X11 impl. |
Linux boots here. Appears to not be more broken than already known on all of the configurations I tested on my box (x11/wayland, sdl2/3). Not reading source because I presume enough eyes have looked at that already. |
Environment variable:
OSU_SDL3=1
.The process of making this PR involved:
All of which culminates in a 99% 1:1 reimplementation of SDL2. Only supporting logic has been added. We should be able to delete the SDL2 pathway with little effort at any point.
As far as osu! is concerned, this is a non-breaking change.
Important changes/things to look out for:
osu.Framework.Platform.SDL
->osu.Framework.Platform.SDL3
.Platform.SDL2
added to hold SDL2 variant classes.SDL
namespace if people believe that's better?SDL3GameHost
->SDLGameHost
.WindowMouseHandler
contains both SDL2 and SDL3 implementations.input.json
thus losing settings.SDL3ReadableKeyCombinationProvider
does not have an SDL2 variant.using static SDL2.SDL
andusing static SDL.SDL3
are used to avoid namespace conflicts.Testing: