Skip to content
37 changes: 20 additions & 17 deletions osu.Framework/Platform/SDL3/SDL3Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,13 @@ protected void RunFrame()
/// As per SDL's recommendation, application events should always be handled via the event filter.
/// See: https://wiki.libsdl.org/SDL3/SDL_EventType#android_ios_and_winrt_events
/// </remarks>
protected virtual void HandleEventFromFilter(SDL_Event evt)
/// <returns>A <c>bool</c> denoting whether to keep the event. <c>false</c> will drop the event.</returns>
protected virtual bool HandleEventFromFilter(SDL_Event e)
{
switch (evt.Type)
switch (e.Type)
{
case SDL_EventType.SDL_EVENT_TERMINATING:
handleQuitEvent(evt.quit);
handleQuitEvent(e.quit);
break;

case SDL_EventType.SDL_EVENT_DID_ENTER_BACKGROUND:
Expand All @@ -306,7 +307,22 @@ protected virtual void HandleEventFromFilter(SDL_Event evt)
case SDL_EventType.SDL_EVENT_LOW_MEMORY:
LowOnMemory?.Invoke();
break;

case SDL_EventType.SDL_EVENT_MOUSE_MOTION:
handleMouseMotionEvent(e.motion);
Copy link
Member Author

Choose a reason for hiding this comment

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

This calls SDL_GetWindowRelativeMouseMode() which could be considered as reading SDL state in a event filter, but it's currently just reading a window flag.

return false;

case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
handleMouseButtonEvent(e.button);
return false;

case SDL_EventType.SDL_EVENT_MOUSE_WHEEL:
handleMouseWheelEvent(e.wheel);
return false;
}

return true;
}

protected void HandleEventFromWatch(SDL_Event evt)
Expand All @@ -327,7 +343,7 @@ private static SDLBool eventFilter(IntPtr userdata, SDL_Event* eventPtr)
{
var handle = new ObjectHandle<SDL3Window>(userdata);
if (handle.GetTarget(out SDL3Window window))
window.HandleEventFromFilter(*eventPtr);
return window.HandleEventFromFilter(*eventPtr);

return true;
}
Expand Down Expand Up @@ -514,19 +530,6 @@ protected virtual void HandleEvent(SDL_Event e)
handleKeymapChangedEvent();
break;

case SDL_EventType.SDL_EVENT_MOUSE_MOTION:
handleMouseMotionEvent(e.motion);
break;

case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
handleMouseButtonEvent(e.button);
break;

case SDL_EventType.SDL_EVENT_MOUSE_WHEEL:
handleMouseWheelEvent(e.wheel);
break;

case SDL_EventType.SDL_EVENT_JOYSTICK_AXIS_MOTION:
handleJoyAxisEvent(e.jaxis);
break;
Expand Down
25 changes: 17 additions & 8 deletions osu.Framework/Platform/SDL3/SDL3Window_Input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.EnumExtensions;
Expand Down Expand Up @@ -151,11 +152,12 @@ private void enqueueJoystickButtonInput(JoystickButton button, bool isPressed)

private PointF previousPolledPoint = PointF.Empty;

private SDL_MouseButtonFlags pressedButtons;
private volatile uint pressedButtons;

private void pollMouse()
{
float x, y;
var pressed = (SDL_MouseButtonFlags)pressedButtons;
SDL_MouseButtonFlags globalButtons = SDL_GetGlobalMouseState(&x, &y);

if (previousPolledPoint.X != x || previousPolledPoint.Y != y)
Expand All @@ -170,18 +172,18 @@ private void pollMouse()
}

// a button should be released if it was pressed and its current global state differs (its bit in globalButtons is set to 0)
SDL_MouseButtonFlags buttonsToRelease = pressedButtons & (globalButtons ^ pressedButtons);
SDL_MouseButtonFlags buttonsToRelease = pressed & (globalButtons ^ pressed);

// the outer if just optimises for the common case that there are no buttons to release.
if (buttonsToRelease != 0)
{
Interlocked.And(ref pressedButtons, (uint)~buttonsToRelease);

if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_LMASK)) MouseUp?.Invoke(MouseButton.Left);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_MMASK)) MouseUp?.Invoke(MouseButton.Middle);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_RMASK)) MouseUp?.Invoke(MouseButton.Right);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_X1MASK)) MouseUp?.Invoke(MouseButton.Button1);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_X2MASK)) MouseUp?.Invoke(MouseButton.Button2);

pressedButtons &= ~buttonsToRelease;
}
}

Expand Down Expand Up @@ -440,10 +442,17 @@ private void handleMouseWheelEvent(SDL_MouseWheelEvent evtWheel)
{
bool isPrecise(float f) => f % 1 != 0;

bool precise;

if (isPrecise(evtWheel.x) || isPrecise(evtWheel.y))
{
precise = true;
lastPreciseScroll = evtWheel.timestamp;

bool precise = evtWheel.timestamp < lastPreciseScroll + precise_scroll_debounce;
}
else
{
precise = evtWheel.timestamp < lastPreciseScroll + precise_scroll_debounce;
}

// SDL reports horizontal scroll opposite of what framework expects (in non-"natural" mode, scrolling to the right gives positive deltas while we want negative).
TriggerMouseWheel(new Vector2(-evtWheel.x, evtWheel.y), precise);
Expand All @@ -458,12 +467,12 @@ private void handleMouseButtonEvent(SDL_MouseButtonEvent evtButton)
switch (evtButton.type)
{
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
pressedButtons |= mask;
MouseDown?.Invoke(button);
Interlocked.Or(ref pressedButtons, (uint)mask);
break;

case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
pressedButtons &= ~mask;
Interlocked.And(ref pressedButtons, (uint)~mask);
MouseUp?.Invoke(button);
break;
}
Expand Down
6 changes: 3 additions & 3 deletions osu.Framework/Platform/Windows/SDL3WindowsWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@ public override void Create()
Native.Input.SetWindowFeedbackSetting(WindowHandle, feedbackType, false);
}

protected override void HandleEventFromFilter(SDL_Event evt)
protected override bool HandleEventFromFilter(SDL_Event e)
{
switch (evt.Type)
switch (e.Type)
{
case SDL_EventType.SDL_EVENT_WINDOW_FOCUS_LOST:
warpCursorFromFocusLoss();
break;
}

base.HandleEventFromFilter(evt);
return base.HandleEventFromFilter(e);
}

public Vector2? LastMousePosition { get; set; }
Expand Down
Loading