SDL: Fixed windows events on 32-bit Windows

From a96664674f6174773ef4a30eb1c53afcdddcaae1 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 9 Nov 2025 07:42:50 -0800
Subject: [PATCH] Fixed windows events on 32-bit Windows

When running on 32-bit Windows, DefWindowProc resolves to a function in ntdll.dll, but after the window is created the actual window proc is a function in user32.dll. We solve this by using our own custom default window proc and looking for that instead.

Fixes https://github.com/libsdl-org/SDL/issues/1442
---
 src/video/windows/SDL_windowsevents.c | 7 ++++++-
 src/video/windows/SDL_windowsevents.h | 4 ++--
 src/video/windows/SDL_windowswindow.c | 4 ++--
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index bde2a53bdeebd..b9f6e9dba0813 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -2471,6 +2471,11 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
     }
 }
 
+LRESULT CALLBACK WIN_DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
+}
+
 int WIN_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
 {
     if (g_WindowsEnableMessageLoop) {
@@ -2754,7 +2759,7 @@ bool SDL_RegisterApp(const char *name, Uint32 style, void *hInst)
     wcex.cbSize = sizeof(WNDCLASSEX);
     wcex.lpszClassName = SDL_Appname;
     wcex.style = SDL_Appstyle;
-    wcex.lpfnWndProc = DefWindowProc;
+    wcex.lpfnWndProc = WIN_DefWindowProc;
     wcex.hInstance = SDL_Instance;
 
 #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
diff --git a/src/video/windows/SDL_windowsevents.h b/src/video/windows/SDL_windowsevents.h
index 5336013b65ae9..78a92208312e2 100644
--- a/src/video/windows/SDL_windowsevents.h
+++ b/src/video/windows/SDL_windowsevents.h
@@ -28,8 +28,8 @@ extern Uint32 SDL_Appstyle;
 extern HINSTANCE SDL_Instance;
 
 extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
-extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
-                                       LPARAM lParam);
+extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+extern LRESULT CALLBACK WIN_DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
 extern void WIN_PollRawInput(SDL_VideoDevice *_this, Uint64 poll_start);
 extern void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, bool initial_check);
 extern void WIN_PumpEvents(SDL_VideoDevice *_this);
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 223020d2c66a9..542c29f510156 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -427,13 +427,13 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, HWND hwn
     // Set up the window proc function
 #ifdef GWLP_WNDPROC
     data->wndproc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
-    if (data->wndproc == DefWindowProc) {
+    if (data->wndproc == WIN_DefWindowProc) {
         data->wndproc = NULL;
         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WIN_WindowProc);
     }
 #else
     data->wndproc = (WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC);
-    if (data->wndproc == DefWindowProc) {
+    if (data->wndproc == WIN_DefWindowProc) {
         data->wndproc = NULL;
         SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR)WIN_WindowProc);
     }