Skip to content

Async mouse input on windows #6235

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

Merged
merged 12 commits into from
Jan 23, 2025
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