From ed70ce85c1a574f77602f71cbbc4c3ae29dd7801 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Wed, 29 Apr 2026 17:51:26 -0500
Subject: [PATCH] pen: Fix enabling touch emulation while a pen is connected
(cherry picked from commit 41f079491a0e79b22441fd32a7c8ad91db237744)
---
src/events/SDL_mouse.c | 18 --------------
src/events/SDL_pen.c | 55 +++++++++++++++++++++++++++---------------
2 files changed, 36 insertions(+), 37 deletions(-)
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index e389e47a16197..5dd25d713aef3 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -188,18 +188,6 @@ static void SDLCALL SDL_PenMouseEventsChanged(void *userdata, const char *name,
mouse->pen_mouse_events = SDL_GetStringBoolean(hint, true);
}
-static void SDLCALL SDL_PenTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
-{
- SDL_Mouse *mouse = (SDL_Mouse *)userdata;
-
- mouse->pen_touch_events = SDL_GetStringBoolean(hint, true);
-
- if (!mouse->pen_touch_events && mouse->added_pen_touch_device) {
- SDL_DelTouch(SDL_PEN_TOUCHID);
- mouse->added_pen_touch_device = false;
- }
-}
-
static void SDLCALL SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_Mouse *mouse = (SDL_Mouse *)userdata;
@@ -282,9 +270,6 @@ bool SDL_PreInitMouse(void)
SDL_AddHintCallback(SDL_HINT_PEN_MOUSE_EVENTS,
SDL_PenMouseEventsChanged, mouse);
- SDL_AddHintCallback(SDL_HINT_PEN_TOUCH_EVENTS,
- SDL_PenTouchEventsChanged, mouse);
-
SDL_AddHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE,
SDL_MouseAutoCaptureChanged, mouse);
@@ -1149,9 +1134,6 @@ void SDL_QuitMouse(void)
SDL_RemoveHintCallback(SDL_HINT_PEN_MOUSE_EVENTS,
SDL_PenMouseEventsChanged, mouse);
- SDL_RemoveHintCallback(SDL_HINT_PEN_TOUCH_EVENTS,
- SDL_PenTouchEventsChanged, mouse);
-
SDL_RemoveHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE,
SDL_MouseAutoCaptureChanged, mouse);
diff --git a/src/events/SDL_pen.c b/src/events/SDL_pen.c
index 83543a695ee9b..d70542b9f9bfc 100644
--- a/src/events/SDL_pen.c
+++ b/src/events/SDL_pen.c
@@ -93,6 +93,33 @@ SDL_PenID SDL_FindPenByCallback(bool (*callback)(void *handle, void *userdata),
return result;
}
+static void UpdateTouchEmulationDevicePresence(void)
+{
+ SDL_Mouse *mouse = SDL_GetMouse();
+
+ SDL_LockRWLockForReading(pen_device_rwlock);
+ bool has_pen = (pen_device_count != 0);
+ SDL_UnlockRWLock(pen_device_rwlock);
+
+ if (!mouse->pen_touch_events || !has_pen) {
+ if (mouse->added_pen_touch_device) {
+ SDL_DelTouch(SDL_PEN_TOUCHID);
+ mouse->added_pen_touch_device = false;
+ }
+ } else if (!mouse->added_pen_touch_device) {
+ SDL_AddTouch(SDL_PEN_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "pen_input");
+ mouse->added_pen_touch_device = true;
+ }
+}
+
+static void SDLCALL SDL_PenTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+ SDL_Mouse *mouse = SDL_GetMouse();
+
+ mouse->pen_touch_events = SDL_GetStringBoolean(hint, true);
+
+ UpdateTouchEmulationDevicePresence();
+}
// public API ...
@@ -106,11 +133,18 @@ bool SDL_InitPen(void)
if (!pen_device_rwlock) {
return false;
}
+
+ SDL_AddHintCallback(SDL_HINT_PEN_TOUCH_EVENTS,
+ SDL_PenTouchEventsChanged, NULL);
+
return true;
}
void SDL_QuitPen(void)
{
+ SDL_RemoveHintCallback(SDL_HINT_PEN_TOUCH_EVENTS,
+ SDL_PenTouchEventsChanged, NULL);
+
SDL_RemoveAllPenDevices(NULL, NULL);
SDL_DestroyRWLock(pen_device_rwlock);
pen_device_rwlock = NULL;
@@ -228,7 +262,6 @@ SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, SDL_Window *windo
SDL_LockRWLockForWriting(pen_device_rwlock);
- bool first_device = false;
SDL_Pen *pen = NULL;
void *ptr = SDL_realloc(pen_devices, (pen_device_count + 1) * sizeof (*pen));
if (ptr) {
@@ -237,8 +270,6 @@ SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, SDL_Window *windo
pen = &pen_devices[pen_device_count];
pen_device_count++;
- first_device = (pen_device_count == 1);
-
SDL_zerop(pen);
pen->instance_id = result;
pen->name = namecpy;
@@ -254,13 +285,7 @@ SDL_PenID SDL_AddPenDevice(Uint64 timestamp, const char *name, SDL_Window *windo
SDL_free(namecpy);
}
- if (first_device) {
- SDL_Mouse *mouse = SDL_GetMouse();
- if (mouse->pen_touch_events && !mouse->added_pen_touch_device) {
- SDL_AddTouch(SDL_PEN_TOUCHID, SDL_TOUCH_DEVICE_DIRECT, "pen_input");
- mouse->added_pen_touch_device = true;
- }
- }
+ UpdateTouchEmulationDevicePresence();
if (result && in_proximity) {
SDL_SendPenProximity(timestamp, result, window, true, true);
@@ -278,7 +303,6 @@ void SDL_RemovePenDevice(Uint64 timestamp, SDL_Window *window, SDL_PenID instanc
SDL_SendPenProximity(timestamp, instance_id, window, false, true); // bye bye
SDL_LockRWLockForWriting(pen_device_rwlock);
- bool last_device = false;
SDL_Pen *pen = FindPenByInstanceId(instance_id);
if (pen) {
SDL_free(pen->name);
@@ -300,18 +324,11 @@ void SDL_RemovePenDevice(Uint64 timestamp, SDL_Window *window, SDL_PenID instanc
} else {
SDL_free(pen_devices);
pen_devices = NULL;
- last_device = true;
}
}
SDL_UnlockRWLock(pen_device_rwlock);
- if (last_device) {
- SDL_Mouse *mouse = SDL_GetMouse();
- if (mouse->added_pen_touch_device) {
- SDL_DelTouch(SDL_PEN_TOUCHID);
- mouse->added_pen_touch_device = false;
- }
- }
+ UpdateTouchEmulationDevicePresence();
}
// This presumably is happening during video quit, so we don't send PROXIMITY_OUT events here.