SDL: Fix race condition that can lead to ENTER/LEAVE window events never firing

From 89b6209313cc65260f88a28ea99ec0df6dd807fc Mon Sep 17 00:00:00 2001
From: Dean Herbert <[EMAIL REDACTED]>
Date: Thu, 1 Apr 2021 14:17:53 +0900
Subject: [PATCH] Fix race condition that can lead to ENTER/LEAVE window events
 never firing

On windows, when toggling the state of RelativeMode rapidly, there is a
high chance that SDL_WINDOWEVENT_ENTER / SDL_WINDOWEVENT_LEAVE events
will stop firing indefinitely.

This aims to resolve that shortcoming by ensuring mouse focus state is
correctly updated via WM_MOUSELEAVE events arriving via the windows
event hook.
---
 src/video/windows/SDL_windowsevents.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 4f914aae6..0fbe012aa 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -783,8 +783,16 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
                     }
                }
             }
-            SDL_SetMouseFocus(NULL);
         }
+
+        /* When WM_MOUSELEAVE is fired we can be assured that the cursor has left the window.
+           Regardless of relative mode, it is important that mouse focus is reset as there is a potential
+           race condition when in the process of leaving/entering relative mode, resulting in focus never
+           being lost. This then causes a cascading failure where SDL_WINDOWEVENT_ENTER / SDL_WINDOWEVENT_LEAVE
+           can stop firing permanently, due to the focus being in the wrong state and TrackMouseEvent never
+           resubscribing. */
+        SDL_SetMouseFocus(NULL);
+
         returnCode = 0;
         break;
 #endif /* WM_MOUSELEAVE */