osu-framework icon indicating copy to clipboard operation
osu-framework copied to clipboard

Fixing windows ink tablet events on SDL3

Open Susko3 opened this issue 3 months ago • 1 comments

Preface

For best performance and customizability, the built in tablet drivers should be used. But windows ink tablets are quite common and plug-and-play on windows, so it makes sense to support them.

Supporting tablets that generate fake mouse events (likely includes external OpenTabletDriver) is out of scope, if it works then great, but if it doesn't, we'll ask users to disable relative mouse mode.

Related issues:

  • SDL3
    • https://github.com/ppy/osu/issues/28223
  • Before SDL3
    • https://github.com/ppy/osu/issues/23011
    • https://github.com/ppy/osu/issues/23839
    • https://github.com/ppy/osu/issues/27227

SDL changes

SDL3 already handles absolute raw input (i.e. tablets/windows ink), but it forcefully converts the events to relative motion. So the fix is to report the events as absolute input. Importantly, the mouseID is SDL_PEN_MOUSEID to allow discerning those events framework-side. (By default, the tablet inputs are marked with mouseID=0, same as touchpad inputs.)

Unsure if upstream will accept this. We would hide this behind a hint, eg. SDL_HINT_WINDOWS_TABLET_ALWAYS_ABSOLUTE_MOTION, but using SDL_PEN_MOUSEID is really hacky. There is already a way to discern tablet events from touches that is arguably just as hacky.

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index eb0131b2b..52d3ca2eb 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -578,13 +578,7 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
                 }
             }
         } else {
-            const int MAXIMUM_TABLET_RELATIVE_MOTION = 32;
-            if (SDL_abs(relX) > MAXIMUM_TABLET_RELATIVE_MOTION ||
-                SDL_abs(relY) > MAXIMUM_TABLET_RELATIVE_MOTION) {
-                /* Ignore this motion, probably a pen lift and drop */
-            } else {
-                SDL_SendMouseMotion(timestamp, window, mouseID, SDL_TRUE, (float)relX, (float)relY);
-            }
+            SDL_SendMouseMotion(timestamp, window, SDL_PEN_MOUSEID, SDL_FALSE, (float)(x - window->x), (float)(y - window->y));
         }
 
         data->last_raw_mouse_position.x = x;

Framework changes

Framework-side we'd discern tablet from relative mouse events, similar to how touch events are handled on windows.

https://github.com/ppy/osu-framework/blob/7fe8bcbdaa0bf3ab36141319318c996af26b3eeb/osu.Framework/Platform/Windows/WindowsWindow.cs#L218-L238

Adding sensitivity is fairly simple, basically copying the old WindowsMouseHandler logic.

https://github.com/ppy/osu-framework/blob/66e8ea1206e3c061ea2d1b1540c7e867433c4990/osu.Framework/Platform/Windows/WindowsMouseHandler.cs#L129-L142

WIP branch & testing

Here's the WIP framework branch: https://github.com/ppy/osu-framework/compare/master...Susko3:win-fix-sdl3-tablet?expand=1. To run, release SDL3-CS locally with the SDL3 changes.

I've tested this with https://github.com/Teages/vTablet using an android phone as a tablet. The code works really well for positioning the cursor, but there are some issues with tablet pen down events not registering. I've not investigated those yet.

Please give it a spin on a real tablet. And if it works fine, I'll start with the upstream SDL changes.

osu! input settings

We should probably have high precision mouse and sensitivity if no tablets are detected. Unsure about the names. It's also possible to have mouse sensitivity be a different setting from tablet sensitivity.

image

Susko3 avatar May 21 '24 09:05 Susko3