Skip to content
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

Windows tablets don't report pen events when relative mouse mode is enabled #12324

Open
Susko3 opened this issue Feb 18, 2025 · 1 comment · May be fixed by #12329
Open

Windows tablets don't report pen events when relative mouse mode is enabled #12324

Susko3 opened this issue Feb 18, 2025 · 1 comment · May be fixed by #12329
Milestone

Comments

@Susko3
Copy link
Contributor

Susko3 commented Feb 18, 2025

SDL has special logic to convert raw absolute mouse (i.e. tablet) input to relative mouse motion. This tablet pen input never generates SDL_PenMotionEvents.

} 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, true, (float)relX, (float)relY);
}
}

I would expect this pen to mouse logic to only fire when SDL_HINT_PEN_MOUSE_EVENTS is enabled. I would also expect to get the usual SDL_PenMotionEvent for this pen input.

This issue only affects tablet drivers that generate absolute mouse input. (Example: Wacom drivers with windows ink disabled, OpenTabletDriver, hawku Tablet Driver.) Tablet drivers that generate windows ink events work as expected via WM_POINTER & co. handling. When relative mouse mode is disabled, absolute tablet events are reported as absolute mouse input, which is not ideal, but is not really a problem as it's mapping absolute to absolute.

@Susko3
Copy link
Contributor Author

Susko3 commented Feb 18, 2025

This patch makes absolute pen input from OpenTablet Driver work when relative mouse mode is enabled. You shouldn't apply the patch as-is, as the previous behaviour of mapping absolute pen input to relative mouse motion is lost. The SDL_pen.c logic doesn't consider relative mouse mode when simulating mouse input.

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index af3407c40..8fddd0d55 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -579,6 +579,11 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
         return;
     }
 
+    SDL_Mouse *mouse = SDL_GetMouse();
+    if (!mouse) {
+        return;
+    }
+
     if (GetMouseMessageSource(rawmouse->ulExtraInformation) != SDL_MOUSE_EVENT_SOURCE_MOUSE) {
         return;
     }
@@ -648,13 +653,10 @@ 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, true, (float)relX, (float)relY);
+                if (!data->raw_input_fake_pen_id) {
+                    data->raw_input_fake_pen_id = SDL_AddPenDevice(timestamp, "raw mouse input", NULL, SDL_malloc(1));
                 }
+                SDL_SendPenMotion(timestamp, data->raw_input_fake_pen_id, window, (float)(x - window->x), (float)(y - window->y));
             }
 
             data->last_raw_mouse_position.x = x;
diff --git a/src/video/windows/SDL_windowsrawinput.c b/src/video/windows/SDL_windowsrawinput.c
index fa249914d..b9d4f979a 100644
--- a/src/video/windows/SDL_windowsrawinput.c
+++ b/src/video/windows/SDL_windowsrawinput.c
@@ -111,6 +111,11 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param)
         WIN_PollRawInput(_this, poll_start);
     }
 
+    if (_this->internal->raw_input_fake_pen_id) {
+        SDL_RemovePenDevice(0, _this->internal->raw_input_fake_pen_id);
+        _this->internal->raw_input_fake_pen_id = 0;
+    }
+
     devices[0].dwFlags |= RIDEV_REMOVE;
     devices[1].dwFlags |= RIDEV_REMOVE;
     RegisterRawInputDevices(devices, count, sizeof(devices[0]));
diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h
index 53cfbadd7..cbf5639e1 100644
--- a/src/video/windows/SDL_windowsvideo.h
+++ b/src/video/windows/SDL_windowsvideo.h
@@ -440,6 +440,7 @@ struct SDL_VideoData
     bool raw_keyboard_enabled;
     bool pending_E1_key_sequence;
     Uint32 raw_input_enabled;
+    SDL_PenID raw_input_fake_pen_id;
 
     WIN_GameInputData *gameinput_context;
 

The simplest solution that works without adding any new flags would be to invoke the new code iff SDL_HINT_PEN_MOUSE_EVENTS is disabled. Applications that handle pen events will likely disable this flag.

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index af3407c40..36a9e4dc5 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -579,6 +579,11 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
         return;
     }
 
+    SDL_Mouse *mouse = SDL_GetMouse();
+    if (!mouse) {
+        return;
+    }
+
     if (GetMouseMessageSource(rawmouse->ulExtraInformation) != SDL_MOUSE_EVENT_SOURCE_MOUSE) {
         return;
     }
@@ -647,7 +652,7 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
                         }
                     }
                 }
-            } else {
+            } else if (mouse->pen_mouse_events) {
                 const int MAXIMUM_TABLET_RELATIVE_MOTION = 32;
                 if (SDL_abs(relX) > MAXIMUM_TABLET_RELATIVE_MOTION ||
                     SDL_abs(relY) > MAXIMUM_TABLET_RELATIVE_MOTION) {
@@ -655,6 +660,11 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_VideoData *data, HANDL
                 } else {
                     SDL_SendMouseMotion(timestamp, window, mouseID, true, (float)relX, (float)relY);
                 }
+            } else {
+                if (!data->raw_input_fake_pen_id) {
+                    data->raw_input_fake_pen_id = SDL_AddPenDevice(timestamp, "raw mouse input", NULL, SDL_malloc(1));
+                }
+                SDL_SendPenMotion(timestamp, data->raw_input_fake_pen_id, window, (float)(x - window->x), (float)(y - window->y));
             }
 
             data->last_raw_mouse_position.x = x;
diff --git a/src/video/windows/SDL_windowsrawinput.c b/src/video/windows/SDL_windowsrawinput.c
index fa249914d..b9d4f979a 100644
--- a/src/video/windows/SDL_windowsrawinput.c
+++ b/src/video/windows/SDL_windowsrawinput.c
@@ -111,6 +111,11 @@ static DWORD WINAPI WIN_RawInputThread(LPVOID param)
         WIN_PollRawInput(_this, poll_start);
     }
 
+    if (_this->internal->raw_input_fake_pen_id) {
+        SDL_RemovePenDevice(0, _this->internal->raw_input_fake_pen_id);
+        _this->internal->raw_input_fake_pen_id = 0;
+    }
+
     devices[0].dwFlags |= RIDEV_REMOVE;
     devices[1].dwFlags |= RIDEV_REMOVE;
     RegisterRawInputDevices(devices, count, sizeof(devices[0]));
diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h
index 53cfbadd7..cbf5639e1 100644
--- a/src/video/windows/SDL_windowsvideo.h
+++ b/src/video/windows/SDL_windowsvideo.h
@@ -440,6 +440,7 @@ struct SDL_VideoData
     bool raw_keyboard_enabled;
     bool pending_E1_key_sequence;
     Uint32 raw_input_enabled;
+    SDL_PenID raw_input_fake_pen_id;
 
     WIN_GameInputData *gameinput_context;
 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants