SDL: windows: Manage WideCharToMultiByte vs Windows XP.

From 1c5bc5373853cb8fdf43ec46ba4f00ce2325113d Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 25 Jan 2024 18:53:56 -0500
Subject: [PATCH] windows: Manage WideCharToMultiByte vs Windows XP.

Reference Issue #8666.
---
 src/core/windows/SDL_windows.c        | 10 ++++++++++
 src/core/windows/SDL_windows.h        |  3 +++
 src/hidapi/windows/hid.c              |  8 ++++++++
 src/video/windows/SDL_windowsevents.c |  2 +-
 src/video/winrt/SDL_winrtkeyboard.cpp |  1 +
 5 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c
index e7e0bc56d511..37e685a3ab24 100644
--- a/src/core/windows/SDL_windows.c
+++ b/src/core/windows/SDL_windows.c
@@ -376,6 +376,16 @@ SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat)
     return 0;
 }
 
+
+int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar)
+{
+    if (WIN_IsWindowsXP()) {
+        dwFlags &= ~WC_ERR_INVALID_CHARS;  // not supported before Vista. Without this flag, it will just replace bogus chars with U+FFFD. You're on your own, WinXP.
+    }
+    return WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
+}
+
+
 /* Win32-specific SDL_RunApp(), which does most of the SDL_main work,
   based on SDL_windows_main.c, placed in the public domain by Sam Lantinga  4/13/98 */
 #ifdef SDL_PLATFORM_WIN32
diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h
index 850b4ecac493..2434a8532c8b 100644
--- a/src/core/windows/SDL_windows.h
+++ b/src/core/windows/SDL_windows.h
@@ -173,6 +173,9 @@ extern BOOL WIN_IsRectEmpty(const RECT *rect);
 
 extern SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat);
 
+/* WideCharToMultiByte, but with some WinXP manangement. */
+extern int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c
index 3a90a3db37cf..b602fb7c2ee9 100644
--- a/src/hidapi/windows/hid.c
+++ b/src/hidapi/windows/hid.c
@@ -795,13 +795,21 @@ static void hid_internal_get_info(const wchar_t* interface_path, struct hid_devi
 static char *hid_internal_UTF16toUTF8(const wchar_t *src)
 {
 	char *dst = NULL;
+#ifdef HIDAPI_USING_SDL_RUNTIME
+	int len = WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
+#else
 	int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, NULL, 0, NULL, NULL);
+#endif
 	if (len) {
 		dst = (char*)calloc(len, sizeof(char));
 		if (dst == NULL) {
 			return NULL;
 		}
+#ifdef HIDAPI_USING_SDL_RUNTIME
+		WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dst, len, NULL, NULL);
+#else
 		WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, src, -1, dst, len, NULL, NULL);
+#endif
 	}
 
 	return dst;
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 2ac4e78aef82..930c2a7da0e3 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -973,7 +973,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
             };
 
             char utf8[5];
-            int result = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
+            int result = WIN_WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
             if (result > 0) {
                 SDL_SendKeyboardText(utf8);
             }
diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp
index b1aa6b0363b2..f210fab4f002 100644
--- a/src/video/winrt/SDL_winrtkeyboard.cpp
+++ b/src/video/winrt/SDL_winrtkeyboard.cpp
@@ -101,6 +101,7 @@ void WINRT_ProcessCharacterReceivedEvent(SDL_Window *window, Windows::UI::Core::
         };
 
         char utf8[5];
+        // doesn't need to be WIN_WideCharToMultiByte, since we don't care about WinXP support in WinRT.
         int result = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, sizeof(utf8), NULL, NULL);
         if (result > 0) {
             SDL_SendKeyboardText(utf8);