SDL: pen: Only allow one pen on Windows.

From 06583ce421416d5eb3b3772728179eb18999362b Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 20 Nov 2025 10:21:30 -0500
Subject: [PATCH] pen: Only allow one pen on Windows.

This "fixes" proximity but limits you to a single pen device. But this is
probably okay for most reasonable use cases.
---
 src/video/windows/SDL_windowsevents.c | 44 ++++++++++++++++-----------
 1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 5abc751ea815c..2ad327441b808 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -1264,19 +1264,18 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
 
     case WM_POINTERENTER:
     {
-        if (!data->videodata->GetPointerType) {
-            break;  // Not on Windows8 or later? We shouldn't get this event, but just in case...
-        }
-
+        // NOTE: GET_POINTERID_WPARAM(wParam) is not a tool ID! It changes for each new WM_POINTERENTER, like a finger ID on a touch display. We can't identify a specific pen through these events.
         const UINT32 pointerid = GET_POINTERID_WPARAM(wParam);
-        void *hpointer = (void *) (size_t) pointerid;
         POINTER_INPUT_TYPE pointer_type = PT_POINTER;
-        if (!data->videodata->GetPointerType(pointerid, &pointer_type)) {
+        if (!data->videodata->GetPointerType) {
+            break;  // Not on Windows8 or later? We shouldn't get this event, but just in case...
+        } else if (!data->videodata->GetPointerType(pointerid, &pointer_type)) {
             break;  // oh well.
         } else if (pointer_type != PT_PEN) {
             break;  // we only care about pens here.
         }
 
+        void *hpointer = (void *)(size_t)1; // just something > 0. We're using this one ID any possible pen.
         const SDL_PenID pen = SDL_FindPenByHandle(hpointer);
         if (pen) {
             SDL_SendPenProximity(WIN_GetEventTimestamp(), pen, data->window, true);
@@ -1300,8 +1299,18 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
     case WM_POINTERCAPTURECHANGED:
     case WM_POINTERLEAVE:
     {
+        // NOTE: GET_POINTERID_WPARAM(wParam) is not a tool ID! It changes for each new WM_POINTERENTER, like a finger ID on a touch display. We can't identify a specific pen through these events.
         const UINT32 pointerid = GET_POINTERID_WPARAM(wParam);
-        void *hpointer = (void *) (size_t) pointerid;
+        POINTER_INPUT_TYPE pointer_type = PT_POINTER;
+        if (!data->videodata->GetPointerType) {
+            break;  // Not on Windows8 or later? We shouldn't get this event, but just in case...
+        } else if (!data->videodata->GetPointerType(pointerid, &pointer_type)) {
+            break;  // oh well.
+        } else if (pointer_type != PT_PEN) {
+            break;  // we only care about pens here.
+        }
+
+        void *hpointer = (void *)(size_t)1; // just something > 0. We're using this one ID any possible pen.
         const SDL_PenID pen = SDL_FindPenByHandle(hpointer);
         if (pen == 0) {
             break;  // not a pen, or not a pen we already knew about.
@@ -1315,26 +1324,25 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
         returnCode = 0;
     } break;
 
+    case WM_POINTERDOWN:
+    case WM_POINTERUP:
     case WM_POINTERUPDATE: {
+        // NOTE: GET_POINTERID_WPARAM(wParam) is not a tool ID! It changes for each new WM_POINTERENTER, like a finger ID on a touch display. We can't identify a specific pen through these events.
+        const UINT32 pointerid = GET_POINTERID_WPARAM(wParam);
         POINTER_INPUT_TYPE pointer_type = PT_POINTER;
-        if (!data->videodata->GetPointerType || !data->videodata->GetPointerType(GET_POINTERID_WPARAM(wParam), &pointer_type)) {
+        if (!data->videodata->GetPointerType || !data->videodata->GetPointerType(pointerid, &pointer_type)) {
             break;  // oh well.
-        }
-
-        if (pointer_type == PT_MOUSE) {
+        } else if ((msg == WM_POINTERUPDATE) && (pointer_type == PT_MOUSE)) {
             data->last_pointer_update = lParam;
             returnCode = 0;
             break;
+        } else if (pointer_type != PT_PEN) {
+            break; // we only care about pens here.
         }
-    }
-    SDL_FALLTHROUGH;
 
-    case WM_POINTERDOWN:
-    case WM_POINTERUP: {
-        POINTER_PEN_INFO pen_info;
-        const UINT32 pointerid = GET_POINTERID_WPARAM(wParam);
-        void *hpointer = (void *) (size_t) pointerid;
+        void *hpointer = (void *)(size_t)1; // just something > 0. We're using this one ID any possible pen.
         const SDL_PenID pen = SDL_FindPenByHandle(hpointer);
+        POINTER_PEN_INFO pen_info;
         if (pen == 0) {
             break;  // not a pen, or not a pen we already knew about.
         } else if (!data->videodata->GetPointerPenInfo || !data->videodata->GetPointerPenInfo(pointerid, &pen_info)) {