Skip to content

Commit

Permalink
Handle SDL pen events by emulating mouse
Browse files Browse the repository at this point in the history
  • Loading branch information
hwsmm committed Sep 15, 2024
1 parent 864c348 commit dd45d8a
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 5 deletions.
14 changes: 14 additions & 0 deletions osu.Framework/Platform/SDL3/SDL3Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,20 @@ protected virtual void HandleEvent(SDL_Event e)
case SDL_EventType.SDL_EVENT_DROP_COMPLETE:
handleDropEvent(e.drop);
break;

case SDL_EventType.SDL_EVENT_PEN_DOWN:
case SDL_EventType.SDL_EVENT_PEN_UP:
handlePenTouchEvent(e.ptouch);
break;

case SDL_EventType.SDL_EVENT_PEN_BUTTON_DOWN:
case SDL_EventType.SDL_EVENT_PEN_BUTTON_UP:
handlePenButtonEvent(e.pbutton);
break;

case SDL_EventType.SDL_EVENT_PEN_MOTION:
handlePenMotionEvent(e.pmotion);
break;
}
}

Expand Down
112 changes: 107 additions & 5 deletions osu.Framework/Platform/SDL3/SDL3Window_Input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ private void enqueueJoystickButtonInput(JoystickButton button, bool isPressed)

private PointF previousPolledPoint = PointF.Empty;

private SDL_MouseButtonFlags pressedButtons;
private SDL_MouseButtonFlags mousePressedButtons;

private SDL_MouseButtonFlags penPressedButtons;

private void pollMouse()
{
Expand All @@ -170,7 +172,7 @@ 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 = mousePressedButtons & (globalButtons ^ mousePressedButtons) & ~penPressedButtons;

// the outer if just optimises for the common case that there are no buttons to release.
if (buttonsToRelease != 0)
Expand All @@ -180,6 +182,8 @@ private void pollMouse()
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);

mousePressedButtons &= ~buttonsToRelease;
}
}

Expand Down Expand Up @@ -437,20 +441,32 @@ private void handleMouseButtonEvent(SDL_MouseButtonEvent evtButton)
switch (evtButton.type)
{
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
pressedButtons |= mask;
if (penPressedButtons.HasFlagFast(mask))
{
Logger.Log("Mouse tried pressing a button already pressed by tablet!", level: LogLevel.Debug);
return;
}

mousePressedButtons |= mask;
MouseDown?.Invoke(button);
break;

case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
pressedButtons &= ~mask;
if (!mousePressedButtons.HasFlagFast(mask))
{
Logger.Log("Mouse tried releasing a button already released by tablet!", level: LogLevel.Debug);
return;
}

mousePressedButtons &= ~mask;
MouseUp?.Invoke(button);
break;
}
}

private void handleMouseMotionEvent(SDL_MouseMotionEvent evtMotion)
{
if (SDL_GetRelativeMouseMode() == SDL_bool.SDL_FALSE)
if (SDL_GetWindowRelativeMouseMode(SDLWindowHandle) == SDL_bool.SDL_FALSE)
MouseMove?.Invoke(new Vector2(evtMotion.x * Scale, evtMotion.y * Scale));
else
MouseMoveRelative?.Invoke(new Vector2(evtMotion.xrel * Scale, evtMotion.yrel * Scale));
Expand Down Expand Up @@ -494,6 +510,55 @@ private void handleKeyboardEvent(SDL_KeyboardEvent evtKey)

private void handleKeymapChangedEvent() => KeymapChanged?.Invoke();

private void handlePenMotionEvent(SDL_PenMotionEvent evtPenMotion)
{
MouseMove?.Invoke(new Vector2(evtPenMotion.x * Scale, evtPenMotion.y * Scale));
}

private void handlePenTouchEvent(SDL_PenTouchEvent evtPenTouch)
{
if (evtPenTouch.eraser == SDL_bool.SDL_TRUE)
return;

handlePenPressEvent(0, evtPenTouch.down == SDL_bool.SDL_TRUE);
}

private void handlePenButtonEvent(SDL_PenButtonEvent evtPenButton)
{
handlePenPressEvent(evtPenButton.button, evtPenButton.down == SDL_bool.SDL_TRUE);
}

private void handlePenPressEvent(byte penButton, bool pressed)
{
mouseButtonFromPen(pressed, penButton, out MouseButton button, out SDL_MouseButtonFlags mask);

if (mask == 0)
return;

if (pressed)
{
if (mousePressedButtons.HasFlagFast(mask))
{
Logger.Log("Tablet tried pressing a button already pressed by mouse!", level: LogLevel.Debug);
return;
}

penPressedButtons |= mask;
MouseDown?.Invoke(button);
}
else
{
if (!penPressedButtons.HasFlagFast(mask))
{
Logger.Log("Tablet tried releasing a button already released by mouse!", level: LogLevel.Debug);
return;
}

penPressedButtons &= ~mask;
MouseUp?.Invoke(button);
}
}

private MouseButton mouseButtonFromEvent(SDLButton button)
{
switch (button)
Expand All @@ -519,6 +584,43 @@ private MouseButton mouseButtonFromEvent(SDLButton button)
}
}

private void mouseButtonFromPen(bool pressed, byte penButton, out MouseButton button, out SDL_MouseButtonFlags buttonFlag)
{
switch (penButton)
{
case 0:
button = MouseButton.Left;
buttonFlag = SDL_MouseButtonFlags.SDL_BUTTON_LMASK;
break;

case 1:
button = MouseButton.Right;
buttonFlag = SDL_MouseButtonFlags.SDL_BUTTON_RMASK;
break;

case 2:
button = MouseButton.Middle;
buttonFlag = SDL_MouseButtonFlags.SDL_BUTTON_MMASK;
break;

case 3:
button = MouseButton.Button1;
buttonFlag = SDL_MouseButtonFlags.SDL_BUTTON_X1MASK;
break;

case 4:
button = MouseButton.Button2;
buttonFlag = SDL_MouseButtonFlags.SDL_BUTTON_X2MASK;
break;

default:
Logger.Log($"unknown pen button index: {penButton}, ignoring...");
button = MouseButton.Button3;
buttonFlag = 0;
break;
}
}

#endregion

/// <summary>
Expand Down

0 comments on commit dd45d8a

Please sign in to comment.