Browse Source

Merge pull request #1110 from Bloodknight/UpdateSDL

Update SDL to 2.28.4
Brian Roberts 1 year ago
parent
commit
0db209e3dc
100 changed files with 2260 additions and 1760 deletions
  1. 1 1
      Engine/lib/CMakeLists.txt
  2. 0 90
      Engine/lib/sdl/.clang-format
  3. 0 79
      Engine/lib/sdl/.editorconfig
  4. 0 188
      Engine/lib/sdl/.gitignore
  5. 0 17
      Engine/lib/sdl/.wikiheaders-options
  6. 30 12
      Engine/lib/sdl/CMakeLists.txt
  7. 1 1
      Engine/lib/sdl/Makefile.os2
  8. 1 1
      Engine/lib/sdl/Makefile.w32
  9. 119 0
      Engine/lib/sdl/SDL2.spec
  10. 1 0
      Engine/lib/sdl/VERSION.txt
  11. 54 0
      Engine/lib/sdl/VisualC/pkg-support/cmake/sdl2-config-version.cmake
  12. 117 0
      Engine/lib/sdl/VisualC/pkg-support/cmake/sdl2-config.cmake
  13. 7 0
      Engine/lib/sdl/WhatsNew.txt
  14. 2 2
      Engine/lib/sdl/Xcode/SDL/Info-Framework.plist
  15. 6 6
      Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj
  16. 1 1
      Engine/lib/sdl/Xcode/SDL/pkg-support/SDL.info
  17. 48 0
      Engine/lib/sdl/Xcode/SDL/pkg-support/resources/CMake/sdl2-config-version.cmake
  18. 71 0
      Engine/lib/sdl/Xcode/SDL/pkg-support/resources/CMake/sdl2-config.cmake
  19. 0 1
      Engine/lib/sdl/android-project-ant/AndroidManifest.xml
  20. 0 17
      Engine/lib/sdl/android-project-ant/ant.properties
  21. 0 17
      Engine/lib/sdl/android-project-ant/build.properties
  22. 0 93
      Engine/lib/sdl/android-project-ant/build.xml
  23. 0 11
      Engine/lib/sdl/android-project-ant/default.properties
  24. 0 1
      Engine/lib/sdl/android-project-ant/jni/Android.mk
  25. 0 10
      Engine/lib/sdl/android-project-ant/jni/Application.mk
  26. 0 18
      Engine/lib/sdl/android-project-ant/jni/src/Android.mk
  27. 0 12
      Engine/lib/sdl/android-project-ant/jni/src/Android_static.mk
  28. 0 20
      Engine/lib/sdl/android-project-ant/proguard-project.txt
  29. 0 14
      Engine/lib/sdl/android-project-ant/project.properties
  30. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-hdpi/ic_launcher.png
  31. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-mdpi/ic_launcher.png
  32. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-xhdpi/ic_launcher.png
  33. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-xxhdpi/ic_launcher.png
  34. 0 13
      Engine/lib/sdl/android-project-ant/res/layout/main.xml
  35. 0 4
      Engine/lib/sdl/android-project-ant/res/values/strings.xml
  36. 0 1
      Engine/lib/sdl/android-project-ant/src
  37. 10 10
      Engine/lib/sdl/android-project/app/build.gradle
  38. 0 1
      Engine/lib/sdl/android-project/app/src/main/AndroidManifest.xml
  39. 16 18
      Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
  40. 1 1
      Engine/lib/sdl/android-project/build.gradle
  41. 1 1
      Engine/lib/sdl/android-project/gradle/wrapper/gradle-wrapper.properties
  42. 52 13
      Engine/lib/sdl/build-scripts/config.guess
  43. 146 76
      Engine/lib/sdl/build-scripts/config.sub
  44. 18 0
      Engine/lib/sdl/cmake/sdlchecks.cmake
  45. 4 0
      Engine/lib/sdl/cmake/sdlplatform.cmake
  46. 4 42
      Engine/lib/sdl/configure
  47. 4 27
      Engine/lib/sdl/configure.ac
  48. 7 7
      Engine/lib/sdl/docs/README-android.md
  49. 1 1
      Engine/lib/sdl/docs/README-cmake.md
  50. 1 1
      Engine/lib/sdl/docs/README-emscripten.md
  51. 1 1
      Engine/lib/sdl/docs/README-os2.md
  52. 2 0
      Engine/lib/sdl/include/SDL_assert.h
  53. 1 1
      Engine/lib/sdl/include/SDL_atomic.h
  54. 2 0
      Engine/lib/sdl/include/SDL_config.h.cmake
  55. 20 0
      Engine/lib/sdl/include/SDL_hints.h
  56. 1 1
      Engine/lib/sdl/include/SDL_render.h
  57. 3 2
      Engine/lib/sdl/include/SDL_revision.h
  58. 1 1
      Engine/lib/sdl/include/SDL_version.h
  59. 19 0
      Engine/lib/sdl/mingw/pkg-support/cmake/sdl2-config-version.cmake
  60. 19 0
      Engine/lib/sdl/mingw/pkg-support/cmake/sdl2-config.cmake
  61. 2 2
      Engine/lib/sdl/src/SDL.c
  62. 10 2
      Engine/lib/sdl/src/SDL_assert.c
  63. 2 0
      Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c
  64. 220 69
      Engine/lib/sdl/src/audio/os2/SDL_os2audio.c
  65. 3 2
      Engine/lib/sdl/src/audio/os2/SDL_os2audio.h
  66. 2 0
      Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c
  67. 0 1
      Engine/lib/sdl/src/core/linux/SDL_fcitx.c
  68. 13 0
      Engine/lib/sdl/src/core/windows/SDL_windows.h
  69. 24 7
      Engine/lib/sdl/src/events/SDL_keyboard.c
  70. 3 0
      Engine/lib/sdl/src/events/SDL_keyboard_c.h
  71. 2 2
      Engine/lib/sdl/src/file/SDL_rwops.c
  72. 3 3
      Engine/lib/sdl/src/hidapi/linux/hid.c
  73. 1 0
      Engine/lib/sdl/src/joystick/SDL_gamecontroller.c
  74. 4 10
      Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h
  75. 15 1
      Engine/lib/sdl/src/joystick/SDL_joystick.c
  76. 87 76
      Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps4.c
  77. 122 81
      Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps5.c
  78. 3 3
      Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c
  79. 477 450
      Engine/lib/sdl/src/joystick/os2/SDL_os2joystick.c
  80. 1 0
      Engine/lib/sdl/src/joystick/sort_controllers.py
  81. 175 34
      Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick.c
  82. 2 2
      Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick_c.h
  83. 162 108
      Engine/lib/sdl/src/joystick/windows/SDL_windows_gaming_input.c
  84. 14 7
      Engine/lib/sdl/src/joystick/windows/SDL_xinputjoystick.c
  85. 1 1
      Engine/lib/sdl/src/main/windows/SDL_windows_main.c
  86. 4 4
      Engine/lib/sdl/src/main/windows/version.rc
  87. 3 5
      Engine/lib/sdl/src/misc/emscripten/SDL_sysurl.c
  88. 13 0
      Engine/lib/sdl/src/misc/unix/SDL_sysurl.c
  89. 1 1
      Engine/lib/sdl/src/render/SDL_render.c
  90. 1 1
      Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c
  91. 6 1
      Engine/lib/sdl/src/render/direct3d12/SDL_render_d3d12.c
  92. 16 2
      Engine/lib/sdl/src/render/metal/SDL_render_metal.m
  93. 6 10
      Engine/lib/sdl/src/stdlib/SDL_iconv.c
  94. 3 1
      Engine/lib/sdl/src/stdlib/SDL_string.c
  95. 24 2
      Engine/lib/sdl/src/test/SDL_test_compare.c
  96. 20 30
      Engine/lib/sdl/src/thread/windows/SDL_sysmutex.c
  97. 2 2
      Engine/lib/sdl/src/thread/windows/SDL_systhread.c
  98. 9 5
      Engine/lib/sdl/src/video/SDL_video.c
  99. 2 0
      Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.h
  100. 9 1
      Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.m

+ 1 - 1
Engine/lib/CMakeLists.txt

@@ -66,6 +66,7 @@ mark_as_advanced(SDL_JOYSTICK)
 mark_as_advanced(SDL_KMSDRM)
 mark_as_advanced(SDL_LIBC)
 mark_as_advanced(SDL_LIBSAMPLERATE)
+mark_as_advanced(SDL_LIBUDEV)
 mark_as_advanced(SDL_LOADSO)
 mark_as_advanced(SDL_LOCALE)
 mark_as_advanced(SDL_METAL)
@@ -97,7 +98,6 @@ mark_as_advanced(SDL_TEST)
 mark_as_advanced(SDL_TESTS)
 mark_as_advanced(SDL_THREADS)
 mark_as_advanced(SDL_TIMERS)
-mark_as_advanced(SDL_TIMERS)
 mark_as_advanced(SDL_VENDOR_INFO)
 mark_as_advanced(SDL_VIDEO)
 mark_as_advanced(SDL_VIRTUAL_JOYSTICK)

+ 0 - 90
Engine/lib/sdl/.clang-format

@@ -1,90 +0,0 @@
----
-AlignConsecutiveMacros: Consecutive
-AlignConsecutiveAssignments: None
-AlignConsecutiveBitFields: None
-AlignConsecutiveDeclarations: None
-AlignEscapedNewlines: Right
-AlignOperands: Align
-AlignTrailingComments: true
-
-AllowAllArgumentsOnNextLine: true
-AllowAllParametersOfDeclarationOnNextLine: true
-AllowShortEnumsOnASingleLine: true
-AllowShortBlocksOnASingleLine: Never
-AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: Never
-AllowShortLoopsOnASingleLine: false
-
-AlwaysBreakAfterDefinitionReturnType: None
-AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: false
-AlwaysBreakTemplateDeclarations: MultiLine
-
-# Custom brace breaking
-BreakBeforeBraces: Custom
-BraceWrapping:
-  AfterCaseLabel: true
-  AfterClass: true
-  AfterControlStatement: Never
-  AfterEnum: true
-  AfterFunction: true
-  AfterNamespace: true
-  AfterObjCDeclaration: true
-  AfterStruct: true
-  AfterUnion: true
-  AfterExternBlock: false
-  BeforeElse: false
-  BeforeWhile: false
-  IndentBraces: false
-  SplitEmptyFunction: true
-  SplitEmptyRecord: true
-
-# Make the closing brace of container literals go to a new line
-Cpp11BracedListStyle: false
-
-# Never format includes
-IncludeBlocks: Preserve
-# clang-format version 4.0 through 12.0:
-#SortIncludes: false
-# clang-format version 13.0+:
-#SortIncludes: Never
-
-# No length limit, in case it breaks macros, you can
-# disable it with /* clang-format off/on */ comments
-ColumnLimit: 0
-
-IndentWidth: 4
-ContinuationIndentWidth: 4
-IndentCaseLabels: false
-IndentCaseBlocks: false
-IndentGotoLabels: true
-IndentPPDirectives: None
-IndentExternBlock: NoIndent
-
-PointerAlignment: Right
-SpaceAfterCStyleCast: false
-SpacesInCStyleCastParentheses: false
-SpacesInConditionalStatement: false
-SpacesInContainerLiterals: true
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeCaseColon: false
-SpaceBeforeParens: ControlStatements
-SpaceAroundPointerQualifiers: Default
-SpaceInEmptyBlock: false
-SpaceInEmptyParentheses: false
-
-UseCRLF: false
-UseTab: Never
-
-ForEachMacros:
-  [
-    "spa_list_for_each",
-    "spa_list_for_each_safe",
-    "wl_list_for_each",
-    "wl_array_for_each",
-    "udev_list_entry_foreach",
-  ]
-
----
-

+ 0 - 79
Engine/lib/sdl/.editorconfig

@@ -1,79 +0,0 @@
-# For format see editorconfig.org
-# Copyright 2022 Collabora Ltd.
-# SPDX-License-Identifier: Zlib
-
-root = true
-
-[*.{c,cg,cpp,gradle,h,java,m,metal,pl,py,S,sh,txt}]
-indent_size = 4
-indent_style = space
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[*.{html,js,json,m4,yml,yaml,vcxproj,vcxproj.filters}]
-indent_size = 2
-indent_style = space
-
-[*.xml]
-indent_size = 4
-indent_style = space
-
-[{CMakeLists.txt,sdl2-config*.cmake.in,cmake/*.cmake}]
-indent_size = 2
-indent_style = space
-
-[{cmake_uninstall.cmake.in,test/CMakeLists.txt}]
-indent_size = 4
-indent_style = space
-
-[configure.ac]
-# Inconsistently 2-, 4- or occasionally 3-space indented, but mostly 4,
-# so let's use 4 for new code
-indent_size = 4
-indent_style = space
-
-[{Makefile.*,*.mk,*.sln,*.pbxproj,*.plist}]
-indent_size = 8
-indent_style = tab
-tab_width = 8
-
-[Makefile.os2]
-indent_size = 4
-indent_style = space
-
-[test/Makefile.os2]
-indent_size = 2
-indent_style = space
-
-[{src/core/os2/geniconv/makefile,src/core/os2/geniconv/os2cp.c}]
-indent_size = 2
-indent_style = space
-
-[src/joystick/controller_type.*]
-indent_style = tab
-
-[src/joystick/hidapi/steam/*.h]
-indent_style = tab
-
-[src/libm/*.c]
-indent_style = tab
-
-[src/test/SDL_test_{crc32,md5,random}.c]
-indent_size = 2
-indent_style = space
-
-[src/video/yuv2rgb/*.{c,h}]
-indent_style = tab
-
-[wayland-protocols/*.xml]
-indent_size = 2
-indent_style = space
-
-[*.{markdown,md}]
-indent_size = 4
-indent_style = space
-# Markdown syntax treats tabs as 4 spaces
-tab_width = 4
-
-[{*.bat,*.rc}]
-end_of_line = crlf

+ 0 - 188
Engine/lib/sdl/.gitignore

@@ -1,188 +0,0 @@
-aclocal.m4
-autom4te*
-config.cache
-config.log
-config.status
-libtool
-Makefile
-Makefile.rules
-sdl2-config
-sdl2-config.cmake
-sdl2-config-version.cmake
-sdl2.pc
-SDL2.spec
-build
-gen
-Build
-buildbot
-/VERSION.txt
-
-*.so
-*.so.*
-*.dll
-*.exe
-*.o
-*.obj
-*.res
-*.lib
-*.a
-*.la
-*.dSYM
-*,e1f
-*,ff8
-*.lnk
-*.err
-*.exp
-*.map
-*.orig
-*~
-*.swp
-*.tmp
-*.rej
-
-# for CMake
-CMakeFiles/
-CMakeCache.txt
-cmake_install.cmake
-cmake_uninstall.cmake
-SDL2ConfigVersion.cmake
-.ninja_*
-*.ninja
-
-# for CLion
-.idea
-cmake-build-*
-
-# for Xcode
-*.mode1*
-*.perspective*
-*.pbxuser
-(^|/)build($|/)
-.DS_Store
-xcuserdata
-*.xcworkspace
-
-# for QtCreator
-CMakeLists.txt.user
-build*/
-*.pro.user*
-
-# for Visual C++
-.vs
-Debug
-Release
-*.user
-*.ncb
-*.suo
-*.sdf
-VisualC/tests/controllermap/axis.bmp
-VisualC/tests/controllermap/button.bmp
-VisualC/tests/controllermap/controllermap.bmp
-VisualC/tests/controllermap/controllermap_back.bmp
-VisualC/tests/loopwave/sample.wav
-VisualC/tests/testautomation/CompareSurfaces0001_Reference.bmp
-VisualC/tests/testautomation/CompareSurfaces0001_TestOutput.bmp
-VisualC/tests/testgamecontroller/axis.bmp
-VisualC/tests/testgamecontroller/button.bmp
-VisualC/tests/testgamecontroller/controllermap.bmp
-VisualC/tests/testgamecontroller/controllermap_back.bmp
-VisualC/tests/testoverlay2/moose.dat
-VisualC/tests/testrendertarget/icon.bmp
-VisualC/tests/testrendertarget/sample.bmp
-VisualC/tests/testscale/icon.bmp
-VisualC/tests/testscale/sample.bmp
-VisualC/tests/testsprite2/icon.bmp
-VisualC/tests/testyuv/testyuv.bmp
-VisualC/visualtest/icon.bmp
-VisualC/visualtest/testquit.actions
-VisualC/visualtest/testquit.config
-VisualC/visualtest/testquit.exe
-VisualC/visualtest/testquit.parameters
-VisualC/visualtest/testsprite2.exe
-VisualC/visualtest/testsprite2_sample.actions
-VisualC/visualtest/testsprite2_sample.config
-VisualC/visualtest/testsprite2_sample.parameters
-VisualC-GDK/**/Layout
-
-# for Android
-android-project/local.properties
-android-project/.gradle/
-
-test/checkkeys
-test/checkkeysthreads
-test/controllermap
-test/loopwave
-test/loopwavequeue
-test/testatomic
-test/testaudiocapture
-test/testaudiohotplug
-test/testaudioinfo
-test/testautomation
-test/testbounds
-test/testcustomcursor
-test/testdisplayinfo
-test/testdraw2
-test/testdrawchessboard
-test/testdropfile
-test/testerror
-test/testevdev
-test/testfile
-test/testfilesystem
-test/testgamecontroller
-test/testgeometry
-test/testgesture
-test/testgl2
-test/testgles
-test/testgles2
-test/testhaptic
-test/testhittesting
-test/testhotplug
-test/testiconv
-test/testime
-test/testintersections
-test/testjoystick
-test/testkeys
-test/testloadso
-test/testlocale
-test/testlock
-test/testmessage
-test/testmouse
-test/testmultiaudio
-test/testnative
-test/testoverlay2
-test/testplatform
-test/testpower
-test/testqsort
-test/testrelative
-test/testrendercopyex
-test/testrendertarget
-test/testresample
-test/testrumble
-test/testscale
-test/testsem
-test/testsensor
-test/testshader
-test/testshape
-test/testsprite2
-test/testspriteminimal
-test/teststreaming
-test/testsurround
-test/testthread
-test/testtimer
-test/testurl
-test/testver
-test/testviewport
-test/testvulkan
-test/testwm2
-test/testyuv
-test/torturethread
-
-builddir/
-!build-scripts/
-debian/*.debhelper.log
-debian/*.substvars
-debian/*.tar.gz
-debian/.debhelper/
-debian/files
-debian/libsdl*/
-debian/tmp/

+ 0 - 17
Engine/lib/sdl/.wikiheaders-options

@@ -1,17 +0,0 @@
-projectfullname = SDL2
-projectshortname = SDL2
-incsubdir = include
-wikisubdir = SDL2
-readmesubdir = docs
-apiprefixregex = (SDL_|SDLK_|KMOD_|AUDIO_)
-mainincludefname = SDL.h
-versionfname = include/SDL_version.h
-versionmajorregex = \A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z
-versionminorregex = \A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z
-versionpatchregex = \A\#define\s+SDL_PATCHLEVEL\s+(\d+)\Z
-selectheaderregex = \ASDL.*?\.h\Z
-projecturl = https://libsdl.org/
-wikiurl = https://wiki.libsdl.org/SDL2
-bugreporturl = https://github.com/libsdl-org/sdlwiki/issues/new
-warn_about_missing = 0
-wikipreamble = (This is the legacy documentation for stable SDL2, the current stable version; [SDL3](https://wiki.libsdl.org/SDL3/) is the current development version.)

+ 30 - 12
Engine/lib/sdl/CMakeLists.txt

@@ -2,6 +2,9 @@ if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
   message(FATAL_ERROR "Prevented in-tree build. Please create a build directory outside of the SDL source code and run \"cmake -S ${CMAKE_SOURCE_DIR} -B .\" from there")
 endif()
 
+# MSVC runtime library flags are selected by an abstraction.
+set(CMAKE_POLICY_DEFAULT_CMP0091 NEW)
+
 cmake_minimum_required(VERSION 3.0.0...3.5)
 project(SDL2 C CXX)
 
@@ -84,7 +87,7 @@ endif()
 # See docs/release_checklist.md
 set(SDL_MAJOR_VERSION 2)
 set(SDL_MINOR_VERSION 28)
-set(SDL_MICRO_VERSION 1)
+set(SDL_MICRO_VERSION 4)
 set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}")
 
 # Set defaults preventing destination file conflicts
@@ -224,11 +227,13 @@ elseif(MSVC_VERSION GREATER 1400) # VisualStudio 8.0+
 elseif(CMAKE_C_COMPILER_ID MATCHES "^Intel$")
   set(OPT_DEF_ASM TRUE)
   set(USE_INTELCC TRUE)
+elseif(CMAKE_C_COMPILER_ID MATCHES "QCC")
+  set(USE_QCC TRUE)
 else()
   set(OPT_DEF_ASM FALSE)
 endif()
 
-if(USE_GCC OR USE_CLANG OR USE_INTELCC)
+if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC)
   set(OPT_DEF_GCC_ATOMICS ON)
 endif()
 
@@ -253,6 +258,9 @@ endif()
 if(MSVC)
   option(SDL_FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF)
   if(SDL_FORCE_STATIC_VCRT)
+    if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
+      set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+    endif()
     foreach(flag_var
         CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
         CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
@@ -563,7 +571,7 @@ if(NOT SDL_FOREGROUNDING_SIGNAL STREQUAL "OFF")
 endif()
 
 # Compiler option evaluation
-if(USE_GCC OR USE_CLANG OR USE_INTELCC)
+if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC)
   # Check for -Wall first, so later things can override pieces of it.
   # Note: clang-cl treats -Wall as -Weverything (which is very loud),
   #       /W3 as -Wall, and /W4 as -Wall -Wextra.  So: /W3 is enough.
@@ -620,11 +628,6 @@ if(USE_GCC OR USE_CLANG OR USE_INTELCC)
     endif()
   endif()
 
-  set(CMAKE_REQUIRED_FLAGS "-mpreferred-stack-boundary=2")
-  check_c_source_compiles("int x = 0; int main(int argc, char **argv) { return 0; }"
-    HAVE_GCC_PREFERRED_STACK_BOUNDARY)
-  set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
-
   set(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden -Werror")
   check_c_source_compiles("
       #if !defined(__GNUC__) || __GNUC__ < 4
@@ -1427,6 +1430,12 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
         file(GLOB AIX_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/paudio/*.c)
         list(APPEND SOURCE_FILES ${AIX_AUDIO_SOURCES})
         set(HAVE_SDL_AUDIO TRUE)
+    elseif(QNX)
+        set(SDL_AUDIO_DRIVER_QSA 1)
+        file(GLOB QSA_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/qsa/*.c)
+        list(APPEND SOURCE_FILES ${QSA_AUDIO_SOURCES})
+        list(APPEND EXTRA_LIBS asound)
+        set(HAVE_SDL_AUDIO TRUE)
     endif()
     CheckOSS()
     CheckALSA()
@@ -1458,6 +1467,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
       set(SDL_VIDEO_VULKAN 1)
       set(HAVE_VULKAN TRUE)
     endif()
+    CheckQNXScreen()
   endif()
 
   if(UNIX)
@@ -1708,6 +1718,13 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
     set(HAVE_RPATH TRUE)
   endif()
 
+  if(QNX)
+    # QNX's *printf() family generates a SIGSEGV if NULL is passed for a string
+    # specifier (on purpose), but SDL expects "(null)". Use the built-in
+    # implementation.
+    set(HAVE_VSNPRINTF 0)
+    set(USE_POSIX_SPAWN 1)
+  endif()
 elseif(WINDOWS)
   find_program(WINDRES windres)
 
@@ -1766,7 +1783,7 @@ elseif(WINDOWS)
     check_include_file(ddraw.h HAVE_DDRAW_H)
     check_include_file(dsound.h HAVE_DSOUND_H)
     check_include_file(dinput.h HAVE_DINPUT_H)
-    if(WINDOWS_STORE OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM")
+    if(WINDOWS_STORE OR SDL_CPU_ARM32)
       set(HAVE_DINPUT_H 0)
     endif()
     check_include_file(dxgi.h HAVE_DXGI_H)
@@ -1926,7 +1943,7 @@ elseif(WINDOWS)
 
   # Libraries for Win32 native and MinGW
   if(NOT WINDOWS_STORE)
-    list(APPEND EXTRA_LIBS user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)
+    list(APPEND EXTRA_LIBS kernel32 user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)
   endif()
 
   if(WINDOWS_STORE)
@@ -3187,7 +3204,7 @@ if (SDL_ASAN)
 endif()
 
 if(SDL_CCACHE AND NOT CMAKE_VERSION VERSION_LESS 3.4)
-  cmake_minimum_required(VERSION 3.4)
+  cmake_minimum_required(VERSION 3.4...3.5)
   find_program(CCACHE_BINARY ccache)
   if(CCACHE_BINARY)
     set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_BINARY})
@@ -3334,6 +3351,7 @@ if(SDL_SHARED)
   # alias target for in-tree builds
   add_library(SDL2::SDL2 ALIAS SDL2)
   set_target_properties(SDL2 PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
+  set_target_properties(SDL2 PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS FALSE)
   if(NOT SDL_LIBC)
     if(SDL_CPU_X86)
       # FIXME: should be added for all architectures (missing symbols for ARM)
@@ -3368,7 +3386,7 @@ if(SDL_SHARED)
       OUTPUT_NAME "SDL2")
   endif()
   # Note: The clang toolset for Visual Studio does not support /NODEFAULTLIB.
-  if(MSVC AND NOT SDL_LIBC AND NOT MSVC_CLANG AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM")
+  if(MSVC AND NOT SDL_LIBC AND NOT MSVC_CLANG AND NOT SDL_CPU_ARM32)
     # Don't try to link with the default set of libraries.
     if(NOT WINDOWS_STORE)
       set_property(TARGET SDL2 APPEND_STRING PROPERTY LINK_FLAGS " /NODEFAULTLIB")

+ 1 - 1
Engine/lib/sdl/Makefile.os2

@@ -15,7 +15,7 @@
 LIBNAME = SDL2
 MAJOR_VERSION = 2
 MINOR_VERSION = 28
-MICRO_VERSION = 1
+MICRO_VERSION = 4
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 DESCRIPTION = Simple DirectMedia Layer 2
 

+ 1 - 1
Engine/lib/sdl/Makefile.w32

@@ -6,7 +6,7 @@
 LIBNAME = SDL2
 MAJOR_VERSION = 2
 MINOR_VERSION = 28
-MICRO_VERSION = 1
+MICRO_VERSION = 4
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 
 LIBHOME = .

+ 119 - 0
Engine/lib/sdl/SDL2.spec

@@ -0,0 +1,119 @@
+Summary: Simple DirectMedia Layer
+Name: SDL2
+Version: 2.28.4
+Release: 2
+Source: http://www.libsdl.org/release/%{name}-%{version}.tar.gz
+URL: http://www.libsdl.org/
+License: zlib
+Group: System Environment/Libraries
+BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
+Prefix: %{_prefix}
+%ifos linux
+Provides: libSDL2-2.0.so.0
+%endif
+
+%define __defattr %defattr(-,root,root)
+%define __soext so
+
+%description
+This is the Simple DirectMedia Layer, a generic API that provides low
+level access to audio, keyboard, mouse, and display framebuffer across
+multiple platforms.
+
+%package devel
+Summary: Libraries, includes and more to develop SDL applications.
+Group: Development/Libraries
+Requires: %{name} = %{version}
+
+%description devel
+This is the Simple DirectMedia Layer, a generic API that provides low
+level access to audio, keyboard, mouse, and display framebuffer across
+multiple platforms.
+
+This is the libraries, include files and other resources you can use
+to develop SDL applications.
+
+
+%prep
+%setup -q 
+
+%build
+%ifos linux
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix} --disable-video-directfb
+%else
+%configure
+%endif
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%ifos linux
+make install prefix=$RPM_BUILD_ROOT%{prefix} \
+             bindir=$RPM_BUILD_ROOT%{_bindir} \
+             libdir=$RPM_BUILD_ROOT%{_libdir} \
+             includedir=$RPM_BUILD_ROOT%{_includedir} \
+             datadir=$RPM_BUILD_ROOT%{_datadir} \
+             mandir=$RPM_BUILD_ROOT%{_mandir}
+%else
+%makeinstall
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%{__defattr}
+%doc README*.txt LICENSE.txt CREDITS.txt BUGS.txt
+%{_libdir}/lib*.%{__soext}.*
+
+%files devel
+%{__defattr}
+%doc docs/README*.md
+%{_bindir}/*-config
+%{_libdir}/lib*.a
+%{_libdir}/lib*.la
+%{_libdir}/lib*.%{__soext}
+%{_includedir}/*/*.h
+%{_libdir}/cmake/*
+%{_libdir}/pkgconfig/SDL2/*
+%{_datadir}/aclocal/*
+
+%changelog
+* Thu Jun 04 2015 Ryan C. Gordon <[email protected]>
+- Fixed README paths.
+
+* Sun Dec 07 2014 Simone Contini <[email protected]>
+- Fixed changelog date issue and docs filenames
+
+* Sun Jan 22 2012 Sam Lantinga <[email protected]>
+- Updated for SDL 2.0
+
+* Tue May 16 2006 Sam Lantinga <[email protected]>
+- Removed support for Darwin, due to build problems on ps2linux
+
+* Sat Jan 03 2004 Anders Bjorklund <[email protected]>
+- Added support for Darwin, updated spec file
+
+* Wed Jan 19 2000 Sam Lantinga <[email protected]>
+- Re-integrated spec file into SDL distribution
+- 'name' and 'version' come from configure 
+- Some of the documentation is devel specific
+- Removed SMP support from %build - it doesn't work with libtool anyway
+
+* Tue Jan 18 2000 Hakan Tandogan <[email protected]>
+- Hacked Mandrake sdl spec to build 1.1
+
+* Sun Dec 19 1999 John Buswell <[email protected]>
+- Build Release
+
+* Sat Dec 18 1999 John Buswell <[email protected]>
+- Add symlink for libSDL-1.0.so.0 required by sdlbomber
+- Added docs
+
+* Thu Dec 09 1999 Lenny Cartier <[email protected]>
+- v 1.0.0
+
+* Mon Nov  1 1999 Chmouel Boudjnah <[email protected]>
+- First spec file for Mandrake distribution.
+
+# end of file

+ 1 - 0
Engine/lib/sdl/VERSION.txt

@@ -0,0 +1 @@
+release-2.28.4-0-gcc016b004

+ 54 - 0
Engine/lib/sdl/VisualC/pkg-support/cmake/sdl2-config-version.cmake

@@ -0,0 +1,54 @@
+# based on the files generated by CMake's write_basic_package_version_file
+
+# SDL2 CMake version configuration file:
+# This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-VC
+
+if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../include/SDL_version.h")
+    message(AUTHOR_WARNING "Could not find SDL_version.h. This script is meant to be placed in the root of SDL2-devel-2.x.y-VC")
+    return()
+endif()
+
+file(READ "${CMAKE_CURRENT_LIST_DIR}/../include/SDL_version.h" _sdl_version_h)
+string(REGEX MATCH "#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)" _sdl_major_re "${_sdl_version_h}")
+set(_sdl_major "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)" _sdl_minor_re "${_sdl_version_h}")
+set(_sdl_minor "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)" _sdl_patch_re "${_sdl_version_h}")
+set(_sdl_patch "${CMAKE_MATCH_1}")
+if(_sdl_major_re AND _sdl_minor_re AND _sdl_patch_re)
+    set(PACKAGE_VERSION "${_sdl_major}.${_sdl_minor}.${_sdl_patch}")
+else()
+    message(AUTHOR_WARNING "Could not extract version from SDL_version.h.")
+    return()
+endif()
+
+if(PACKAGE_FIND_VERSION_RANGE)
+    # Package version must be in the requested version range
+    if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+        OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+        OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    else()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    endif()
+else()
+    if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    else()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+        if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+            set(PACKAGE_VERSION_EXACT TRUE)
+        endif()
+    endif()
+endif()
+
+# if the using project doesn't have CMAKE_SIZEOF_VOID_P set, fail.
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
+    set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
+
+# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
+if(NOT (CMAKE_SIZEOF_VOID_P STREQUAL "8" OR CMAKE_SIZEOF_VOID_P STREQUAL "4"))
+    set(PACKAGE_VERSION "${PACKAGE_VERSION} (32+64bit)")
+    set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()

+ 117 - 0
Engine/lib/sdl/VisualC/pkg-support/cmake/sdl2-config.cmake

@@ -0,0 +1,117 @@
+# SDL2 CMake configuration file:
+# This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-VC
+
+cmake_minimum_required(VERSION 3.0...3.5)
+
+include(FeatureSummary)
+set_package_properties(SDL2 PROPERTIES
+    URL "https://www.libsdl.org/"
+    DESCRIPTION "low level access to audio, keyboard, mouse, joystick, and graphics hardware"
+)
+
+# Copied from `configure_package_config_file`
+macro(set_and_check _var _file)
+    set(${_var} "${_file}")
+    if(NOT EXISTS "${_file}")
+        message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
+    endif()
+endmacro()
+
+# Copied from `configure_package_config_file`
+macro(check_required_components _NAME)
+    foreach(comp ${${_NAME}_FIND_COMPONENTS})
+        if(NOT ${_NAME}_${comp}_FOUND)
+            if(${_NAME}_FIND_REQUIRED_${comp})
+                set(${_NAME}_FOUND FALSE)
+            endif()
+        endif()
+    endforeach()
+endmacro()
+
+set(SDL2_FOUND TRUE)
+
+if(CMAKE_SIZEOF_VOID_P STREQUAL "4")
+    set(_sdl_arch_subdir "x86")
+elseif(CMAKE_SIZEOF_VOID_P STREQUAL "8")
+    set(_sdl_arch_subdir "x64")
+else()
+    set(SDL2_FOUND FALSE)
+    return()
+endif()
+
+# For compatibility with autotools sdl2-config.cmake, provide SDL2_* variables.
+
+set_and_check(SDL2_PREFIX       "${CMAKE_CURRENT_LIST_DIR}/..")
+set_and_check(SDL2_EXEC_PREFIX  "${CMAKE_CURRENT_LIST_DIR}/..")
+set_and_check(SDL2_INCLUDE_DIR  "${SDL2_PREFIX}/include")
+set(SDL2_INCLUDE_DIRS           "${SDL2_INCLUDE_DIR}")
+set_and_check(SDL2_BINDIR       "${SDL2_PREFIX}/lib/${_sdl_arch_subdir}")
+set_and_check(SDL2_LIBDIR       "${SDL2_PREFIX}/lib/${_sdl_arch_subdir}")
+
+set(SDL2_LIBRARIES      SDL2::SDL2main SDL2::SDL2)
+set(SDL2MAIN_LIBRARY    SDL2::SDL2main)
+set(SDL2TEST_LIBRARY    SDL2::SDL2test)
+
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL2-target.cmake files.
+
+set(_sdl2_library     "${SDL2_LIBDIR}/SDL2.lib")
+set(_sdl2_dll_library "${SDL2_BINDIR}/SDL2.dll")
+if(EXISTS "${_sdl2_library}" AND EXISTS "${_sdl2_dll_library}")
+    if(NOT TARGET SDL2::SDL2)
+        add_library(SDL2::SDL2 SHARED IMPORTED)
+        set_target_properties(SDL2::SDL2
+            PROPERTIES
+                INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}"
+                IMPORTED_IMPLIB "${_sdl2_library}"
+                IMPORTED_LOCATION "${_sdl2_dll_library}"
+                COMPATIBLE_INTERFACE_BOOL "SDL2_SHARED"
+                INTERFACE_SDL2_SHARED "ON"
+                COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+                INTERFACE_SDL_VERSION "SDL2"
+        )
+    endif()
+    set(SDL2_SDL2_FOUND TRUE)
+else()
+    set(SDL2_SDL2_FOUND FALSE)
+endif()
+unset(_sdl2_library)
+unset(_sdl2_dll_library)
+
+set(_sdl2main_library "${SDL2_LIBDIR}/SDL2main.lib")
+if(EXISTS "${_sdl2main_library}")
+    if(NOT TARGET SDL2::SDL2main)
+        add_library(SDL2::SDL2main STATIC IMPORTED)
+        set_target_properties(SDL2::SDL2main
+        PROPERTIES
+            IMPORTED_LOCATION "${_sdl2main_library}"
+            COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+            INTERFACE_SDL_VERSION "SDL2"
+        )
+    endif()
+    set(SDL2_SDL2main_FOUND TRUE)
+else()
+    set(SDL2_SDL2_FOUND FALSE)
+endif()
+unset(_sdl2main_library)
+
+set(_sdl2test_library "${SDL2_LIBDIR}/SDL2test.lib")
+if(EXISTS "${_sdl2test_library}")
+    if(NOT TARGET SDL2::SDL2test)
+        add_library(SDL2::SDL2test STATIC IMPORTED)
+        set_target_properties(SDL2::SDL2test
+            PROPERTIES
+                INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}"
+                IMPORTED_LOCATION "${_sdl2test_library}"
+                COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+                INTERFACE_SDL_VERSION "SDL2"
+        )
+    endif()
+    set(SDL2_SDL2test_FOUND TRUE)
+else()
+    set(SDL2_SDL2_FOUND FALSE)
+endif()
+unset(_sdl2test_library)
+
+check_required_components(SDL2)

+ 7 - 0
Engine/lib/sdl/WhatsNew.txt

@@ -1,6 +1,13 @@
 
 This is a list of major changes in SDL's version history.
 
+---------------------------------------------------------------------------
+2.28.2:
+---------------------------------------------------------------------------
+General:
+* Added the hint SDL_HINT_JOYSTICK_WGI to control whether to use Windows.Gaming.Input for controllers
+
+
 ---------------------------------------------------------------------------
 2.28.0:
 ---------------------------------------------------------------------------

+ 2 - 2
Engine/lib/sdl/Xcode/SDL/Info-Framework.plist

@@ -19,10 +19,10 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.28.1</string>
+	<string>2.28.4</string>
 	<key>CFBundleSignature</key>
 	<string>SDLX</string>
 	<key>CFBundleVersion</key>
-	<string>2.28.1</string>
+	<string>2.28.4</string>
 </dict>
 </plist>

+ 6 - 6
Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj

@@ -9529,7 +9529,7 @@
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEPLOYMENT_POSTPROCESSING = YES;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.1.0;
+				DYLIB_CURRENT_VERSION = 2801.4.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_ALTIVEC_EXTENSIONS = YES;
@@ -9570,7 +9570,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_LINK_OBJC_RUNTIME = NO;
-				MARKETING_VERSION = 2.28.1;
+				MARKETING_VERSION = 2.28.4;
 				OTHER_LDFLAGS = "-liconv";
 			};
 			name = Release;
@@ -9614,7 +9614,7 @@
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.1.0;
+				DYLIB_CURRENT_VERSION = 2801.4.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -9656,7 +9656,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_LINK_OBJC_RUNTIME = NO;
-				MARKETING_VERSION = 2.28.1;
+				MARKETING_VERSION = 2.28.4;
 				OTHER_LDFLAGS = "-liconv";
 			};
 			name = Debug;
@@ -9863,7 +9863,7 @@
 				DEFINES_MODULE = YES;
 				DEVELOPMENT_TEAM = "";
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.1.0;
+				DYLIB_CURRENT_VERSION = 2801.4.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GCC_DYNAMIC_NO_PIC = NO;
@@ -9915,7 +9915,7 @@
 				DEFINES_MODULE = YES;
 				DEVELOPMENT_TEAM = "";
 				DYLIB_COMPATIBILITY_VERSION = 2801.0.0;
-				DYLIB_CURRENT_VERSION = 2801.1.0;
+				DYLIB_CURRENT_VERSION = 2801.4.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_NS_ASSERTIONS = NO;
 				GCC_C_LANGUAGE_STANDARD = gnu11;

+ 1 - 1
Engine/lib/sdl/Xcode/SDL/pkg-support/SDL.info

@@ -1,4 +1,4 @@
-Title SDL 2.28.1
+Title SDL 2.28.4
 Version 1
 Description SDL Library for Mac OS X (http://www.libsdl.org)
 DefaultLocation /Library/Frameworks

+ 48 - 0
Engine/lib/sdl/Xcode/SDL/pkg-support/resources/CMake/sdl2-config-version.cmake

@@ -0,0 +1,48 @@
+# based on the files generated by CMake's write_basic_package_version_file
+
+# SDL2 CMake version configuration file:
+# This file is meant to be placed in Resources/CMake of a SDL2 framework
+
+if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../../Headers/SDL_version.h")
+    message(AUTHOR_WARNING "Could not find SDL_version.h. This script is meant to be placed in the Resources/CMake directory of SDL2.framework")
+    return()
+endif()
+
+file(READ "${CMAKE_CURRENT_LIST_DIR}/../../Headers/SDL_version.h" _sdl_version_h)
+string(REGEX MATCH "#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)" _sdl_major_re "${_sdl_version_h}")
+set(_sdl_major "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)" _sdl_minor_re "${_sdl_version_h}")
+set(_sdl_minor "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)" _sdl_patch_re "${_sdl_version_h}")
+set(_sdl_patch "${CMAKE_MATCH_1}")
+if(_sdl_major_re AND _sdl_minor_re AND _sdl_patch_re)
+    set(PACKAGE_VERSION "${_sdl_major}.${_sdl_minor}.${_sdl_patch}")
+else()
+    message(AUTHOR_WARNING "Could not extract version from SDL_version.h.")
+    return()
+endif()
+
+if(PACKAGE_FIND_VERSION_RANGE)
+    # Package version must be in the requested version range
+    if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+        OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+        OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    else()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    endif()
+else()
+    if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    else()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+        if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+            set(PACKAGE_VERSION_EXACT TRUE)
+        endif()
+    endif()
+endif()
+
+# if the using project doesn't have CMAKE_SIZEOF_VOID_P set, fail.
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
+    set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()

+ 71 - 0
Engine/lib/sdl/Xcode/SDL/pkg-support/resources/CMake/sdl2-config.cmake

@@ -0,0 +1,71 @@
+# SDL2 CMake configuration file:
+# This file is meant to be placed in Resources/CMake of a SDL2 framework
+
+# INTERFACE_LINK_OPTIONS needs CMake 3.12
+cmake_minimum_required(VERSION 3.12)
+
+include(FeatureSummary)
+set_package_properties(SDL2 PROPERTIES
+    URL "https://www.libsdl.org/"
+    DESCRIPTION "low level access to audio, keyboard, mouse, joystick, and graphics hardware"
+)
+
+# Copied from `configure_package_config_file`
+macro(set_and_check _var _file)
+    set(${_var} "${_file}")
+    if(NOT EXISTS "${_file}")
+        message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
+    endif()
+endmacro()
+
+# Copied from `configure_package_config_file`
+macro(check_required_components _NAME)
+    foreach(comp ${${_NAME}_FIND_COMPONENTS})
+        if(NOT ${_NAME}_${comp}_FOUND)
+            if(${_NAME}_FIND_REQUIRED_${comp})
+                set(${_NAME}_FOUND FALSE)
+            endif()
+        endif()
+    endforeach()
+endmacro()
+
+set(SDL2_FOUND TRUE)
+
+string(REGEX REPLACE "SDL2\\.framework.*" "SDL2.framework" SDL2_FRAMEWORK_PATH "${CMAKE_CURRENT_LIST_DIR}")
+string(REGEX REPLACE "SDL2\\.framework.*" "" SDL2_FRAMEWORK_PARENT_PATH "${CMAKE_CURRENT_LIST_DIR}")
+
+# For compatibility with autotools sdl2-config.cmake, provide SDL2_* variables.
+
+set_and_check(SDL2_PREFIX       "${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_EXEC_PREFIX  "${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_INCLUDE_DIR  "${SDL2_FRAMEWORK_PATH}/Headers")
+set(SDL2_INCLUDE_DIRS           "${SDL2_INCLUDE_DIR};${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_BINDIR       "${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_LIBDIR       "${SDL2_FRAMEWORK_PATH}")
+
+set(SDL2_LIBRARIES "SDL2::SDL2")
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL2-target.cmake files.
+
+if(NOT TARGET SDL2::SDL2)
+    add_library(SDL2::SDL2 INTERFACE IMPORTED)
+    set_target_properties(SDL2::SDL2
+        PROPERTIES
+            INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${SDL2_FRAMEWORK_PARENT_PATH}\""
+            INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}"
+            INTERFACE_LINK_OPTIONS "SHELL:-F \"${SDL2_FRAMEWORK_PARENT_PATH}\";SHELL:-framework SDL2"
+            COMPATIBLE_INTERFACE_BOOL "SDL2_SHARED"
+            INTERFACE_SDL2_SHARED "ON"
+            COMPATIBLE_INTERFACE_STRING "SDL_VERSION"
+            INTERFACE_SDL_VERSION "SDL2"
+    )
+endif()
+set(SDL2_SDL2_FOUND TRUE)
+
+if(NOT TARGET SDL2::SDL2main)
+    add_library(SDL2::SDL2main INTERFACE IMPORTED)
+endif()
+set(SDL2_SDL2main_FOUND TRUE)
+
+check_required_components(SDL2)

+ 0 - 1
Engine/lib/sdl/android-project-ant/AndroidManifest.xml

@@ -1 +0,0 @@
-../android-project/app/src/main/AndroidManifest.xml

+ 0 - 17
Engine/lib/sdl/android-project-ant/ant.properties

@@ -1,17 +0,0 @@
-# This file is used to override default values used by the Ant build system.
-#
-# This file must be checked into Version Control Systems, as it is
-# integral to the build system of your project.
-
-# This file is only used by the Ant script.
-
-# You can use this to override default values such as
-#  'source.dir' for the location of your java source folder and
-#  'out.dir' for the location of your output folder.
-
-# You can also use it define how the release builds are signed by declaring
-# the following properties:
-#  'key.store' for the location of your keystore and
-#  'key.alias' for the name of the key to use.
-# The password will be asked during the build when you use the 'release' target.
-

+ 0 - 17
Engine/lib/sdl/android-project-ant/build.properties

@@ -1,17 +0,0 @@
-# This file is used to override default values used by the Ant build system.
-# 
-# This file must be checked in Version Control Systems, as it is
-# integral to the build system of your project.
-
-# This file is only used by the Ant script.
-
-# You can use this to override default values such as
-#  'source.dir' for the location of your java source folder and
-#  'out.dir' for the location of your output folder.
-
-# You can also use it define how the release builds are signed by declaring
-# the following properties:
-#  'key.store' for the location of your keystore and
-#  'key.alias' for the name of the key to use.
-# The password will be asked during the build when you use the 'release' target.
-

+ 0 - 93
Engine/lib/sdl/android-project-ant/build.xml

@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- This should be changed to the name of your project -->
-<project name="SDLActivity" default="help">
-
-    <!-- The local.properties file is created and updated by the 'android' tool.
-         It contains the path to the SDK. It should *NOT* be checked into
-         Version Control Systems. -->
-    <property file="local.properties" />
-
-    <!-- The ant.properties file can be created by you. It is only edited by the
-         'android' tool to add properties to it.
-         This is the place to change some Ant specific build properties.
-         Here are some properties you may want to change/update:
-
-         source.dir
-             The name of the source directory. Default is 'src'.
-         out.dir
-             The name of the output directory. Default is 'bin'.
-
-         For other overridable properties, look at the beginning of the rules
-         files in the SDK, at tools/ant/build.xml
-
-         Properties related to the SDK location or the project target should
-         be updated using the 'android' tool with the 'update' action.
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems.
-
-         -->
-    <property file="ant.properties" />
-
-    <!-- if sdk.dir was not set from one of the property file, then
-         get it from the ANDROID_HOME env var.
-         This must be done before we load project.properties since
-         the proguard config can use sdk.dir -->
-    <property environment="env" />
-    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
-        <isset property="env.ANDROID_HOME" />
-    </condition>
-
-    <!-- The project.properties file is created and updated by the 'android'
-         tool, as well as ADT.
-
-         This contains project specific properties such as project target, and library
-         dependencies. Lower level build properties are stored in ant.properties
-         (or in .classpath for Eclipse projects).
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems. -->
-    <loadproperties srcFile="project.properties" />
-
-    <!-- quick check on sdk.dir -->
-    <fail
-            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
-            unless="sdk.dir"
-    />
-
-    <!--
-        Import per project custom build rules if present at the root of the project.
-        This is the place to put custom intermediary targets such as:
-            -pre-build
-            -pre-compile
-            -post-compile (This is typically used for code obfuscation.
-                           Compiled code location: ${out.classes.absolute.dir}
-                           If this is not done in place, override ${out.dex.input.absolute.dir})
-            -post-package
-            -post-build
-            -pre-clean
-    -->
-    <import file="custom_rules.xml" optional="true" />
-
-    <!-- Import the actual build file.
-
-         To customize existing targets, there are two options:
-         - Customize only one target:
-             - copy/paste the target into this file, *before* the
-               <import> task.
-             - customize it to your needs.
-         - Customize the whole content of build.xml
-             - copy/paste the content of the rules files (minus the top node)
-               into this file, replacing the <import> task.
-             - customize to your needs.
-
-         ***********************
-         ****** IMPORTANT ******
-         ***********************
-         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
-         in order to avoid having your file be overridden by tools such as "android update project"
-    -->
-    <!-- version-tag: 1 -->
-    <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>

+ 0 - 11
Engine/lib/sdl/android-project-ant/default.properties

@@ -1,11 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-# 
-# This file must be checked in Version Control Systems.
-# 
-# To customize properties used by the Ant build system use,
-# "build.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-16

+ 0 - 1
Engine/lib/sdl/android-project-ant/jni/Android.mk

@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)

+ 0 - 10
Engine/lib/sdl/android-project-ant/jni/Application.mk

@@ -1,10 +0,0 @@
-
-# Uncomment this if you're using STL in your project
-# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information
-# APP_STL := stlport_static 
-
-APP_ABI := armeabi armeabi-v7a x86
-
-# Min SDK level
-APP_PLATFORM=android-10
-

+ 0 - 18
Engine/lib/sdl/android-project-ant/jni/src/Android.mk

@@ -1,18 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := main
-
-SDL_PATH := ../SDL
-
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
-
-# Add your application source files here...
-LOCAL_SRC_FILES := YourSourceHere.c
-
-LOCAL_SHARED_LIBRARIES := SDL2
-
-LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog
-
-include $(BUILD_SHARED_LIBRARY)

+ 0 - 12
Engine/lib/sdl/android-project-ant/jni/src/Android_static.mk

@@ -1,12 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := main
-
-LOCAL_SRC_FILES := YourSourceHere.c
-
-LOCAL_STATIC_LIBRARIES := SDL2_static
-
-include $(BUILD_SHARED_LIBRARY)
-$(call import-module,SDL)LOCAL_PATH := $(call my-dir)

+ 0 - 20
Engine/lib/sdl/android-project-ant/proguard-project.txt

@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-#   http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-#   public *;
-#}

+ 0 - 14
Engine/lib/sdl/android-project-ant/project.properties

@@ -1,14 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-16

BIN
Engine/lib/sdl/android-project-ant/res/drawable-hdpi/ic_launcher.png


BIN
Engine/lib/sdl/android-project-ant/res/drawable-mdpi/ic_launcher.png


BIN
Engine/lib/sdl/android-project-ant/res/drawable-xhdpi/ic_launcher.png


BIN
Engine/lib/sdl/android-project-ant/res/drawable-xxhdpi/ic_launcher.png


+ 0 - 13
Engine/lib/sdl/android-project-ant/res/layout/main.xml

@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    >
-<TextView  
-    android:layout_width="fill_parent" 
-    android:layout_height="wrap_content" 
-    android:text="Hello World, SDLActivity"
-    />
-</LinearLayout>
-

+ 0 - 4
Engine/lib/sdl/android-project-ant/res/values/strings.xml

@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <string name="app_name">SDL App</string>
-</resources>

+ 0 - 1
Engine/lib/sdl/android-project-ant/src

@@ -1 +0,0 @@
-../android-project/app/src/main/java

+ 10 - 10
Engine/lib/sdl/android-project/app/build.gradle

@@ -8,22 +8,22 @@ else {
 }
 
 android {
-    compileSdkVersion 31
+    if (buildAsApplication) {
+        namespace "org.libsdl.app"
+    }
+    compileSdkVersion 34
     defaultConfig {
-        if (buildAsApplication) {
-            applicationId "org.libsdl.app"
-        }
-        minSdkVersion 16
-        targetSdkVersion 31
+        minSdkVersion 19
+        targetSdkVersion 34
         versionCode 1
         versionName "1.0"
         externalNativeBuild {
             ndkBuild {
-                arguments "APP_PLATFORM=android-16"
+                arguments "APP_PLATFORM=android-19"
                 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
             }
             // cmake {
-            //     arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
+            //     arguments "-DANDROID_APP_PLATFORM=android-19", "-DANDROID_STL=c++_static"
             //     // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
             //     abiFilters 'arm64-v8a'
             // }
@@ -53,10 +53,10 @@ android {
         }
        
     }
-    lintOptions {
+    lint {
         abortOnError false
     }
-    
+
     if (buildAsLibrary) {
         libraryVariants.all { variant ->
             variant.outputs.each { output ->

+ 0 - 1
Engine/lib/sdl/android-project/app/src/main/AndroidManifest.xml

@@ -3,7 +3,6 @@
      com.gamemaker.game
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.libsdl.app"
     android:versionCode="1"
     android:versionName="1.0"
     android:installLocation="auto">

+ 16 - 18
Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     private static final String TAG = "SDL";
     private static final int SDL_MAJOR_VERSION = 2;
     private static final int SDL_MINOR_VERSION = 28;
-    private static final int SDL_MICRO_VERSION = 1;
+    private static final int SDL_MICRO_VERSION = 4;
 /*
     // Display InputType.SOURCE/CLASS of events and devices
     //
@@ -1345,23 +1345,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             }
         }
 
-        if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) {
-            if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                if (isTextInputEvent(event)) {
-                    if (ic != null) {
-                        ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
-                    } else {
-                        SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
-                    }
-                }
-                onNativeKeyDown(keyCode);
-                return true;
-            } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                onNativeKeyUp(keyCode);
-                return true;
-            }
-        }
-
         if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
             // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
             // they are ignored here because sending them as mouse input to SDL is messy
@@ -1376,6 +1359,21 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             }
         }
 
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            if (isTextInputEvent(event)) {
+                if (ic != null) {
+                    ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
+                } else {
+                    SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
+                }
+            }
+            onNativeKeyDown(keyCode);
+            return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            onNativeKeyUp(keyCode);
+            return true;
+        }
+
         return false;
     }
 

+ 1 - 1
Engine/lib/sdl/android-project/build.gradle

@@ -6,7 +6,7 @@ buildscript {
         google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:7.0.3'
+        classpath 'com.android.tools.build:gradle:8.1.1'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files

+ 1 - 1
Engine/lib/sdl/android-project/gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
 #Thu Nov 11 18:20:34 PST 2021
 distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
 distributionPath=wrapper/dists
 zipStorePath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME

+ 52 - 13
Engine/lib/sdl/build-scripts/config.guess

@@ -1,10 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2022 Free Software Foundation, Inc.
+#   Copyright 1992-2023 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2022-05-25'
+timestamp='2023-08-22'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -47,7 +47,7 @@ me=`echo "$0" | sed -e 's,.*/,,'`
 usage="\
 Usage: $0 [OPTION]
 
-Output the configuration name of the system \`$me' is run on.
+Output the configuration name of the system '$me' is run on.
 
 Options:
   -h, --help         print this help, then exit
@@ -60,13 +60,13 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 
 help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
 
 # Parse command line
 while test $# -gt 0 ; do
@@ -102,8 +102,8 @@ GUESS=
 # temporary files to be created and, as you can see below, it is a
 # headache to deal with in a portable fashion.
 
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
+# use 'HOST_CC' if defined, but it is deprecated.
 
 # Portable tmp directory creation inspired by the Autoconf team.
 
@@ -155,6 +155,9 @@ Linux|GNU|GNU/*)
 
 	set_cc_for_build
 	cat <<-EOF > "$dummy.c"
+	#if defined(__ANDROID__)
+	LIBC=android
+	#else
 	#include <features.h>
 	#if defined(__UCLIBC__)
 	LIBC=uclibc
@@ -169,6 +172,7 @@ Linux|GNU|GNU/*)
 	LIBC=musl
 	#endif
 	#endif
+	#endif
 	EOF
 	cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
 	eval "$cc_set_libc"
@@ -459,7 +463,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
 		UNAME_RELEASE=`uname -v`
 		;;
 	esac
-	# Japanese Language versions have a version number like `4.1.3-JL'.
+	# Japanese Language versions have a version number like '4.1.3-JL'.
 	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
 	GUESS=sparc-sun-sunos$SUN_REL
 	;;
@@ -904,7 +908,7 @@ EOF
 	fi
 	;;
     *:FreeBSD:*:*)
-	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	UNAME_PROCESSOR=`uname -p`
 	case $UNAME_PROCESSOR in
 	    amd64)
 		UNAME_PROCESSOR=x86_64 ;;
@@ -966,11 +970,37 @@ EOF
 	GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
 	GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
 	;;
+    x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+	GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+	;;
+    *:[Mm]anagarm:*:*)
+	GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+	;;
     *:Minix:*:*)
 	GUESS=$UNAME_MACHINE-unknown-minix
 	;;
     aarch64:Linux:*:*)
-	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+	set_cc_for_build
+	CPU=$UNAME_MACHINE
+	LIBCABI=$LIBC
+	if test "$CC_FOR_BUILD" != no_compiler_found; then
+	    ABI=64
+	    sed 's/^	    //' << EOF > "$dummy.c"
+	    #ifdef __ARM_EABI__
+	    #ifdef __ARM_PCS_VFP
+	    ABI=eabihf
+	    #else
+	    ABI=eabi
+	    #endif
+	    #endif
+EOF
+	    cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+	    eval "$cc_set_abi"
+	    case $ABI in
+		eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
+	    esac
+	fi
+	GUESS=$CPU-unknown-linux-$LIBCABI
 	;;
     aarch64_be:Linux:*:*)
 	UNAME_MACHINE=aarch64_be
@@ -1036,7 +1066,16 @@ EOF
     k1om:Linux:*:*)
 	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
 	;;
-    loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+    kvx:Linux:*:*)
+	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+	;;
+    kvx:cos:*:*)
+	GUESS=$UNAME_MACHINE-unknown-cos
+	;;
+    kvx:mbr:*:*)
+	GUESS=$UNAME_MACHINE-unknown-mbr
+	;;
+    loongarch32:Linux:*:* | loongarch64:Linux:*:*)
 	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
 	;;
     m32r*:Linux:*:*)
@@ -1191,7 +1230,7 @@ EOF
 	GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
 	;;
     i*86:OS/2:*:*)
-	# If we were able to find `uname', then EMX Unix compatibility
+	# If we were able to find 'uname', then EMX Unix compatibility
 	# is probably installed.
 	GUESS=$UNAME_MACHINE-pc-os2-emx
 	;;
@@ -1332,7 +1371,7 @@ EOF
 		GUESS=ns32k-sni-sysv
 	fi
 	;;
-    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+    PENTIUM:*:4.0*:*)	# Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
 			# says <[email protected]>
 	GUESS=i586-unisys-sysv4
 	;;

+ 146 - 76
Engine/lib/sdl/build-scripts/config.sub

@@ -1,10 +1,10 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2022 Free Software Foundation, Inc.
+#   Copyright 1992-2023 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2022-01-03'
+timestamp='2023-09-19'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -76,13 +76,13 @@ Report bugs and patches to <[email protected]>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2022 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 
 help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
 
 # Parse command line
 while test $# -gt 0 ; do
@@ -130,7 +130,7 @@ IFS=$saved_IFS
 # Separate into logical components for further validation
 case $1 in
 	*-*-*-*-*)
-		echo Invalid configuration \`"$1"\': more than four components >&2
+		echo "Invalid configuration '$1': more than four components" >&2
 		exit 1
 		;;
 	*-*-*-*)
@@ -145,7 +145,8 @@ case $1 in
 			nto-qnx* | linux-* | uclinux-uclibc* \
 			| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
 			| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
-			| storm-chaos* | os2-emx* | rtmk-nova*)
+			| storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \
+			| windows-* )
 				basic_machine=$field1
 				basic_os=$maybe_os
 				;;
@@ -943,7 +944,7 @@ $basic_machine
 EOF
 		IFS=$saved_IFS
 		;;
-	# We use `pc' rather than `unknown'
+	# We use 'pc' rather than 'unknown'
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
 	i*86 | x86_64)
@@ -1180,7 +1181,7 @@ case $cpu-$vendor in
 		case $cpu in
 			1750a | 580 \
 			| a29k \
-			| aarch64 | aarch64_be \
+			| aarch64 | aarch64_be | aarch64c | arm64ec \
 			| abacus \
 			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
 			| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
@@ -1199,45 +1200,23 @@ case $cpu-$vendor in
 			| d10v | d30v | dlx | dsp16xx \
 			| e2k | elxsi | epiphany \
 			| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+			| javascript \
 			| h8300 | h8500 \
 			| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 			| hexagon \
 			| i370 | i*86 | i860 | i960 | ia16 | ia64 \
 			| ip2k | iq2000 \
 			| k1om \
+			| kvx \
 			| le32 | le64 \
 			| lm32 \
-			| loongarch32 | loongarch64 | loongarchx32 \
+			| loongarch32 | loongarch64 \
 			| m32c | m32r | m32rle \
 			| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
 			| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
 			| m88110 | m88k | maxq | mb | mcore | mep | metag \
 			| microblaze | microblazeel \
-			| mips | mipsbe | mipseb | mipsel | mipsle \
-			| mips16 \
-			| mips64 | mips64eb | mips64el \
-			| mips64octeon | mips64octeonel \
-			| mips64orion | mips64orionel \
-			| mips64r5900 | mips64r5900el \
-			| mips64vr | mips64vrel \
-			| mips64vr4100 | mips64vr4100el \
-			| mips64vr4300 | mips64vr4300el \
-			| mips64vr5000 | mips64vr5000el \
-			| mips64vr5900 | mips64vr5900el \
-			| mipsisa32 | mipsisa32el \
-			| mipsisa32r2 | mipsisa32r2el \
-			| mipsisa32r3 | mipsisa32r3el \
-			| mipsisa32r5 | mipsisa32r5el \
-			| mipsisa32r6 | mipsisa32r6el \
-			| mipsisa64 | mipsisa64el \
-			| mipsisa64r2 | mipsisa64r2el \
-			| mipsisa64r3 | mipsisa64r3el \
-			| mipsisa64r5 | mipsisa64r5el \
-			| mipsisa64r6 | mipsisa64r6el \
-			| mipsisa64sb1 | mipsisa64sb1el \
-			| mipsisa64sr71k | mipsisa64sr71kel \
-			| mipsr5900 | mipsr5900el \
-			| mipstx39 | mipstx39el \
+			| mips* \
 			| mmix \
 			| mn10200 | mn10300 \
 			| moxie \
@@ -1285,7 +1264,7 @@ case $cpu-$vendor in
 				;;
 
 			*)
-				echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+				echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
 				exit 1
 				;;
 		esac
@@ -1306,11 +1285,12 @@ esac
 
 # Decode manufacturer-specific aliases for certain operating systems.
 
-if test x$basic_os != x
+if test x"$basic_os" != x
 then
 
 # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
 # set os.
+obj=
 case $basic_os in
 	gnu/linux*)
 		kernel=linux
@@ -1341,6 +1321,10 @@ EOF
 		kernel=linux
 		os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
 		;;
+	managarm*)
+		kernel=managarm
+		os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
+		;;
 	*)
 		kernel=
 		os=$basic_os
@@ -1506,10 +1490,16 @@ case $os in
 			os=eabi
 			;;
 		    *)
-			os=elf
+			os=
+			obj=elf
 			;;
 		esac
 		;;
+	aout* | coff* | elf* | pe*)
+		# These are machine code file formats, not OSes
+		obj=$os
+		os=
+		;;
 	*)
 		# No normalization, but not necessarily accepted, that comes below.
 		;;
@@ -1528,12 +1518,15 @@ else
 # system, and we'll never get to this point.
 
 kernel=
+obj=
 case $cpu-$vendor in
 	score-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	spu-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	*-acorn)
 		os=riscix1.2
@@ -1543,28 +1536,35 @@ case $cpu-$vendor in
 		os=gnu
 		;;
 	arm*-semi)
-		os=aout
+		os=
+		obj=aout
 		;;
 	c4x-* | tic4x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	c8051-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	clipper-intergraph)
 		os=clix
 		;;
 	hexagon-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	tic54x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	tic55x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	tic6x-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	# This must come before the *-dec entry.
 	pdp10-*)
@@ -1586,19 +1586,24 @@ case $cpu-$vendor in
 		os=sunos3
 		;;
 	m68*-cisco)
-		os=aout
+		os=
+		obj=aout
 		;;
 	mep-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	mips*-cisco)
-		os=elf
+		os=
+		obj=elf
 		;;
 	mips*-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	or32-*)
-		os=coff
+		os=
+		obj=coff
 		;;
 	*-tti)	# must be before sparc entry or we get the wrong os.
 		os=sysv3
@@ -1607,7 +1612,8 @@ case $cpu-$vendor in
 		os=sunos4.1.1
 		;;
 	pru-*)
-		os=elf
+		os=
+		obj=elf
 		;;
 	*-be)
 		os=beos
@@ -1688,10 +1694,12 @@ case $cpu-$vendor in
 		os=uxpv
 		;;
 	*-rom68k)
-		os=coff
+		os=
+		obj=coff
 		;;
 	*-*bug)
-		os=coff
+		os=
+		obj=coff
 		;;
 	*-apple)
 		os=macos
@@ -1709,7 +1717,8 @@ esac
 
 fi
 
-# Now, validate our (potentially fixed-up) OS.
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
+
 case $os in
 	# Sometimes we do "kernel-libc", so those need to count as OSes.
 	musl* | newlib* | relibc* | uclibc*)
@@ -1720,6 +1729,9 @@ case $os in
 	# VxWorks passes extra cpu info in the 4th filed.
 	simlinux | simwindows | spe)
 		;;
+	# See `case $cpu-$os` validation below
+	ghcjs)
+		;;
 	# Now accept the basic system types.
 	# The portable systems comes first.
 	# Each alternative MUST end in a * to match a version number.
@@ -1728,7 +1740,7 @@ case $os in
 	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
 	     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \
 	     | hiux* | abug | nacl* | netware* | windows* \
-	     | os9* | macos* | osx* | ios* \
+	     | os9* | macos* | osx* | ios* | tvos* | watchos* \
 	     | mpw* | magic* | mmixware* | mon960* | lnews* \
 	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
 	     | aos* | aros* | cloudabi* | sortix* | twizzler* \
@@ -1737,11 +1749,11 @@ case $os in
 	     | mirbsd* | netbsd* | dicos* | openedition* | ose* \
 	     | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
 	     | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
-	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
-	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+	     | bosx* | nextstep* | cxux* | oabi* \
+	     | ptx* | ecoff* | winnt* | domain* | vsta* \
 	     | udi* | lites* | ieee* | go32* | aux* | hcos* \
 	     | chorusrdb* | cegcc* | glidix* | serenity* \
-	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+	     | cygwin* | msys* | moss* | proelf* | rtems* \
 	     | midipix* | mingw32* | mingw64* | mint* \
 	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
 	     | interix* | uwin* | mks* | rhapsody* | darwin* \
@@ -1754,7 +1766,7 @@ case $os in
 	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
 	     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
 	     | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
-	     | fiwix* )
+	     | fiwix* | mlibc* | cos* | mbr* )
 		;;
 	# This one is extra strict with allowed versions
 	sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1762,41 +1774,99 @@ case $os in
 		;;
 	none)
 		;;
+	kernel* | msvc* )
+		# Restricted further below
+		;;
+	'')
+		if test x"$obj" = x
+		then
+			echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
+		fi
+		;;
+	*)
+		echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
+		exit 1
+		;;
+esac
+
+case $obj in
+	aout* | coff* | elf* | pe*)
+		;;
+	'')
+		# empty is fine
+		;;
 	*)
-		echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+		echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
+		exit 1
+		;;
+esac
+
+# Here we handle the constraint that a (synthetic) cpu and os are
+# valid only in combination with each other and nowhere else.
+case $cpu-$os in
+	# The "javascript-unknown-ghcjs" triple is used by GHC; we
+	# accept it here in order to tolerate that, but reject any
+	# variations.
+	javascript-ghcjs)
+		;;
+	javascript-* | *-ghcjs)
+		echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
 		exit 1
 		;;
 esac
 
 # As a final step for OS-related things, validate the OS-kernel combination
 # (given a valid OS), if there is a kernel.
-case $kernel-$os in
-	linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
-		   | linux-musl* | linux-relibc* | linux-uclibc* )
+case $kernel-$os-$obj in
+	linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \
+		   | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- )
+		;;
+	uclinux-uclibc*- )
 		;;
-	uclinux-uclibc* )
+	managarm-mlibc*- | managarm-kernel*- )
 		;;
-	-dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
+	windows*-msvc*-)
+		;;
+	-dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- )
 		# These are just libc implementations, not actual OSes, and thus
 		# require a kernel.
-		echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+		echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
 		exit 1
 		;;
-	kfreebsd*-gnu* | kopensolaris*-gnu*)
+	-kernel*- )
+		echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
+		exit 1
 		;;
-	vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+	*-kernel*- )
+		echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
+		exit 1
 		;;
-	nto-qnx*)
+	*-msvc*- )
+		echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
+		exit 1
 		;;
-	os2-emx)
+	kfreebsd*-gnu*- | kopensolaris*-gnu*-)
 		;;
-	*-eabi* | *-gnueabi*)
+	vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
 		;;
-	-*)
+	nto-qnx*-)
+		;;
+	os2-emx-)
+		;;
+	*-eabi*- | *-gnueabi*-)
+		;;
+	none--*)
+		# None (no kernel, i.e. freestanding / bare metal),
+		# can be paired with an machine code file format
+		;;
+	-*-)
 		# Blank kernel with real OS is always fine.
 		;;
-	*-*)
-		echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+	--*)
+		# Blank kernel and OS with real machine code file format is always fine.
+		;;
+	*-*-*)
+		echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
 		exit 1
 		;;
 esac
@@ -1879,7 +1949,7 @@ case $vendor in
 		;;
 esac
 
-echo "$cpu-$vendor-${kernel:+$kernel-}$os"
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
 exit
 
 # Local variables:

+ 18 - 0
Engine/lib/sdl/cmake/sdlchecks.cmake

@@ -905,6 +905,22 @@ macro(CheckOpenGLES)
   endif()
 endmacro()
 
+# Requires:
+# - EGL
+macro(CheckQNXScreen)
+  if(QNX AND HAVE_OPENGL_EGL)
+    check_c_source_compiles("
+        #include <screen/screen.h>
+        int main (int argc, char** argv) { return 0; }" HAVE_QNX_SCREEN)
+    if(HAVE_QNX_SCREEN)
+      set(SDL_VIDEO_DRIVER_QNX 1)
+      file(GLOB QNX_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/qnx/*.c)
+      list(APPEND SOURCE_FILES ${QNX_VIDEO_SOURCES})
+      list(APPEND EXTRA_LIBS screen EGL)
+    endif()
+  endif()
+endmacro()
+
 # Requires:
 # - nada
 # Optional:
@@ -955,6 +971,8 @@ macro(CheckPTHREAD)
     elseif(EMSCRIPTEN)
       set(PTHREAD_CFLAGS "-D_REENTRANT -pthread")
       set(PTHREAD_LDFLAGS "-pthread")
+    elseif(QNX)
+      # pthread support is baked in
     else()
       set(PTHREAD_CFLAGS "-D_REENTRANT")
       set(PTHREAD_LDFLAGS "-lpthread")

+ 4 - 0
Engine/lib/sdl/cmake/sdlplatform.cmake

@@ -28,6 +28,8 @@ macro(SDL_DetectCMakePlatform)
       set(SDL_CMAKE_PLATFORM AIX)
     elseif(CMAKE_SYSTEM_NAME MATCHES "Minix.*")
       set(SDL_CMAKE_PLATFORM MINIX)
+    elseif(CMAKE_SYSTEM_NAME MATCHES "QNX")
+      set(SDL_CMAKE_PLATFORM QNX)
     endif()
   elseif(APPLE)
     if(CMAKE_SYSTEM_NAME MATCHES ".*Darwin.*")
@@ -48,6 +50,8 @@ macro(SDL_DetectCMakePlatform)
     set(SDL_CMAKE_PLATFORM HAIKU)
   elseif(NINTENDO_3DS)
     set(SDL_CMAKE_PLATFORM N3DS)
+  elseif(OS2)
+    set(SDL_CMAKE_PLATFORM OS2)
   endif()
   if(SDL_CMAKE_PLATFORM)
     set(${SDL_CMAKE_PLATFORM} TRUE)

+ 4 - 42
Engine/lib/sdl/configure

@@ -3507,7 +3507,7 @@ orig_CFLAGS="$CFLAGS"
 # See docs/release_checklist.md
 SDL_MAJOR_VERSION=2
 SDL_MINOR_VERSION=28
-SDL_MICRO_VERSION=1
+SDL_MICRO_VERSION=4
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 
 SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION`
@@ -23026,41 +23026,6 @@ printf "%s\n" "$have_gcc_no_strict_aliasing" >&6; }
     fi
 }
 
-CheckStackBoundary()
-{
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GCC -mpreferred-stack-boundary option" >&5
-printf %s "checking for GCC -mpreferred-stack-boundary option... " >&6; }
-    have_gcc_preferred_stack_boundary=no
-
-    save_CFLAGS="$CFLAGS"
-    CFLAGS="$save_CFLAGS -mpreferred-stack-boundary=2"
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-    int x = 0;
-
-int
-main (void)
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-  have_gcc_preferred_stack_boundary=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_gcc_preferred_stack_boundary" >&5
-printf "%s\n" "$have_gcc_preferred_stack_boundary" >&6; }
-    CFLAGS="$save_CFLAGS"
-
-    if test x$have_gcc_preferred_stack_boundary = xyes; then
-        EXTRA_CFLAGS="$EXTRA_CFLAGS -mpreferred-stack-boundary=2"
-    fi
-}
-
 CheckWerror()
 {
     # Check whether --enable-werror was given.
@@ -27474,9 +27439,6 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_wince" >&5
 printf "%s\n" "$have_wince" >&6; }
 
-    # This fixes Windows stack alignment with newer GCC
-    CheckStackBoundary
-
     # headers needed elsewhere
     ac_fn_c_check_header_compile "$LINENO" "tpcshrd.h" "ac_cv_header_tpcshrd_h" "$ac_includes_default"
 if test "x$ac_cv_header_tpcshrd_h" = xyes
@@ -28285,7 +28247,7 @@ fi
                 enable_hidapi_libusb=yes
                 require_hidapi_libusb=yes
                 ;;
-           *-*-os2* )
+            *-*-os2* )
                 enable_hidapi_libusb=yes
                 ;;
         esac
@@ -29678,7 +29640,7 @@ printf "%s\n" "#define SDL_VIDEO_DRIVER_OS2 1" >>confdefs.h
 
             SOURCES="$SOURCES $srcdir/src/video/os2/*.c"
             have_video=yes
-            SUMMARY_video="${SUMMARY_video} os/2"
+            SUMMARY_video="${SUMMARY_video} OS/2"
         fi
         # Set up files for the audio library
         if test x$enable_audio = xyes; then
@@ -29687,7 +29649,7 @@ printf "%s\n" "#define SDL_AUDIO_DRIVER_OS2 1" >>confdefs.h
 
             SOURCES="$SOURCES $srcdir/src/audio/os2/*.c"
             have_audio=yes
-            SUMMARY_audio="${SUMMARY_audio} os/2"
+            SUMMARY_audio="${SUMMARY_audio} OS/2"
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmmpm2"
         fi
         # Set up files for the thread library

+ 4 - 27
Engine/lib/sdl/configure.ac

@@ -13,7 +13,7 @@ dnl Set various version strings - taken gratefully from the GTk sources
 # See docs/release_checklist.md
 SDL_MAJOR_VERSION=2
 SDL_MINOR_VERSION=28
-SDL_MICRO_VERSION=1
+SDL_MICRO_VERSION=4
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 
 SDL_BINARY_AGE=`expr $SDL_MINOR_VERSION \* 100 + $SDL_MICRO_VERSION`
@@ -1558,26 +1558,6 @@ CheckNoStrictAliasing()
     fi
 }
 
-dnl See if GCC's -mpreferred-stack-boundary is supported.
-dnl  Reference: http://bugzilla.libsdl.org/show_bug.cgi?id=1296
-CheckStackBoundary()
-{
-    AC_MSG_CHECKING(for GCC -mpreferred-stack-boundary option)
-    have_gcc_preferred_stack_boundary=no
-
-    save_CFLAGS="$CFLAGS"
-    CFLAGS="$save_CFLAGS -mpreferred-stack-boundary=2"
-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-    int x = 0;
-    ]],[])], [have_gcc_preferred_stack_boundary=yes],[])
-    AC_MSG_RESULT($have_gcc_preferred_stack_boundary)
-    CFLAGS="$save_CFLAGS"
-
-    if test x$have_gcc_preferred_stack_boundary = xyes; then
-        EXTRA_CFLAGS="$EXTRA_CFLAGS -mpreferred-stack-boundary=2"
-    fi
-}
-
 dnl See if GCC's -Werror is supported.
 CheckWerror()
 {
@@ -3306,9 +3286,6 @@ CheckWINDOWS()
     ],[])
     AC_MSG_RESULT($have_wince)
 
-    # This fixes Windows stack alignment with newer GCC
-    CheckStackBoundary
-
     # headers needed elsewhere
     AC_CHECK_HEADER(tpcshrd.h,have_tpcshrd_h=yes)
     if test x$have_tpcshrd_h = xyes; then
@@ -3637,7 +3614,7 @@ CheckHIDAPI()
                 enable_hidapi_libusb=yes
                 require_hidapi_libusb=yes
                 ;;
-           *-*-os2* )
+            *-*-os2* )
                 enable_hidapi_libusb=yes
                 ;;
         esac
@@ -4648,14 +4625,14 @@ dnl BeOS support removed after SDL 2.0.1. Haiku still works.  --ryan.
             AC_DEFINE(SDL_VIDEO_DRIVER_OS2, 1, [ ])
             SOURCES="$SOURCES $srcdir/src/video/os2/*.c"
             have_video=yes
-            SUMMARY_video="${SUMMARY_video} os/2"
+            SUMMARY_video="${SUMMARY_video} OS/2"
         fi
         # Set up files for the audio library
         if test x$enable_audio = xyes; then
             AC_DEFINE(SDL_AUDIO_DRIVER_OS2, 1, [ ])
             SOURCES="$SOURCES $srcdir/src/audio/os2/*.c"
             have_audio=yes
-            SUMMARY_audio="${SUMMARY_audio} os/2"
+            SUMMARY_audio="${SUMMARY_audio} OS/2"
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lmmpm2"
         fi
         # Set up files for the thread library

+ 7 - 7
Engine/lib/sdl/docs/README-android.md

@@ -13,13 +13,13 @@ supported, but you can use the "android-project-ant" directory as a template.
 Requirements
 ================================================================================
 
-Android SDK (version 31 or later)
+Android SDK (version 34 or later)
 https://developer.android.com/sdk/index.html
 
 Android NDK r15c or later
 https://developer.android.com/tools/sdk/ndk/index.html
 
-Minimum API level supported by SDL: 16 (Android 4.1)
+Minimum API level supported by SDL: 19 (Android 4.4)
 
 
 How the port works
@@ -431,13 +431,13 @@ The Tegra Graphics Debugger is available from NVidia here:
 https://developer.nvidia.com/tegra-graphics-debugger
 
 
-Why is API level 16 the minimum required?
+Why is API level 19 the minimum required?
 ================================================================================
 
-The latest NDK toolchain doesn't support targeting earlier than API level 16.
-As of this writing, according to https://developer.android.com/about/dashboards/index.html
-about 99% of the Android devices accessing Google Play support API level 16 or
-higher (January 2018).
+The latest NDK toolchain doesn't support targeting earlier than API level 19.
+As of this writing, according to https://www.composables.com/tools/distribution-chart
+about 99.7% of the Android devices accessing Google Play support API level 19 or
+higher (August 2023).
 
 
 A note regarding the use of the "dirty rectangles" rendering technique

+ 1 - 1
Engine/lib/sdl/docs/README-cmake.md

@@ -48,7 +48,7 @@ SDL can be included in your project in 2 major ways:
 The following CMake script supports both, depending on the value of `MYGAME_VENDORED`.
 
 ```cmake
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.5)
 project(mygame)
 
 # Create an option to switch between a system sdl library and a vendored sdl library

+ 1 - 1
Engine/lib/sdl/docs/README-emscripten.md

@@ -38,7 +38,7 @@ for some Javascript code to steal for this approach.
 
 ## Building SDL/emscripten
 
-SDL currently requires at least Emscripten 2.0.32 to build. Newer versions
+SDL currently requires at least Emscripten 3.1.35 to build. Newer versions
 are likely to work, as well.
 
 

+ 1 - 1
Engine/lib/sdl/docs/README-os2.md

@@ -3,7 +3,7 @@ Simple DirectMedia Layer 2 for OS/2 & eComStation
 SDL port for OS/2, authored by Andrey Vasilkin <[email protected]>, 2016
 
 
-OpenGL and audio capture not supported by this port.
+OpenGL not supported by this port.
 
 Additional optional environment variables:
 

+ 2 - 0
Engine/lib/sdl/include/SDL_assert.h

@@ -55,6 +55,8 @@ assert can have unique static variables associated with it.
     #define SDL_TriggerBreakpoint() __builtin_debugtrap()
 #elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
+#elif (defined(__GNUC__) || defined(__clang__)) && defined(__riscv)
+    #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "ebreak\n\t" )
 #elif ( defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) )  /* this might work on other ARM targets, but this is a known quantity... */
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #22\n\t" )
 #elif defined(__APPLE__) && defined(__arm__)

+ 1 - 1
Engine/lib/sdl/include/SDL_atomic.h

@@ -240,7 +240,7 @@ typedef void (*SDL_KernelMemoryBarrierFunc)();
 /* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
 #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
     #define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n")  /* Some assemblers can't do REP NOP, so go with PAUSE. */
-#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
+#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
     #define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
 #elif (defined(__powerpc__) || defined(__powerpc64__))
     #define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");

+ 2 - 0
Engine/lib/sdl/include/SDL_config.h.cmake

@@ -262,6 +262,8 @@
 #cmakedefine HAVE_XINPUT_GAMEPAD_EX @HAVE_XINPUT_GAMEPAD_EX@
 #cmakedefine HAVE_XINPUT_STATE_EX @HAVE_XINPUT_STATE_EX@
 
+#cmakedefine USE_POSIX_SPAWN @USE_POSIX_SPAWN@
+
 /* SDL internal assertion support */
 #if @SDL_DEFAULT_ASSERT_LEVEL_CONFIGURED@
 #cmakedefine SDL_DEFAULT_ASSERT_LEVEL @SDL_DEFAULT_ASSERT_LEVEL@

+ 20 - 0
Engine/lib/sdl/include/SDL_hints.h

@@ -1007,6 +1007,15 @@ extern "C" {
   */
 #define SDL_HINT_JOYSTICK_THREAD "SDL_JOYSTICK_THREAD"
 
+/**
+  *  \brief  A variable controlling whether Windows.Gaming.Input should be used for controller handling.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - WGI is not used
+  *    "1"       - WGI is used (the default)
+  */
+#define SDL_HINT_JOYSTICK_WGI "SDL_JOYSTICK_WGI"
+
 /**
  * \brief Determines whether SDL enforces that DRM master is required in order
  *        to initialize the KMSDRM video backend.
@@ -1465,6 +1474,17 @@ extern "C" {
  */
 #define SDL_HINT_RENDER_VSYNC               "SDL_RENDER_VSYNC"
 
+/**
+ *  \brief  A variable controlling whether the Metal render driver select low power device over default one
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Use the prefered OS device
+ *    "1"       - Select a low power one
+ *
+ *  By default the prefered OS device is used.
+ */
+#define SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE "SDL_RENDER_METAL_PREFER_LOW_POWER_DEVICE"
+
 /**
  *  \brief  A variable controlling if VSYNC is automatically disable if doesn't reach the enough FPS
  *

+ 1 - 1
Engine/lib/sdl/include/SDL_render.h

@@ -1890,7 +1890,7 @@ extern DECLSPEC void *SDLCALL SDL_RenderGetMetalLayer(SDL_Renderer * renderer);
  * Note that as of SDL 2.0.18, this will return NULL if Metal refuses to give
  * SDL a drawable to render to, which might happen if the window is
  * hidden/minimized/offscreen. This doesn't apply to command encoders for
- * render targets, just the window's backbacker. Check your return values!
+ * render targets, just the window's backbuffer. Check your return values!
  *
  * \param renderer The renderer to query
  * \returns an `id<MTLRenderCommandEncoder>` on success, or NULL if the

+ 3 - 2
Engine/lib/sdl/include/SDL_revision.h

@@ -1,6 +1,7 @@
+/* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION SDL_VENDOR_INFO
+#define SDL_REVISION "SDL-release-2.28.4-0-gcc016b004 (" SDL_VENDOR_INFO ")"
 #else
-#define SDL_REVISION ""
+#define SDL_REVISION "SDL-release-2.28.4-0-gcc016b004"
 #endif
 #define SDL_REVISION_NUMBER 0

+ 1 - 1
Engine/lib/sdl/include/SDL_version.h

@@ -59,7 +59,7 @@ typedef struct SDL_version
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   28
-#define SDL_PATCHLEVEL      1
+#define SDL_PATCHLEVEL      4
 
 /**
  * Macro to determine SDL version program was compiled against.

+ 19 - 0
Engine/lib/sdl/mingw/pkg-support/cmake/sdl2-config-version.cmake

@@ -0,0 +1,19 @@
+# SDL2 CMake version configuration file:
+# This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-mingw
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+    set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake")
+elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config-version.cmake")
+else()
+    set(PACKAGE_VERSION_UNSUITABLE TRUE)
+    return()
+endif()
+
+if(NOT EXISTS "${sdl2_config_path}")
+    message(WARNING "${sdl2_config_path} does not exist: MinGW development package is corrupted")
+    set(PACKAGE_VERSION_UNSUITABLE TRUE)
+    return()
+endif()
+
+include("${sdl2_config_path}")

+ 19 - 0
Engine/lib/sdl/mingw/pkg-support/cmake/sdl2-config.cmake

@@ -0,0 +1,19 @@
+# SDL2 CMake configuration file:
+# This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-mingw
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 4)
+    set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../i686-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake")
+elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    set(sdl2_config_path "${CMAKE_CURRENT_LIST_DIR}/../x86_64-w64-mingw32/lib/cmake/SDL2/sdl2-config.cmake")
+else()
+    set(SDL2_FOUND FALSE)
+    return()
+endif()
+
+if(NOT EXISTS "${sdl2_config_path}")
+    message(WARNING "${sdl2_config_path} does not exist: MinGW development package is corrupted")
+    set(SDL2_FOUND FALSE)
+    return()
+endif()
+
+include("${sdl2_config_path}")

+ 2 - 2
Engine/lib/sdl/src/SDL.c

@@ -631,9 +631,9 @@ SDL_bool SDL_IsTablet(void)
 #if defined(__WIN32__)
 
 #if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB)
-/* Need to include DllMain() on Watcom C for some reason.. */
+/* FIXME: Still need to include DllMain() on Watcom C ? */
 
-BOOL APIENTRY _DllMainCRTStartup(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+BOOL APIENTRY MINGW32_FORCEALIGN _DllMainCRTStartup(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
 {
     switch (ul_reason_for_call) {
     case DLL_PROCESS_ATTACH:

+ 10 - 2
Engine/lib/sdl/src/SDL_assert.c

@@ -42,7 +42,15 @@
 #endif
 
 #if defined(__EMSCRIPTEN__)
-#include <emscripten.h>
+    #include <emscripten.h>
+    /* older Emscriptens don't have this, but we need to for wasm64 compatibility. */
+    #ifndef MAIN_THREAD_EM_ASM_PTR
+        #ifdef __wasm64__
+            #error You need to upgrade your Emscripten compiler to support wasm64
+        #else
+            #define MAIN_THREAD_EM_ASM_PTR MAIN_THREAD_EM_ASM_INT
+        #endif
+    #endif
 #endif
 
 /* The size of the stack buffer to use for rendering assert messages. */
@@ -251,7 +259,7 @@ static SDL_assert_state SDLCALL SDL_PromptAssertion(const SDL_assert_data *data,
         for (;;) {
             SDL_bool okay = SDL_TRUE;
             /* *INDENT-OFF* */ /* clang-format off */
-            char *buf = (char *) EM_ASM_INT({
+            char *buf = (char *) MAIN_THREAD_EM_ASM_PTR({
                 var str =
                     UTF8ToString($0) + '\n\n' +
                     'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';

+ 2 - 0
Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c

@@ -197,6 +197,8 @@ static void EMSCRIPTENAUDIO_CloseDevice(_THIS)
 #endif
 }
 
+EM_JS_DEPS(sdlaudio, "$autoResumeAudioContext,$dynCall");
+
 static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
 {
     SDL_AudioFormat test_format;

+ 220 - 69
Engine/lib/sdl/src/audio/os2/SDL_os2audio.c

@@ -30,17 +30,12 @@
 #include "../SDL_audio_c.h"
 #include "SDL_os2audio.h"
 
-/*
-void lockIncr(volatile int *piVal);
-#pragma aux lockIncr = \
-  "lock add [eax], 1 "\
-  parm [eax];
-
-void lockDecr(volatile int *piVal);
-#pragma aux lockDecr = \
-  "lock sub [eax], 1 "\
-  parm [eax];
-*/
+static PMCI_MIX_BUFFER _getNextBuffer(SDL_PrivateAudioData *pAData, PMCI_MIX_BUFFER pBuffer)
+{
+    PMCI_MIX_BUFFER pFirstBuffer = &pAData->aMixBuffers[0];
+    PMCI_MIX_BUFFER pLastBuffer = &pAData->aMixBuffers[pAData->cMixBuffers -1];
+    return (pBuffer == pLastBuffer ? pFirstBuffer : pBuffer+1);
+}
 
 static ULONG _getEnvULong(const char *name, ULONG ulMax, ULONG ulDefault)
 {
@@ -64,7 +59,7 @@ static int _MCIError(const char *func, ULONG ulResult)
 
 static void _mixIOError(const char *function, ULONG ulRC)
 {
-    debug_os2("%s() - failed, rc = 0x%X (%s)",
+    debug_os2("%s() - failed, rc = 0x%lX (%s)",
               function, ulRC,
               (ulRC == MCIERR_INVALID_MODE)   ? "Mixer mode does not match request" :
               (ulRC == MCIERR_INVALID_BUFFER) ? "Caller sent an invalid buffer"     : "unknown");
@@ -73,18 +68,33 @@ static void _mixIOError(const char *function, ULONG ulRC)
 static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
                                        ULONG ulFlags)
 {
-    SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
+    SDL_AudioDevice      *_this = (SDL_AudioDevice *)pBuffer->ulUserParm;
+    SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
     ULONG   ulRC;
 
+    debug_os2("cbAudioWriteEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags);
+
+    if (pAData->ulState == 2)
+    {
+        return 0;
+    }
+
     if (ulFlags != MIX_WRITE_COMPLETE) {
-        debug_os2("flags = 0x%X", ulFlags);
+        debug_os2("flags = 0x%lX", ulFlags);
+        return 0;
+    }
+
+    pAData->pDrainBuffer = pBuffer;
+    ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
+                                           pAData->pDrainBuffer, 1);
+    if (ulRC != MCIERR_SUCCESS) {
+        _mixIOError("pmixWrite", ulRC);
         return 0;
     }
 
-    /*lockDecr((int *)&pAData->ulQueuedBuf);*/
     ulRC = DosPostEventSem(pAData->hevBuf);
     if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
-        debug_os2("DosPostEventSem(), rc = %u", ulRC);
+        debug_os2("DosPostEventSem(), rc = %lu", ulRC);
     }
 
     return 1; /* return value doesn't seem to matter. */
@@ -93,19 +103,36 @@ static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
 static LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
                                       ULONG ulFlags)
 {
-    SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
+    SDL_AudioDevice      *_this = (SDL_AudioDevice *)pBuffer->ulUserParm;
+    SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
     ULONG   ulRC;
 
+    debug_os2("cbAudioReadEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags);
+
+    if (pAData->ulState == 2)
+    {
+        return 0;
+    }
+
     if (ulFlags != MIX_READ_COMPLETE) {
-        debug_os2("flags = 0x%X", ulFlags);
+        debug_os2("flags = 0x%lX", ulFlags);
         return 0;
     }
 
-    pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, pBuffer, 1);
+    pAData->pFillBuffer = pBuffer;
+    if (pAData->pFillBuffer == pAData->aMixBuffers)
+    {
+       ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle,
+                                             pAData->pFillBuffer, pAData->cMixBuffers);
+       if (ulRC != MCIERR_SUCCESS) {
+           _mixIOError("pmixRead", ulRC);
+           return 0;
+       }
+    }
 
     ulRC = DosPostEventSem(pAData->hevBuf);
     if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
-        debug_os2("DosPostEventSem(), rc = %u", ulRC);
+        debug_os2("DosPostEventSem(), rc = %lu", ulRC);
     }
 
     return 1;
@@ -120,31 +147,36 @@ static void OS2_DetectDevices(void)
     MCI_SYSINFO_LOGDEVICE   stLogDevice;
     MCI_SYSINFO_PARMS       stSysInfoParams;
     ULONG                   ulRC;
-    ULONG                   ulHandle = 0;
+    ULONG                   ulNumber;
+    MCI_GETDEVCAPS_PARMS    stDevCapsParams;
+    MCI_OPEN_PARMS          stMCIOpen;
+    MCI_GENERIC_PARMS       stMCIGenericParams;
 
+    SDL_memset(&stMCISysInfo, 0, sizeof(stMCISysInfo));
     acBuf[0] = '\0';
     stMCISysInfo.pszReturn    = acBuf;
     stMCISysInfo.ulRetSize    = sizeof(acBuf);
     stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
     ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY,
                           &stMCISysInfo, 0);
-    if (ulRC != NO_ERROR) {
-        debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%X", ulRC);
+    if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+        debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%hX", LOUSHORT(ulRC));
         return;
     }
 
     ulDevicesNum = SDL_strtoul(stMCISysInfo.pszReturn, NULL, 10);
 
-    for (stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum;
-         stSysInfoParams.ulNumber++) {
+    for (ulNumber = 1; ulNumber <= ulDevicesNum;
+         ulNumber++) {
         /* Get device install name. */
+        stSysInfoParams.ulNumber     = ulNumber;
         stSysInfoParams.pszReturn    = acBuf;
         stSysInfoParams.ulRetSize    = sizeof(acBuf);
         stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
         ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
                               &stSysInfoParams, 0);
-        if (ulRC != NO_ERROR) {
-            debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC);
+        if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+            debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%hX", LOUSHORT(ulRC));
             continue;
         }
 
@@ -154,15 +186,45 @@ static void OS2_DetectDevices(void)
         SDL_strlcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn, MAX_DEVICE_NAME);
         ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM,
                               &stSysInfoParams, 0);
-        if (ulRC != NO_ERROR) {
-            debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%X", ulRC);
+        if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+            debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC));
             continue;
         }
 
-        ulHandle++;
-        SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
-        ulHandle++;
-        SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
+        SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)ulNumber);
+
+        /* Open audio device for querying its capabilities */
+        /* at this point we HAVE TO OPEN the waveaudio device and not the ampmix device */
+        /* because only the waveaudio device (tied to the ampmix device) supports querying for playback/record capability */
+        SDL_memset(&stMCIOpen, 0, sizeof(stMCIOpen));
+        stMCIOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,LOUSHORT(ulNumber));
+        ulRC = mciSendCommand(0, MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,&stMCIOpen,  0);
+        if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+            debug_os2("MCI_OPEN (getDevCaps) - failed");
+            continue;
+        }
+
+        /* check for recording capability */
+        SDL_memset(&stDevCapsParams, 0, sizeof(stDevCapsParams));
+        stDevCapsParams.ulItem = MCI_GETDEVCAPS_CAN_RECORD;
+        ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_GETDEVCAPS, MCI_WAIT | MCI_GETDEVCAPS_ITEM,
+                              &stDevCapsParams, 0);
+        if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+            debug_os2("MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC));
+        }
+        else {
+            if (stDevCapsParams.ulReturn) {
+                SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulNumber | 0x80000000));
+            }
+        }
+
+        /* close the audio device, we are done querying its capabilities */
+        SDL_memset(&stMCIGenericParams, 0, sizeof(stMCIGenericParams));
+        ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_CLOSE, MCI_WAIT,
+                              &stMCIGenericParams, 0);
+        if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+            debug_os2("MCI_CLOSE (getDevCaps) - failed");
+        }
     }
 }
 
@@ -171,52 +233,145 @@ static void OS2_WaitDevice(_THIS)
     SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
     ULONG   ulRC;
 
+    debug_os2("Enter");
+
     /* Wait for an audio chunk to finish */
     ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
     if (ulRC != NO_ERROR) {
-        debug_os2("DosWaitEventSem(), rc = %u", ulRC);
+        debug_os2("DosWaitEventSem(), rc = %lu", ulRC);
     }
 }
 
 static Uint8 *OS2_GetDeviceBuf(_THIS)
 {
     SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
-    return (Uint8 *) pAData->aMixBuffers[pAData->ulNextBuf].pBuffer;
+
+    debug_os2("Enter");
+
+    return (Uint8 *) pAData->pFillBuffer->pBuffer;
 }
 
 static void OS2_PlayDevice(_THIS)
 {
     SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
     ULONG                 ulRC;
-    PMCI_MIX_BUFFER       pMixBuffer = &pAData->aMixBuffers[pAData->ulNextBuf];
+    PMCI_MIX_BUFFER       pMixBuffer = NULL;
+
+    debug_os2("Enter");
+
+    pMixBuffer  = pAData->pDrainBuffer;
+    pAData->pFillBuffer = _getNextBuffer(pAData, pAData->pFillBuffer);
+    if (!pAData->ulState && pAData->pFillBuffer != pMixBuffer)
+    {
+        /*
+         * this buffer was filled but we have not yet filled all buffers
+         * so just signal event sem so that OS2_WaitDevice does not need
+         * to block
+         */
+        ulRC = DosPostEventSem(pAData->hevBuf);
+    }
 
-    /* Queue it up */
-    /*lockIncr((int *)&pAData->ulQueuedBuf);*/
-    ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
-                                           pMixBuffer, 1);
-    if (ulRC != MCIERR_SUCCESS) {
-        _mixIOError("pmixWrite", ulRC);
-    } else {
-        pAData->ulNextBuf = (pAData->ulNextBuf + 1) % pAData->cMixBuffers;
+    if (!pAData->ulState && (pAData->pFillBuffer == pMixBuffer) )
+    {
+        debug_os2("!hasStarted");
+        pAData->ulState = 1;
+
+        /* Write buffers to kick off the amp mixer */
+        ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
+                                               pMixBuffer, pAData->cMixBuffers);
+
+        if (ulRC != MCIERR_SUCCESS) {
+            _mixIOError("pmixWrite", ulRC);
+        }
     }
 }
 
+static int OS2_CaptureFromDevice(_THIS,void *buffer,int buflen)
+{
+    SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
+    ULONG                 ulRC;
+    PMCI_MIX_BUFFER       pMixBuffer = NULL;
+    int                   len = 0;
+
+    if (!pAData->ulState)
+    {
+        pAData->ulState = 1;
+        ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle,
+                                              pAData->aMixBuffers, pAData->cMixBuffers);
+        if (ulRC != MCIERR_SUCCESS) {
+            _mixIOError("pmixRead", ulRC);
+            return -1;
+        }
+    }
+
+    /* Wait for an audio chunk to finish */
+    ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
+    if (ulRC != NO_ERROR)
+    {
+        debug_os2("DosWaitEventSem(), rc = %lu", ulRC);
+        return -1;
+    }
+
+    pMixBuffer = pAData->pDrainBuffer;
+    len = SDL_min((int)pMixBuffer->ulBufferLength, buflen);
+    SDL_memcpy(buffer,pMixBuffer->pBuffer, len);
+    pAData->pDrainBuffer = _getNextBuffer(pAData, pMixBuffer);
+
+    debug_os2("buflen = %u, ulBufferLength = %lu",buflen,pMixBuffer->ulBufferLength);
+
+    return len;
+}
+
+static void OS2_FlushCapture(_THIS)
+{
+    SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
+    ULONG                 ulIdx;
+
+    debug_os2("Enter");
+
+    /* Fill all device buffers with data */
+    for (ulIdx = 0; ulIdx < pAData->cMixBuffers; ulIdx++) {
+        pAData->aMixBuffers[ulIdx].ulFlags        = 0;
+        pAData->aMixBuffers[ulIdx].ulBufferLength = _this->spec.size;
+        pAData->aMixBuffers[ulIdx].ulUserParm     = (ULONG)_this;
+
+        SDL_memset(((PMCI_MIX_BUFFER)pAData->aMixBuffers)[ulIdx].pBuffer,
+                   _this->spec.silence, _this->spec.size);
+    }
+    pAData->pFillBuffer  = pAData->aMixBuffers;
+    pAData->pDrainBuffer = pAData->aMixBuffers;
+}
+
+
 static void OS2_CloseDevice(_THIS)
 {
     SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
     MCI_GENERIC_PARMS     sMCIGenericParms;
     ULONG                 ulRC;
 
+    debug_os2("Enter");
+
     if (pAData == NULL)
         return;
 
+    pAData->ulState = 2;
+
     /* Close up audio */
     if (pAData->usDeviceId != (USHORT)~0) { /* Device is open. */
+            SDL_zero(sMCIGenericParms);
+
+            ulRC = mciSendCommand(pAData->usDeviceId, MCI_STOP,
+                                  MCI_WAIT,
+                                  &sMCIGenericParms, 0);
+            if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+                debug_os2("MCI_STOP - failed" );
+            }
+
         if (pAData->stMCIMixSetup.ulBitsPerSample != 0) { /* Mixer was initialized. */
             ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
                                   MCI_WAIT | MCI_MIXSETUP_DEINIT,
                                   &pAData->stMCIMixSetup, 0);
-            if (ulRC != MCIERR_SUCCESS) {
+            if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
                 debug_os2("MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed");
             }
         }
@@ -230,14 +385,14 @@ static void OS2_CloseDevice(_THIS)
 
             ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
                                   MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0);
-            if (ulRC != MCIERR_SUCCESS) {
+            if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
                 debug_os2("MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed");
             }
         }
 
         ulRC = mciSendCommand(pAData->usDeviceId, MCI_CLOSE, MCI_WAIT,
                               &sMCIGenericParms, 0);
-        if (ulRC != MCIERR_SUCCESS) {
+        if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
             debug_os2("MCI_CLOSE - failed");
         }
     }
@@ -257,6 +412,7 @@ static int OS2_OpenDevice(_THIS, const char *devname)
     ULONG                 ulRC;
     ULONG                 ulIdx;
     BOOL                  new_freq;
+    ULONG                 ulHandle = (ULONG)_this->handle;
     SDL_bool              iscapture = _this->iscapture;
 
     new_freq = FALSE;
@@ -279,20 +435,21 @@ static int OS2_OpenDevice(_THIS, const char *devname)
 
     ulRC = DosCreateEventSem(NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE);
     if (ulRC != NO_ERROR) {
-        debug_os2("DosCreateEventSem() failed, rc = %u", ulRC);
+        debug_os2("DosCreateEventSem() failed, rc = %lu", ulRC);
         return -1;
     }
 
     /* Open audio device */
-    stMCIAmpOpen.usDeviceID = (_this->handle != NULL) ? ((ULONG)_this->handle - 1) : 0;
-    stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX;
+    stMCIAmpOpen.usDeviceID = 0;
+    stMCIAmpOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,LOUSHORT(ulHandle));
     ulRC = mciSendCommand(0, MCI_OPEN,
                           (_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)?
                            MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE :
                            MCI_WAIT | MCI_OPEN_TYPE_ID,
                           &stMCIAmpOpen,  0);
-    if (ulRC != MCIERR_SUCCESS) {
-        stMCIAmpOpen.usDeviceID = (USHORT)~0;
+    if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
+        DosCloseEventSem(pAData->hevBuf);
+        pAData->usDeviceId = (USHORT)~0;
         return _MCIError("MCI_OPEN", ulRC);
     }
     pAData->usDeviceId = stMCIAmpOpen.usDeviceID;
@@ -355,7 +512,7 @@ static int OS2_OpenDevice(_THIS, const char *devname)
 
     ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
                           MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
-    if (ulRC != MCIERR_SUCCESS && _this->spec.freq > 44100) {
+    if (LOUSHORT(ulRC) != MCIERR_SUCCESS && _this->spec.freq > 44100) {
         new_freq = TRUE;
         pAData->stMCIMixSetup.ulSamplesPerSec = 44100;
         _this->spec.freq = 44100;
@@ -363,7 +520,7 @@ static int OS2_OpenDevice(_THIS, const char *devname)
                               MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
     }
 
-    debug_os2("Setup mixer [BPS: %u, Freq.: %u, Channels: %u]: %s",
+    debug_os2("Setup mixer [BPS: %lu, Freq.: %lu, Channels: %lu]: %s",
               pAData->stMCIMixSetup.ulBitsPerSample,
               pAData->stMCIMixSetup.ulSamplesPerSec,
               pAData->stMCIMixSetup.ulChannels,
@@ -394,29 +551,25 @@ static int OS2_OpenDevice(_THIS, const char *devname)
 
     ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
                           MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0);
-    if (ulRC != MCIERR_SUCCESS) {
+    if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
         return _MCIError("MCI_BUFFER", ulRC);
     }
     pAData->cMixBuffers = stMCIBuffer.ulNumBuffers;
     _this->spec.size = stMCIBuffer.ulBufferSize;
 
+    debug_os2("%s, number of mix buffers: %lu",iscapture ? "capture": "play",pAData->cMixBuffers);
+
     /* Fill all device buffers with data */
     for (ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++) {
         pAData->aMixBuffers[ulIdx].ulFlags        = 0;
         pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize;
-        pAData->aMixBuffers[ulIdx].ulUserParm     = (ULONG)pAData;
+        pAData->aMixBuffers[ulIdx].ulUserParm     = (ULONG)_this;
 
         SDL_memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
                    _this->spec.silence, stMCIBuffer.ulBufferSize);
     }
-
-    /* Write buffers to kick off the amp mixer */
-    ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
-                                           pAData->aMixBuffers, 1);
-    if (ulRC != MCIERR_SUCCESS) {
-        _mixIOError("pmixWrite", ulRC);
-        return -1;
-    }
+    pAData->pFillBuffer  = pAData->aMixBuffers;
+    pAData->pDrainBuffer = pAData->aMixBuffers;
 
     return 0;
 }
@@ -431,12 +584,10 @@ static SDL_bool OS2_Init(SDL_AudioDriverImpl * impl)
     impl->WaitDevice    = OS2_WaitDevice;
     impl->GetDeviceBuf  = OS2_GetDeviceBuf;
     impl->CloseDevice   = OS2_CloseDevice;
-
-    /* TODO: IMPLEMENT CAPTURE SUPPORT:
-    impl->CaptureFromDevice = ;
-    impl->FlushCapture = ;
+    impl->CaptureFromDevice = OS2_CaptureFromDevice ;
+    impl->FlushCapture = OS2_FlushCapture;
     impl->HasCaptureSupport = SDL_TRUE;
-    */
+
     return SDL_TRUE; /* this audio target is available. */
 }
 

+ 3 - 2
Engine/lib/sdl/src/audio/os2/SDL_os2audio.h

@@ -43,10 +43,11 @@ typedef struct SDL_PrivateAudioData
     BYTE                _pad[2];
     MCI_MIXSETUP_PARMS  stMCIMixSetup;
     HEV                 hevBuf;
-    ULONG               ulNextBuf;
+    PMCI_MIX_BUFFER     pFillBuffer;
+    PMCI_MIX_BUFFER     pDrainBuffer;
+    ULONG               ulState;
     ULONG               cMixBuffers;
     MCI_MIX_BUFFER      aMixBuffers[NUM_BUFFERS];
-/*  ULONG               ulQueuedBuf;*/
 } SDL_PrivateAudioData;
 
 #endif /* SDL_os2mm_h_ */

+ 2 - 0
Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c

@@ -233,6 +233,7 @@ static Uint8 *QSA_GetDeviceBuf(_THIS)
 static void QSA_CloseDevice(_THIS)
 {
     if (this->hidden->audio_handle != NULL) {
+#if _NTO_VERSION < 710
         if (!this->iscapture) {
             /* Finish playing available samples */
             snd_pcm_plugin_flush(this->hidden->audio_handle,
@@ -242,6 +243,7 @@ static void QSA_CloseDevice(_THIS)
             snd_pcm_plugin_flush(this->hidden->audio_handle,
                                  SND_PCM_CHANNEL_CAPTURE);
         }
+#endif
         snd_pcm_close(this->hidden->audio_handle);
     }
 

+ 0 - 1
Engine/lib/sdl/src/core/linux/SDL_fcitx.c

@@ -401,7 +401,6 @@ void SDL_Fcitx_SetFocus(SDL_bool focused)
 void SDL_Fcitx_Reset(void)
 {
     FcitxClientICCallMethod(&fcitx_client, "Reset");
-    FcitxClientICCallMethod(&fcitx_client, "CloseIC");
 }
 
 SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state)

+ 13 - 0
Engine/lib/sdl/src/core/windows/SDL_windows.h

@@ -76,6 +76,19 @@
 #define WINVER       _WIN32_WINNT
 #endif
 
+/* See https://github.com/libsdl-org/SDL/pull/7607  */
+/* force_align_arg_pointer attribute requires gcc >= 4.2.x.  */
+#if defined(__clang__)
+#define HAVE_FORCE_ALIGN_ARG_POINTER
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+#define HAVE_FORCE_ALIGN_ARG_POINTER
+#endif
+#if defined(__GNUC__) && defined(__i386__) && defined(HAVE_FORCE_ALIGN_ARG_POINTER)
+#define MINGW32_FORCEALIGN __attribute__((force_align_arg_pointer))
+#else
+#define MINGW32_FORCEALIGN
+#endif
+
 #include <windows.h>
 #include <basetyps.h> /* for REFIID with broken mingw.org headers */
 

+ 24 - 7
Engine/lib/sdl/src/events/SDL_keyboard.c

@@ -34,7 +34,8 @@
 /* Global keyboard information */
 
 #define KEYBOARD_HARDWARE    0x01
-#define KEYBOARD_AUTORELEASE 0x02
+#define KEYBOARD_VIRTUAL     0x02
+#define KEYBOARD_AUTORELEASE 0x04
 
 typedef struct SDL_Keyboard SDL_Keyboard;
 
@@ -47,6 +48,7 @@ struct SDL_Keyboard
     Uint8 keystate[SDL_NUM_SCANCODES];
     SDL_Keycode keymap[SDL_NUM_SCANCODES];
     SDL_bool autorelease_pending;
+    Uint32 hardware_timestamp;
 };
 
 static SDL_Keyboard SDL_keyboard;
@@ -865,7 +867,9 @@ static int SDL_SendKeyboardKeyInternal(Uint8 source, Uint8 state, SDL_Scancode s
         keycode = keyboard->keymap[scancode];
     }
 
-    if (source == KEYBOARD_AUTORELEASE) {
+    if (source == KEYBOARD_HARDWARE) {
+        keyboard->hardware_timestamp = SDL_GetTicks();
+    } else if (source == KEYBOARD_AUTORELEASE) {
         keyboard->autorelease_pending = SDL_TRUE;
     }
 
@@ -965,20 +969,25 @@ int SDL_SendKeyboardUnicodeKey(Uint32 ch)
 
     if (mod & KMOD_SHIFT) {
         /* If the character uses shift, press shift down */
-        SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT);
+        SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_PRESSED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
     }
 
     /* Send a keydown and keyup for the character */
-    SDL_SendKeyboardKey(SDL_PRESSED, code);
-    SDL_SendKeyboardKey(SDL_RELEASED, code);
+    SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_PRESSED, code, SDLK_UNKNOWN);
+    SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_RELEASED, code, SDLK_UNKNOWN);
 
     if (mod & KMOD_SHIFT) {
         /* If the character uses shift, release shift */
-        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
+        SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, SDL_RELEASED, SDL_SCANCODE_LSHIFT, SDLK_UNKNOWN);
     }
     return 0;
 }
 
+int SDL_SendVirtualKeyboardKey(Uint8 state, SDL_Scancode scancode)
+{
+    return SDL_SendKeyboardKeyInternal(KEYBOARD_VIRTUAL, state, scancode, SDLK_UNKNOWN);
+}
+
 int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
 {
     return SDL_SendKeyboardKeyInternal(KEYBOARD_HARDWARE, state, scancode, SDLK_UNKNOWN);
@@ -1007,6 +1016,13 @@ void SDL_ReleaseAutoReleaseKeys(void)
         }
         keyboard->autorelease_pending = SDL_FALSE;
     }
+
+    if (keyboard->hardware_timestamp) {
+        /* Keep hardware keyboard "active" for 250 ms */
+        if (SDL_TICKS_PASSED(SDL_GetTicks(), keyboard->hardware_timestamp + 250)) {
+            keyboard->hardware_timestamp = 0;
+        }
+    }
 }
 
 SDL_bool SDL_HardwareKeyboardKeyPressed(void)
@@ -1019,7 +1035,8 @@ SDL_bool SDL_HardwareKeyboardKeyPressed(void)
             return SDL_TRUE;
         }
     }
-    return SDL_FALSE;
+
+    return keyboard->hardware_timestamp ? SDL_TRUE : SDL_FALSE;
 }
 
 int SDL_SendKeyboardText(const char *text)

+ 3 - 0
Engine/lib/sdl/src/events/SDL_keyboard_c.h

@@ -52,6 +52,9 @@ extern void SDL_SetKeyboardFocus(SDL_Window *window);
  */
 extern int SDL_SendKeyboardUnicodeKey(Uint32 ch);
 
+/* Send a key from a virtual key source, like an on-screen keyboard */
+extern int SDL_SendVirtualKeyboardKey(Uint8 state, SDL_Scancode scancode);
+
 /* Send a keyboard key event */
 extern int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode);
 extern int SDL_SendKeyboardKeyAutoRelease(SDL_Scancode scancode);

+ 2 - 2
Engine/lib/sdl/src/file/SDL_rwops.c

@@ -648,7 +648,7 @@ SDL_RWops *SDL_RWFromMem(void *mem, int size)
         SDL_InvalidParamError("mem");
         return rwops;
     }
-    if (!size) {
+    if (size <= 0) {
         SDL_InvalidParamError("size");
         return rwops;
     }
@@ -675,7 +675,7 @@ SDL_RWops *SDL_RWFromConstMem(const void *mem, int size)
         SDL_InvalidParamError("mem");
         return rwops;
     }
-    if (!size) {
+    if (size <= 0) {
         SDL_InvalidParamError("size");
         return rwops;
     }

+ 3 - 3
Engine/lib/sdl/src/hidapi/linux/hid.c

@@ -884,9 +884,9 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data,
 	unsigned char report = data[0];
 
 	res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
-	if (res < 0)
-		perror("ioctl (GFEATURE)");
-	else if (dev->needs_ble_hack) {
+	if (res < 0) {
+		/* perror("ioctl (GFEATURE)"); */
+	} else if (dev->needs_ble_hack) {
 		/* Versions of BlueZ before 5.56 don't include the report in the data,
 		 * and versions of BlueZ >= 5.56 include 2 copies of the report.
 		 * We'll fix it so that there is a single copy of the report in both cases

+ 1 - 0
Engine/lib/sdl/src/joystick/SDL_gamecontroller.c

@@ -586,6 +586,7 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
         switch (guid.data[15]) {
         case k_eSwitchDeviceInfoControllerType_HVCLeft:
             SDL_strlcat(mapping_string, "a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,", sizeof(mapping_string));
+            break;
         case k_eSwitchDeviceInfoControllerType_HVCRight:
             SDL_strlcat(mapping_string, "a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,", sizeof(mapping_string));
             break;

+ 4 - 10
Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h

@@ -134,9 +134,7 @@ static const char *s_ControllerMappings[] = {
     "03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,",
     "03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
     "030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
-    "03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,", /* Bluetooth */
-    "03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,", /* Dongle */
-    "03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,", /* Wired */
+    "03000000790000000600000000000000,G-Shark GS-GP702,crc:8e4f,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
     "030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
     "03000000300f00000b01000000000000,GGE909 Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
     "03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
@@ -416,9 +414,6 @@ static const char *s_ControllerMappings[] = {
     "03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,",
     "030000000d0f00008400000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
     "030000000d0f00008500000000010000,Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
-    "03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,", /* Bluetooth */
-    "03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Dongle */
-    "03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Wired */
     "03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
     "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
     "03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
@@ -610,9 +605,6 @@ static const char *s_ControllerMappings[] = {
     "050000004c050000f20d000000010000,DualSense Edge Wireless Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
     "030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
     "03000000790000001100000010010000,Elecom Gamepad,crc:e86c,a:b2,b:b3,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b0,y:b1,",
-    "03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Dongle */
-    "03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Wired */
-    "05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Bluetooth */
     "0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
     "0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
     "03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
@@ -824,6 +816,7 @@ static const char *s_ControllerMappings[] = {
     "05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
     "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
     "05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+    "03000000de2800000512000011010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,misc1:b2,paddle1:b21,paddle2:b20,paddle3:b23,paddle4:b22,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,",
     "03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
     "0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
     "05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b6,leftstick:b13,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:+a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
@@ -856,6 +849,8 @@ static const char *s_ControllerMappings[] = {
     "0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
     "030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
     "0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
+    "050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+    "050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
     "05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
     "03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
     "03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
@@ -907,7 +902,6 @@ static const char *s_ControllerMappings[] = {
     "05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
     "05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b0,b:b1,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
     "05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
-    "05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
     "05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
     "0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
     "05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",

+ 15 - 1
Engine/lib/sdl/src/joystick/SDL_joystick.c

@@ -1906,7 +1906,7 @@ void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *prod
         if (crc16) {
             *crc16 = SDL_SwapLE16(guid16[1]);
         }
-    } else if (bus < ' ') {
+    } else if (bus < ' ' || bus == SDL_HARDWARE_BUS_VIRTUAL) {
         /* This GUID fits the unknown VID/PID form:
          * 16-bit bus
          * 16-bit CRC16 of the joystick name (can be zero)
@@ -2479,8 +2479,11 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
         MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */
         MAKE_VIDPID(0x046d, 0xc268), /* Logitech PRO Racing Wheel (PC mode) */
         MAKE_VIDPID(0x046d, 0xc269), /* Logitech PRO Racing Wheel (PS4/PS5 mode) */
+        MAKE_VIDPID(0x046d, 0xc272), /* Logitech PRO Racing Wheel for Xbox (PC mode) */
         MAKE_VIDPID(0x046d, 0xc26d), /* Logitech G923 (Xbox) */
         MAKE_VIDPID(0x046d, 0xc26e), /* Logitech G923 */
+        MAKE_VIDPID(0x046d, 0xc266), /* Logitech G923 for Playstation 4 and PC (PC mode) */
+        MAKE_VIDPID(0x046d, 0xc267), /* Logitech G923 for Playstation 4 and PC (PS4 mode)*/
         MAKE_VIDPID(0x046d, 0xca03), /* Logitech Momo Racing */
         MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */
         MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */
@@ -2492,6 +2495,17 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
         MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */
         MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */
         MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */
+        MAKE_VIDPID(0x0483, 0x0522), /* Simagic Wheelbase (including M10, Alpha Mini, Alpha, Alpha U) */
+        MAKE_VIDPID(0x0eb7, 0x0001), /* Fanatec ClubSport Wheel Base V2 */
+        MAKE_VIDPID(0x0eb7, 0x0004), /* Fanatec ClubSport Wheel Base V2.5 */
+        MAKE_VIDPID(0x0eb7, 0x0005), /* Fanatec CSL Elite Wheel Base+ (PS4) */
+        MAKE_VIDPID(0x0eb7, 0x0006), /* Fanatec Podium Wheel Base DD1 */
+        MAKE_VIDPID(0x0eb7, 0x0007), /* Fanatec Podium Wheel Base DD2 */
+        MAKE_VIDPID(0x0eb7, 0x0011), /* Fanatec Forza Motorsport (CSR Wheel / CSR Elite Wheel) */
+        MAKE_VIDPID(0x0eb7, 0x0020), /* Fanatec generic wheel / CSL DD / GT DD Pro */
+        MAKE_VIDPID(0x0eb7, 0x0197), /* Fanatec Porsche Wheel (Turbo / GT3 RS / Turbo S / GT3 V2 / GT2) */
+        MAKE_VIDPID(0x0eb7, 0x038e), /* Fanatec ClubSport Wheel Base V1 */
+        MAKE_VIDPID(0x0eb7, 0x0e03), /* Fanatec CSL Elite Wheel Base */
         MAKE_VIDPID(0x11ff, 0x0511), /* DragonRise Inc. Wired Wheel (initial mode) (also known as PXN V900 (PS3), Superdrive SV-750, or a Genesis Seaborg 400) */
     };
     int i;

+ 87 - 76
Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps4.c

@@ -320,81 +320,83 @@ static SDL_bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
     SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", device->is_bluetooth ? "TRUE" : "FALSE");
 #endif
 
-    size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data));
-    /* Get the device capabilities */
-    if (size == 48 && data[2] == 0x27) {
-        Uint8 capabilities = data[4];
-        Uint8 device_type = data[5];
-        Uint16 gyro_numerator = LOAD16(data[10], data[11]);
-        Uint16 gyro_denominator = LOAD16(data[12], data[13]);
-        Uint16 accel_numerator = LOAD16(data[14], data[15]);
-        Uint16 accel_denominator = LOAD16(data[16], data[17]);
-
-#ifdef DEBUG_PS4_PROTOCOL
-        HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
-#endif
-        if (capabilities & 0x02) {
-            ctx->sensors_supported = SDL_TRUE;
-        }
-        if (capabilities & 0x04) {
-            ctx->lightbar_supported = SDL_TRUE;
-        }
-        if (capabilities & 0x08) {
-            ctx->vibration_supported = SDL_TRUE;
-        }
-        if (capabilities & 0x40) {
-            ctx->touchpad_supported = SDL_TRUE;
-        }
-
-        switch (device_type) {
-        case 0x00:
-            joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
-            break;
-        case 0x01:
-            joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
-            break;
-        case 0x02:
-            joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
-            break;
-        case 0x04:
-            joystick_type = SDL_JOYSTICK_TYPE_DANCE_PAD;
-            break;
-        case 0x06:
-            joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
-            break;
-        case 0x07:
-            joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
-            break;
-        case 0x08:
-            joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
-            break;
-        default:
-            joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
-            break;
-        }
-
-        if (gyro_numerator && gyro_denominator) {
-            ctx->gyro_numerator = gyro_numerator;
-            ctx->gyro_denominator = gyro_denominator;
-        }
-        if (accel_numerator && accel_denominator) {
-            ctx->accel_numerator = accel_numerator;
-            ctx->accel_denominator = accel_denominator;
-        }
-    } else if (device->vendor_id == USB_VENDOR_SONY) {
+    if (device->vendor_id == USB_VENDOR_SONY) {
         ctx->official_controller = SDL_TRUE;
         ctx->sensors_supported = SDL_TRUE;
         ctx->lightbar_supported = SDL_TRUE;
         ctx->vibration_supported = SDL_TRUE;
         ctx->touchpad_supported = SDL_TRUE;
-    } else if (device->vendor_id == USB_VENDOR_RAZER) {
-        /* The Razer Raiju doesn't respond to the detection protocol, but has a touchpad and vibration */
-        ctx->vibration_supported = SDL_TRUE;
-        ctx->touchpad_supported = SDL_TRUE;
+    } else {
+        size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data));
+        /* Get the device capabilities */
+        if (size == 48 && data[2] == 0x27) {
+            Uint8 capabilities = data[4];
+            Uint8 device_type = data[5];
+            Uint16 gyro_numerator = LOAD16(data[10], data[11]);
+            Uint16 gyro_denominator = LOAD16(data[12], data[13]);
+            Uint16 accel_numerator = LOAD16(data[14], data[15]);
+            Uint16 accel_denominator = LOAD16(data[16], data[17]);
 
-        if (device->product_id == USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH ||
-            device->product_id == USB_PRODUCT_RAZER_ULTIMATE_EDITION_BLUETOOTH) {
-            device->is_bluetooth = SDL_TRUE;
+#ifdef DEBUG_PS4_PROTOCOL
+            HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
+#endif
+            if (capabilities & 0x02) {
+                ctx->sensors_supported = SDL_TRUE;
+            }
+            if (capabilities & 0x04) {
+                ctx->lightbar_supported = SDL_TRUE;
+            }
+            if (capabilities & 0x08) {
+                ctx->vibration_supported = SDL_TRUE;
+            }
+            if (capabilities & 0x40) {
+                ctx->touchpad_supported = SDL_TRUE;
+            }
+
+            switch (device_type) {
+            case 0x00:
+                joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+                break;
+            case 0x01:
+                joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
+                break;
+            case 0x02:
+                joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
+                break;
+            case 0x04:
+                joystick_type = SDL_JOYSTICK_TYPE_DANCE_PAD;
+                break;
+            case 0x06:
+                joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
+                break;
+            case 0x07:
+                joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
+                break;
+            case 0x08:
+                joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
+                break;
+            default:
+                joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
+                break;
+            }
+
+            if (gyro_numerator && gyro_denominator) {
+                ctx->gyro_numerator = gyro_numerator;
+                ctx->gyro_denominator = gyro_denominator;
+            }
+            if (accel_numerator && accel_denominator) {
+                ctx->accel_numerator = accel_numerator;
+                ctx->accel_denominator = accel_denominator;
+            }
+        } else if (device->vendor_id == USB_VENDOR_RAZER) {
+            /* The Razer Raiju doesn't respond to the detection protocol, but has a touchpad and vibration */
+            ctx->vibration_supported = SDL_TRUE;
+            ctx->touchpad_supported = SDL_TRUE;
+
+            if (device->product_id == USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH ||
+                device->product_id == USB_PRODUCT_RAZER_ULTIMATE_EDITION_BLUETOOTH) {
+                device->is_bluetooth = SDL_TRUE;
+            }
         }
     }
     ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported);
@@ -660,16 +662,25 @@ static int HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device)
 
 static void HIDAPI_DriverPS4_TickleBluetooth(SDL_HIDAPI_Device *device)
 {
-    /* This is just a dummy packet that should have no effect, since we don't set the CRC */
-    Uint8 data[78];
+    SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
 
-    SDL_zeroa(data);
+    if (ctx->enhanced_mode) {
+        /* This is just a dummy packet that should have no effect, since we don't set the CRC */
+        Uint8 data[78];
 
-    data[0] = k_EPS4ReportIdBluetoothEffects;
-    data[1] = 0xC0; /* Magic value HID + CRC */
+        SDL_zeroa(data);
+
+        data[0] = k_EPS4ReportIdBluetoothEffects;
+        data[1] = 0xC0; /* Magic value HID + CRC */
 
-    if (SDL_HIDAPI_LockRumble() == 0) {
-        SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
+        if (SDL_HIDAPI_LockRumble() == 0) {
+            SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
+        }
+    } else {
+        /* We can't even send an invalid effects packet, or it will put the controller in enhanced mode */
+        if (device->num_joysticks > 0) {
+            HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
+        }
     }
 }
 

+ 122 - 81
Engine/lib/sdl/src/joystick/hidapi/SDL_hidapi_ps5.c

@@ -102,7 +102,7 @@ typedef struct
     Uint8 rgucAccelX[2];          /* 21 */
     Uint8 rgucAccelY[2];          /* 23 */
     Uint8 rgucAccelZ[2];          /* 25 */
-    Uint8 rgucSensorTimestamp[4]; /* 27 - 32 bit little endian */
+    Uint8 rgucSensorTimestamp[4]; /* 27 - 16/32 bit little endian */
 
 } PS5StatePacketCommon_t;
 
@@ -154,7 +154,9 @@ typedef struct
     Uint8 rgucAccelX[2];          /* 21 */
     Uint8 rgucAccelY[2];          /* 23 */
     Uint8 rgucAccelZ[2];          /* 25 */
-    Uint8 rgucSensorTimestamp[4]; /* 27 - 32 bit little endian */
+    Uint8 rgucSensorTimestamp[2]; /* 27 - 16 bit little endian */
+    Uint8 ucBatteryLevel;         /* 29 */
+    Uint8 ucUnknown;              /* 30 */
     Uint8 ucTouchpadCounter1;     /* 31 - high bit clear + counter */
     Uint8 rgucTouchpadData1[3];   /* 32 - X/Y, 12 bits per axis */
     Uint8 ucTouchpadCounter2;     /* 35 - high bit clear + counter */
@@ -421,7 +423,6 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
         }
     }
 
-    size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data));
     /* Get the device capabilities */
     if (device->vendor_id == USB_VENDOR_SONY) {
         ctx->sensors_supported = SDL_TRUE;
@@ -429,61 +430,66 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
         ctx->vibration_supported = SDL_TRUE;
         ctx->playerled_supported = SDL_TRUE;
         ctx->touchpad_supported = SDL_TRUE;
-    } else if (size == 48 && data[2] == 0x28) {
-        Uint8 capabilities = data[4];
-        Uint8 capabilities2 = data[20];
-        Uint8 device_type = data[5];
+    } else {
+        /* Third party controller capability request */
+        size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data));
+        if (size == 48 && data[2] == 0x28) {
+            Uint8 capabilities = data[4];
+            Uint8 capabilities2 = data[20];
+            Uint8 device_type = data[5];
 
 #ifdef DEBUG_PS5_PROTOCOL
-        HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
+            HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
 #endif
-        if (capabilities & 0x02) {
+            if (capabilities & 0x02) {
+                ctx->sensors_supported = SDL_TRUE;
+            }
+            if (capabilities & 0x04) {
+                ctx->lightbar_supported = SDL_TRUE;
+            }
+            if (capabilities & 0x08) {
+                ctx->vibration_supported = SDL_TRUE;
+            }
+            if (capabilities & 0x40) {
+                ctx->touchpad_supported = SDL_TRUE;
+            }
+            if (capabilities2 & 0x80) {
+                ctx->playerled_supported = SDL_TRUE;
+            }
+
+            switch (device_type) {
+            case 0x00:
+                joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+                break;
+            case 0x01:
+                joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
+                break;
+            case 0x02:
+                joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
+                break;
+            case 0x06:
+                joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
+                break;
+            case 0x07:
+                joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
+                break;
+            case 0x08:
+                joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
+                break;
+            default:
+                joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
+                break;
+            }
+
+            ctx->use_alternate_report = SDL_TRUE;
+        } else if (device->vendor_id == USB_VENDOR_RAZER &&
+                   (device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED ||
+                    device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS)) {
+            /* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors, but no vibration */
             ctx->sensors_supported = SDL_TRUE;
-        }
-        if (capabilities & 0x04) {
-            ctx->lightbar_supported = SDL_TRUE;
-        }
-        if (capabilities & 0x08) {
-            ctx->vibration_supported = SDL_TRUE;
-        }
-        if (capabilities & 0x40) {
             ctx->touchpad_supported = SDL_TRUE;
+            ctx->use_alternate_report = SDL_TRUE;
         }
-        if (capabilities2 & 0x80) {
-            ctx->playerled_supported = SDL_TRUE;
-        }
-
-        switch (device_type) {
-        case 0x00:
-            joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
-            break;
-        case 0x01:
-            joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
-            break;
-        case 0x02:
-            joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
-            break;
-        case 0x06:
-            joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
-            break;
-        case 0x07:
-            joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
-            break;
-        case 0x08:
-            joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
-            break;
-        default:
-            joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
-            break;
-        }
-
-        ctx->use_alternate_report = SDL_TRUE;
-    } else if (device->vendor_id == USB_VENDOR_RAZER &&
-               (device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED ||
-                device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS)) {
-        /* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors, but no vibration */
-        ctx->sensors_supported = SDL_TRUE;
-        ctx->touchpad_supported = SDL_TRUE;
     }
     ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported);
 
@@ -717,7 +723,7 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
     SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
     SDL_bool led_reset_complete = SDL_FALSE;
 
-    if (ctx->sensors_supported) {
+    if (ctx->enhanced_mode && ctx->sensors_supported && !ctx->use_alternate_report) {
         const PS5StatePacketCommon_t *packet = &ctx->last_state.state;
 
         /* Check the timer to make sure the Bluetooth connection LED animation is complete */
@@ -726,7 +732,7 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
                                   packet->rgucSensorTimestamp[1],
                                   packet->rgucSensorTimestamp[2],
                                   packet->rgucSensorTimestamp[3]);
-        if (SDL_TICKS_PASSED(timestamp, connection_complete)) {
+        if (timestamp >= connection_complete) {
             led_reset_complete = SDL_TRUE;
         }
     } else {
@@ -745,16 +751,25 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
 
 static void HIDAPI_DriverPS5_TickleBluetooth(SDL_HIDAPI_Device *device)
 {
-    /* This is just a dummy packet that should have no effect, since we don't set the CRC */
-    Uint8 data[78];
+    SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
 
-    SDL_zeroa(data);
+    if (ctx->enhanced_mode) {
+        /* This is just a dummy packet that should have no effect, since we don't set the CRC */
+        Uint8 data[78];
 
-    data[0] = k_EPS5ReportIdBluetoothEffects;
-    data[1] = 0x02; /* Magic value */
+        SDL_zeroa(data);
 
-    if (SDL_HIDAPI_LockRumble() == 0) {
-        SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
+        data[0] = k_EPS5ReportIdBluetoothEffects;
+        data[1] = 0x02; /* Magic value */
+
+        if (SDL_HIDAPI_LockRumble() == 0) {
+            SDL_HIDAPI_SendRumbleAndUnlock(device, data, sizeof(data));
+        }
+    } else {
+        /* We can't even send an invalid effects packet, or it will put the controller in enhanced mode */
+        if (device->num_joysticks > 0) {
+            HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
+        }
     }
 }
 
@@ -1216,30 +1231,56 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
 
     if (ctx->report_sensors) {
-        Uint32 timestamp;
-        Uint64 timestamp_us;
         float data[3];
+        Uint64 timestamp_us;
 
-        timestamp = LOAD32(packet->rgucSensorTimestamp[0],
-                           packet->rgucSensorTimestamp[1],
-                           packet->rgucSensorTimestamp[2],
-                           packet->rgucSensorTimestamp[3]);
-        if (ctx->timestamp) {
-            Uint32 delta;
+        if (ctx->use_alternate_report) {
+            /* 16-bit timestamp */
+            Uint16 timestamp;
 
-            if (ctx->last_timestamp > timestamp) {
-                delta = (SDL_MAX_UINT32 - ctx->last_timestamp + timestamp + 1);
+            timestamp = LOAD16(packet->rgucSensorTimestamp[0],
+                               packet->rgucSensorTimestamp[1]);
+            if (ctx->timestamp) {
+                Uint16 delta;
+
+                if (ctx->last_timestamp > timestamp) {
+                    delta = (SDL_MAX_UINT16 - ctx->last_timestamp + timestamp + 1);
+                } else {
+                    delta = (timestamp - ctx->last_timestamp);
+                }
+                ctx->timestamp += delta;
             } else {
-                delta = (timestamp - ctx->last_timestamp);
+                ctx->timestamp = timestamp;
             }
-            ctx->timestamp += delta;
+            ctx->last_timestamp = timestamp;
+
+            /* Sensor timestamp is in 1us units */
+            timestamp_us = ctx->timestamp;
         } else {
-            ctx->timestamp = timestamp;
-        }
-        ctx->last_timestamp = timestamp;
+            /* 32-bit timestamp */
+            Uint32 timestamp;
+
+            timestamp = LOAD32(packet->rgucSensorTimestamp[0],
+                               packet->rgucSensorTimestamp[1],
+                               packet->rgucSensorTimestamp[2],
+                               packet->rgucSensorTimestamp[3]);
+            if (ctx->timestamp) {
+                Uint32 delta;
+
+                if (ctx->last_timestamp > timestamp) {
+                    delta = (SDL_MAX_UINT32 - ctx->last_timestamp + timestamp + 1);
+                } else {
+                    delta = (timestamp - ctx->last_timestamp);
+                }
+                ctx->timestamp += delta;
+            } else {
+                ctx->timestamp = timestamp;
+            }
+            ctx->last_timestamp = timestamp;
 
-        /* Sensor timestamp is in 0.33us units */
-        timestamp_us = ctx->timestamp / 3;
+            /* Sensor timestamp is in 0.33us units */
+            timestamp_us = ctx->timestamp / 3;
+        }
 
         data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1]));
         data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1]));
@@ -1395,15 +1436,15 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
                 /* This is the extended report, we can enable effects now */
                 HIDAPI_DriverPS5_SetEnhancedMode(device, joystick);
             }
-            if (ctx->led_reset_state == k_EDS5LEDResetStatePending) {
-                HIDAPI_DriverPS5_CheckPendingLEDReset(device);
-            }
             HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[2]);
             if (ctx->use_alternate_report) {
                 HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[2]);
             } else {
                 HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]);
             }
+            if (ctx->led_reset_state == k_EDS5LEDResetStatePending) {
+                HIDAPI_DriverPS5_CheckPendingLEDReset(device);
+            }
             break;
         default:
 #ifdef DEBUG_JOYSTICK

+ 3 - 3
Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c

@@ -1041,7 +1041,7 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd)
         }
         for (i = 0; i < ABS_MAX; ++i) {
             /* Skip digital hats */
-            if (joystick->hwdata->has_hat[(i - ABS_HAT0X) / 2]) {
+            if (i >= ABS_HAT0X && i <= ABS_HAT3Y && joystick->hwdata->has_hat[(i - ABS_HAT0X) / 2]) {
                 continue;
             }
             if (test_bit(i, absbit)) {
@@ -1752,11 +1752,11 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
     /* We temporarily open the device to check how it's configured. Make
        a fake SDL_Joystick object to do so. */
     joystick = (SDL_Joystick *)SDL_calloc(sizeof(*joystick), 1);
-    joystick->magic = &SDL_joystick_magic;
     if (joystick == NULL) {
         SDL_OutOfMemory();
         return SDL_FALSE;
     }
+    joystick->magic = &SDL_joystick_magic;
     SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid));
 
     joystick->hwdata = (struct joystick_hwdata *)
@@ -2026,7 +2026,7 @@ static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
 #endif
     }
 
-    if (!(mapped & MAPPED_TRIGGER_LEFT) && joystick->hwdata->has_key[BTN_TR2]) {
+    if (!(mapped & MAPPED_TRIGGER_RIGHT) && joystick->hwdata->has_key[BTN_TR2]) {
         out->righttrigger.kind = EMappingKind_Button;
         out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
         mapped |= MAPPED_TRIGGER_RIGHT;

File diff suppressed because it is too large
+ 477 - 450
Engine/lib/sdl/src/joystick/os2/SDL_os2joystick.c


+ 1 - 0
Engine/lib/sdl/src/joystick/sort_controllers.py

@@ -22,6 +22,7 @@ standard_guid_pattern = re.compile(r'^([0-9a-fA-F]{4})([0-9a-fA-F]{2})([0-9a-fA-
 invalid_controllers = (
     ('0079', '0006', '0000'), # DragonRise Inc. Generic USB Joystick
     ('0079', '0006', '6120'), # DragonRise Inc. Generic USB Joystick
+    ('04b4', '2412', 'c529'), # Flydigi Vader 2, Vader 2 Pro, Apex 2, Apex 3
     ('16c0', '05e1', '0000'), # Xinmotek Controller
 )
 

+ 175 - 34
Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick.c

@@ -33,6 +33,7 @@
 
 #if SDL_JOYSTICK_RAWINPUT
 
+#include "SDL_atomic.h"
 #include "SDL_endian.h"
 #include "SDL_events.h"
 #include "SDL_hints.h"
@@ -47,7 +48,7 @@
    raw input will turn off the Xbox Series X controller when it is connected via the
    Xbox One Wireless Adapter.
  */
-#if 0 /*def HAVE_XINPUT_H*/
+#ifdef HAVE_XINPUT_H
 #define SDL_JOYSTICK_RAWINPUT_XINPUT
 #endif
 #ifdef HAVE_WINDOWS_GAMING_INPUT_H
@@ -78,7 +79,9 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
 #endif
 #endif
 
-/*#define DEBUG_RAWINPUT*/
+#if 0
+#define DEBUG_RAWINPUT
+#endif
 
 #ifndef RIDEV_EXINPUTSINK
 #define RIDEV_EXINPUTSINK 0x00001000
@@ -401,6 +404,21 @@ static SDL_bool RAWINPUT_GuessXInputSlot(const WindowsMatchState *state, Uint8 *
     int user_index;
     int match_count;
 
+    /* If there is only one available slot, let's use that
+     * That will be right most of the time, and uncorrelation will fix any bad guesses
+     */
+    match_count = 0;
+    for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
+        if (xinput_state[user_index].connected && !xinput_state[user_index].used) {
+            *slot_idx = user_index;
+            ++match_count;
+        }
+    }
+    if (match_count == 1) {
+        *correlation_id = ++xinput_state[*slot_idx].correlation_id;
+        return SDL_TRUE;
+    }
+
     *slot_idx = 0;
 
     match_count = 0;
@@ -445,8 +463,86 @@ static struct
     SDL_bool need_device_list_update;
     int ref_count;
     __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
+    EventRegistrationToken gamepad_added_token;
+    EventRegistrationToken gamepad_removed_token;
 } wgi_state;
 
+typedef struct GamepadDelegate
+{
+    __FIEventHandler_1_Windows__CGaming__CInput__CGamepad iface;
+    SDL_atomic_t refcount;
+} GamepadDelegate;
+
+static const IID IID_IEventHandler_Gamepad = { 0x8a7639ee, 0x624a, 0x501a, { 0xbb, 0x53, 0x56, 0x2d, 0x1e, 0xc1, 0x1b, 0x52 } };
+
+static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_QueryInterface(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, REFIID riid, void **ppvObject)
+{
+    if (ppvObject == NULL) {
+        return E_INVALIDARG;
+    }
+
+    *ppvObject = NULL;
+    if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IAgileObject) || WIN_IsEqualIID(riid, &IID_IEventHandler_Gamepad)) {
+        *ppvObject = This;
+        __FIEventHandler_1_Windows__CGaming__CInput__CGamepad_AddRef(This);
+        return S_OK;
+    } else if (WIN_IsEqualIID(riid, &IID_IMarshal)) {
+        /* This seems complicated. Let's hope it doesn't happen. */
+        return E_OUTOFMEMORY;
+    } else {
+        return E_NOINTERFACE;
+    }
+}
+
+static ULONG STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_AddRef(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This)
+{
+    GamepadDelegate *self = (GamepadDelegate *)This;
+    return SDL_AtomicAdd(&self->refcount, 1) + 1UL;
+}
+
+static ULONG STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_Release(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This)
+{
+    GamepadDelegate *self = (GamepadDelegate *)This;
+    int rc = SDL_AtomicAdd(&self->refcount, -1) - 1;
+    /* Should never free the static delegate objects */
+    SDL_assert(rc > 0);
+    return rc;
+}
+
+static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_InvokeAdded(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIGamepad *e)
+{
+    wgi_state.need_device_list_update = SDL_TRUE;
+    return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE IEventHandler_CGamepadVtbl_InvokeRemoved(__FIEventHandler_1_Windows__CGaming__CInput__CGamepad *This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIGamepad *e)
+{
+    wgi_state.need_device_list_update = SDL_TRUE;
+    return S_OK;
+}
+
+static __FIEventHandler_1_Windows__CGaming__CInput__CGamepadVtbl gamepad_added_vtbl = {
+    IEventHandler_CGamepadVtbl_QueryInterface,
+    IEventHandler_CGamepadVtbl_AddRef,
+    IEventHandler_CGamepadVtbl_Release,
+    IEventHandler_CGamepadVtbl_InvokeAdded
+};
+static GamepadDelegate gamepad_added = {
+    { &gamepad_added_vtbl },
+    { 1 }
+};
+
+static __FIEventHandler_1_Windows__CGaming__CInput__CGamepadVtbl gamepad_removed_vtbl = {
+    IEventHandler_CGamepadVtbl_QueryInterface,
+    IEventHandler_CGamepadVtbl_AddRef,
+    IEventHandler_CGamepadVtbl_Release,
+    IEventHandler_CGamepadVtbl_InvokeRemoved
+};
+static GamepadDelegate gamepad_removed = {
+    { &gamepad_removed_vtbl },
+    { 1 }
+};
+
 static void RAWINPUT_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, RAWINPUT_DeviceContext *ctx)
 {
     wgi_slot->used = SDL_TRUE;
@@ -564,7 +660,10 @@ static void RAWINPUT_UpdateWindowsGamingInput()
 }
 static void RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
 {
-    wgi_state.need_device_list_update = SDL_TRUE;
+    if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, SDL_TRUE)) {
+        return;
+    }
+
     wgi_state.ref_count++;
     if (!wgi_state.initialized) {
         static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
@@ -596,6 +695,20 @@ static void RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
                 if (SUCCEEDED(hr)) {
                     RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, (void **)&wgi_state.gamepad_statics);
                 }
+
+                if (wgi_state.gamepad_statics) {
+                    wgi_state.need_device_list_update = SDL_TRUE;
+
+                    hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadAdded(wgi_state.gamepad_statics, &gamepad_added.iface, &wgi_state.gamepad_added_token);
+                    if (!SUCCEEDED(hr)) {
+                        SDL_SetError("add_GamepadAdded() failed: 0x%lx\n", hr);
+                    }
+
+                    hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_add_GamepadRemoved(wgi_state.gamepad_statics, &gamepad_removed.iface, &wgi_state.gamepad_removed_token);
+                    if (!SUCCEEDED(hr)) {
+                        SDL_SetError("add_GamepadRemoved() failed: 0x%lx\n", hr);
+                    }
+                }
             }
         }
     }
@@ -621,10 +734,27 @@ static SDL_bool RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *
 static SDL_bool RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot, SDL_bool xinput_correlated)
 {
     int match_count, user_index;
+    WindowsGamingInputGamepadState *gamepad_state = NULL;
+
+    /* If there is only one available slot, let's use that
+     * That will be right most of the time, and uncorrelation will fix any bad guesses
+     */
+    match_count = 0;
+    for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
+        gamepad_state = wgi_state.per_gamepad[user_index];
+        if (gamepad_state->connected && !gamepad_state->used) {
+            *slot = gamepad_state;
+            ++match_count;
+        }
+    }
+    if (match_count == 1) {
+        *correlation_id = ++gamepad_state->correlation_id;
+        return SDL_TRUE;
+    }
 
     match_count = 0;
     for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
-        WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index];
+        gamepad_state = wgi_state.per_gamepad[user_index];
         if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state, xinput_correlated)) {
             ++match_count;
             *slot = gamepad_state;
@@ -643,7 +773,6 @@ static SDL_bool RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *st
 
 static void RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
 {
-    wgi_state.need_device_list_update = SDL_TRUE;
     --wgi_state.ref_count;
     if (!wgi_state.ref_count && wgi_state.initialized) {
         int ii;
@@ -656,6 +785,8 @@ static void RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
         }
         wgi_state.per_gamepad_count = 0;
         if (wgi_state.gamepad_statics) {
+            __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_remove_GamepadAdded(wgi_state.gamepad_statics, wgi_state.gamepad_added_token);
+            __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_remove_GamepadRemoved(wgi_state.gamepad_statics, wgi_state.gamepad_removed_token);
             __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
             wgi_state.gamepad_statics = NULL;
         }
@@ -879,12 +1010,12 @@ static int RAWINPUT_JoystickInit(void)
 {
     SDL_assert(!SDL_RAWINPUT_inited);
 
-    if (!WIN_IsWindowsVistaOrGreater()) {
-        /* According to bug 6400, this doesn't work on Windows XP */
-        return -1;
+    if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
+        return 0;
     }
 
-    if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_RAWINPUT, SDL_TRUE)) {
+    if (!WIN_IsWindowsVistaOrGreater()) {
+        /* According to bug 6400, this doesn't work on Windows XP */
         return -1;
     }
 
@@ -917,9 +1048,6 @@ SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 ve
 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
     xinput_device_change = SDL_TRUE;
 #endif
-#ifdef SDL_JOYSTICK_RAWINPUT_WGI
-    wgi_state.need_device_list_update = SDL_TRUE;
-#endif
 
     device = SDL_RAWINPUT_devices;
     while (device) {
@@ -1008,8 +1136,13 @@ static void RAWINPUT_PostUpdate(void)
 
 static void RAWINPUT_JoystickDetect(void)
 {
-    SDL_bool remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? SDL_TRUE : SDL_FALSE;
+    SDL_bool remote_desktop;
+
+    if (!SDL_RAWINPUT_inited) {
+        return;
+    }
 
+    remote_desktop = GetSystemMetrics(SM_REMOTESESSION) ? SDL_TRUE : SDL_FALSE;
     if (remote_desktop != SDL_RAWINPUT_remote_desktop) {
         SDL_RAWINPUT_remote_desktop = remote_desktop;
 
@@ -1281,20 +1414,8 @@ static int RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_
 #endif
     SDL_bool rumbled = SDL_FALSE;
 
-#ifdef SDL_JOYSTICK_RAWINPUT_WGI
-    if (!rumbled && ctx->wgi_correlated) {
-        WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
-        HRESULT hr;
-        gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
-        gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
-        hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
-        if (SUCCEEDED(hr)) {
-            rumbled = SDL_TRUE;
-        }
-    }
-#endif
-
 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+    /* Prefer XInput over WGI because it allows rumble in the background */
     if (!rumbled && ctx->xinput_correlated) {
         XINPUT_VIBRATION XVibration;
 
@@ -1312,6 +1433,19 @@ static int RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_
     }
 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
 
+#ifdef SDL_JOYSTICK_RAWINPUT_WGI
+    if (!rumbled && ctx->wgi_correlated) {
+        WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
+        HRESULT hr;
+        gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
+        gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
+        hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
+        if (SUCCEEDED(hr)) {
+            rumbled = SDL_TRUE;
+        }
+    }
+#endif
+
     if (!rumbled) {
 #if defined(SDL_JOYSTICK_RAWINPUT_WGI) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT)
         return SDL_SetError("Controller isn't correlated yet, try hitting a button first");
@@ -1911,10 +2045,14 @@ static void RAWINPUT_JoystickClose(SDL_Joystick *joystick)
     }
 }
 
-SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd)
+int RAWINPUT_RegisterNotifications(HWND hWnd)
 {
-    RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
     int i;
+    RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
+
+    if (!SDL_RAWINPUT_inited) {
+        return 0;
+    }
 
     for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
         rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
@@ -1924,17 +2062,20 @@ SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd)
     }
 
     if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
-        SDL_SetError("Couldn't register for raw input events");
-        return SDL_FALSE;
+        return SDL_SetError("Couldn't register for raw input events");
     }
-    return SDL_TRUE;
+    return 0;
 }
 
-void RAWINPUT_UnregisterNotifications()
+int RAWINPUT_UnregisterNotifications()
 {
     int i;
     RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
 
+    if (!SDL_RAWINPUT_inited) {
+        return 0;
+    }
+
     for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
         rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
         rid[i].usUsage = subscribed_devices[i];
@@ -1943,9 +2084,9 @@ void RAWINPUT_UnregisterNotifications()
     }
 
     if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
-        SDL_SetError("Couldn't unregister for raw input events");
-        return;
+        return SDL_SetError("Couldn't unregister for raw input events");
     }
+    return 0;
 }
 
 LRESULT CALLBACK

+ 2 - 2
Engine/lib/sdl/src/joystick/windows/SDL_rawinputjoystick_c.h

@@ -28,8 +28,8 @@ extern SDL_bool RAWINPUT_IsEnabled();
 extern SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
 
 /* Registers for input events */
-extern SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd);
-extern void RAWINPUT_UnregisterNotifications();
+extern int RAWINPUT_RegisterNotifications(HWND hWnd);
+extern int RAWINPUT_UnregisterNotifications();
 
 /* Returns 0 if message was handled */
 extern LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

+ 162 - 108
Engine/lib/sdl/src/joystick/windows/SDL_windows_gaming_input.c

@@ -101,6 +101,9 @@ static const IID IID_IRacingWheelStatics = { 0x3AC12CD5, 0x581B, 0x4936, { 0x9F,
 static const IID IID_IRacingWheelStatics2 = { 0xE666BCAA, 0xEDFD, 0x4323, { 0xA9, 0xF6, 0x3C, 0x38, 0x40, 0x48, 0xD1, 0xED } };
 /*static const IID IID_IRacingWheel = { 0xF546656F, 0xE106, 0x4C82, { 0xA9, 0x0F, 0x55, 0x40, 0x12, 0x90, 0x4B, 0x85 } };*/
 
+typedef HRESULT(WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING *string);
+typedef HRESULT(WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void **factory);
+
 
 extern SDL_bool SDL_XINPUT_Enabled(void);
 extern SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version);
@@ -211,6 +214,136 @@ static SDL_bool SDL_IsXInputDevice(Uint16 vendor, Uint16 product)
     return SDL_FALSE;
 }
 
+static void WGI_LoadRawGameControllerStatics()
+{
+    WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
+    RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
+    HRESULT hr;
+
+#ifdef __WINRT__
+    WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
+    RoGetActivationFactoryFunc = RoGetActivationFactory;
+#else
+    {
+        WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
+        RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
+    }
+#endif /* __WINRT__ */
+    if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
+        PCWSTR pNamespace;
+        HSTRING_HEADER hNamespaceStringHeader;
+        HSTRING hNamespaceString;
+
+        pNamespace = L"Windows.Gaming.Input.RawGameController";
+        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
+        if (SUCCEEDED(hr)) {
+            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, (void **)&wgi.statics);
+            if (!SUCCEEDED(hr)) {
+                SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%lx", hr);
+            }
+        }
+    }
+}
+
+static void WGI_LoadOtherControllerStatics()
+{
+    WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
+    RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
+    HRESULT hr;
+
+#ifdef __WINRT__
+    WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
+    RoGetActivationFactoryFunc = RoGetActivationFactory;
+#else
+    {
+        WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
+        RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
+    }
+#endif /* __WINRT__ */
+    if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
+        PCWSTR pNamespace;
+        HSTRING_HEADER hNamespaceStringHeader;
+        HSTRING hNamespaceString;
+
+        pNamespace = L"Windows.Gaming.Input.ArcadeStick";
+        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
+        if (SUCCEEDED(hr)) {
+            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, (void **)&wgi.arcade_stick_statics);
+            if (SUCCEEDED(hr)) {
+                __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2);
+            } else {
+                SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%lx", hr);
+            }
+        }
+
+        pNamespace = L"Windows.Gaming.Input.FlightStick";
+        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
+        if (SUCCEEDED(hr)) {
+            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, (void **)&wgi.flight_stick_statics);
+            if (!SUCCEEDED(hr)) {
+                SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%lx", hr);
+            }
+        }
+
+        pNamespace = L"Windows.Gaming.Input.Gamepad";
+        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
+        if (SUCCEEDED(hr)) {
+            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, (void **)&wgi.gamepad_statics);
+            if (SUCCEEDED(hr)) {
+                __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, (void **)&wgi.gamepad_statics2);
+            } else {
+                SDL_SetError("Couldn't find IGamepadStatics: 0x%lx", hr);
+            }
+        }
+
+        pNamespace = L"Windows.Gaming.Input.RacingWheel";
+        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
+        if (SUCCEEDED(hr)) {
+            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, (void **)&wgi.racing_wheel_statics);
+            if (SUCCEEDED(hr)) {
+                __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2);
+            } else {
+                SDL_SetError("Couldn't find IRacingWheelStatics: 0x%lx", hr);
+            }
+        }
+    }
+}
+
+static SDL_JoystickType GetGameControllerType(__x_ABI_CWindows_CGaming_CInput_CIGameController *gamecontroller)
+{
+    __x_ABI_CWindows_CGaming_CInput_CIArcadeStick *arcade_stick = NULL;
+    __x_ABI_CWindows_CGaming_CInput_CIFlightStick *flight_stick = NULL;
+    __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad = NULL;
+    __x_ABI_CWindows_CGaming_CInput_CIRacingWheel *racing_wheel = NULL;
+
+    /* Wait to initialize these interfaces until we need them.
+     * Initializing the gamepad interface will switch Bluetooth PS4 controllers into enhanced mode, breaking DirectInput
+     */
+    WGI_LoadOtherControllerStatics();
+
+    if (wgi.gamepad_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, gamecontroller, &gamepad)) && gamepad) {
+        __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
+        return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+    }
+
+    if (wgi.arcade_stick_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_FromGameController(wgi.arcade_stick_statics2, gamecontroller, &arcade_stick)) && arcade_stick) {
+        __x_ABI_CWindows_CGaming_CInput_CIArcadeStick_Release(arcade_stick);
+        return SDL_JOYSTICK_TYPE_ARCADE_STICK;
+    }
+
+    if (wgi.flight_stick_statics && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_FromGameController(wgi.flight_stick_statics, gamecontroller, &flight_stick)) && flight_stick) {
+        __x_ABI_CWindows_CGaming_CInput_CIFlightStick_Release(flight_stick);
+        return SDL_JOYSTICK_TYPE_FLIGHT_STICK;
+    }
+
+    if (wgi.racing_wheel_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_FromGameController(wgi.racing_wheel_statics2, gamecontroller, &racing_wheel)) && racing_wheel) {
+        __x_ABI_CWindows_CGaming_CInput_CIRacingWheel_Release(racing_wheel);
+        return SDL_JOYSTICK_TYPE_WHEEL;
+    }
+
+    return SDL_JOYSTICK_TYPE_UNKNOWN;
+}
+
 typedef struct RawGameControllerDelegate
 {
     __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController iface;
@@ -226,7 +359,7 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_QueryInter
     *ppvObject = NULL;
     if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IAgileObject) || WIN_IsEqualIID(riid, &IID_IEventHandler_RawGameController)) {
         *ppvObject = This;
-        __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_AddRef(This);
+        __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController_AddRef(This);
         return S_OK;
     } else if (WIN_IsEqualIID(riid, &IID_IMarshal)) {
         /* This seems complicated. Let's hope it doesn't happen. */
@@ -313,38 +446,6 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
             name = SDL_strdup("");
         }
 
-        hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IGameController, (void **)&gamecontroller);
-        if (SUCCEEDED(hr)) {
-            __x_ABI_CWindows_CGaming_CInput_CIArcadeStick *arcade_stick = NULL;
-            __x_ABI_CWindows_CGaming_CInput_CIFlightStick *flight_stick = NULL;
-            __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad = NULL;
-            __x_ABI_CWindows_CGaming_CInput_CIRacingWheel *racing_wheel = NULL;
-            boolean wireless;
-
-            if (wgi.gamepad_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, gamecontroller, &gamepad)) && gamepad) {
-                type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
-                __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
-            } else if (wgi.arcade_stick_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_FromGameController(wgi.arcade_stick_statics2, gamecontroller, &arcade_stick)) && arcade_stick) {
-                type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
-                __x_ABI_CWindows_CGaming_CInput_CIArcadeStick_Release(arcade_stick);
-            } else if (wgi.flight_stick_statics && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_FromGameController(wgi.flight_stick_statics, gamecontroller, &flight_stick)) && flight_stick) {
-                type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
-                __x_ABI_CWindows_CGaming_CInput_CIFlightStick_Release(flight_stick);
-            } else if (wgi.racing_wheel_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_FromGameController(wgi.racing_wheel_statics2, gamecontroller, &racing_wheel)) && racing_wheel) {
-                type = SDL_JOYSTICK_TYPE_WHEEL;
-                __x_ABI_CWindows_CGaming_CInput_CIRacingWheel_Release(racing_wheel);
-            }
-
-            hr = __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(gamecontroller, &wireless);
-            if (SUCCEEDED(hr) && wireless) {
-                bus = SDL_HARDWARE_BUS_BLUETOOTH;
-            }
-
-            __x_ABI_CWindows_CGaming_CInput_CIGameController_Release(gamecontroller);
-        }
-
-        guid = SDL_CreateJoystickGUID(bus, vendor, product, version, name, 'w', (Uint8)type);
-
 #ifdef SDL_JOYSTICK_HIDAPI
         if (!ignore_joystick && HIDAPI_IsDevicePresent(vendor, product, version, name)) {
             ignore_joystick = SDL_TRUE;
@@ -365,13 +466,29 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
             ignore_joystick = SDL_TRUE;
         }
 
-        if (!ignore_joystick && SDL_ShouldIgnoreJoystick(name, guid)) {
-            ignore_joystick = SDL_TRUE;
+        if (!ignore_joystick) {
+            hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IGameController, (void **)&gamecontroller);
+            if (SUCCEEDED(hr)) {
+                boolean wireless;
+
+                type = GetGameControllerType(gamecontroller);
+
+                hr = __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(gamecontroller, &wireless);
+                if (SUCCEEDED(hr) && wireless) {
+                    bus = SDL_HARDWARE_BUS_BLUETOOTH;
+                }
+
+                __x_ABI_CWindows_CGaming_CInput_CIGameController_Release(gamecontroller);
+            }
+
+            guid = SDL_CreateJoystickGUID(bus, vendor, product, version, name, 'w', (Uint8)type);
+
+            if (SDL_ShouldIgnoreJoystick(name, guid)) {
+                ignore_joystick = SDL_TRUE;
+            }
         }
 
-        if (ignore_joystick) {
-            SDL_free(name);
-        } else {
+        if (!ignore_joystick) {
             /* New device, add it */
             WindowsGamingInputControllerState *controllers = SDL_realloc(wgi.controllers, sizeof(wgi.controllers[0]) * (wgi.controller_count + 1));
             if (controllers) {
@@ -398,6 +515,8 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
             } else {
                 SDL_free(name);
             }
+        } else {
+            SDL_free(name);
         }
 
         __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller);
@@ -476,13 +595,12 @@ static RawGameControllerDelegate controller_removed = {
 
 static int WGI_JoystickInit(void)
 {
-    typedef HRESULT(WINAPI * WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER * hstringHeader, HSTRING * string);
-    typedef HRESULT(WINAPI * RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void **factory);
-
-    WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
-    RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
     HRESULT hr;
 
+    if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, SDL_TRUE)) {
+        return 0;
+    }
+
     if (FAILED(WIN_RoInitialize())) {
         return SDL_SetError("RoInitialize() failed");
     }
@@ -511,71 +629,7 @@ static int WGI_JoystickInit(void)
     }
 #endif
 
-#ifdef __WINRT__
-    WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
-    RoGetActivationFactoryFunc = RoGetActivationFactory;
-#else
-    {
-        WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
-        RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
-    }
-#endif /* __WINRT__ */
-    if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
-        PCWSTR pNamespace;
-        HSTRING_HEADER hNamespaceStringHeader;
-        HSTRING hNamespaceString;
-
-        pNamespace = L"Windows.Gaming.Input.RawGameController";
-        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
-        if (SUCCEEDED(hr)) {
-            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, (void **)&wgi.statics);
-            if (!SUCCEEDED(hr)) {
-                SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%lx", hr);
-            }
-        }
-
-        pNamespace = L"Windows.Gaming.Input.ArcadeStick";
-        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
-        if (SUCCEEDED(hr)) {
-            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, (void **)&wgi.arcade_stick_statics);
-            if (SUCCEEDED(hr)) {
-                __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2);
-            } else {
-                SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%lx", hr);
-            }
-        }
-
-        pNamespace = L"Windows.Gaming.Input.FlightStick";
-        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
-        if (SUCCEEDED(hr)) {
-            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, (void **)&wgi.flight_stick_statics);
-            if (!SUCCEEDED(hr)) {
-                SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%lx", hr);
-            }
-        }
-
-        pNamespace = L"Windows.Gaming.Input.Gamepad";
-        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
-        if (SUCCEEDED(hr)) {
-            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, (void **)&wgi.gamepad_statics);
-            if (SUCCEEDED(hr)) {
-                __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, (void **)&wgi.gamepad_statics2);
-            } else {
-                SDL_SetError("Couldn't find IGamepadStatics: 0x%lx", hr);
-            }
-        }
-
-        pNamespace = L"Windows.Gaming.Input.RacingWheel";
-        hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
-        if (SUCCEEDED(hr)) {
-            hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, (void **)&wgi.racing_wheel_statics);
-            if (SUCCEEDED(hr)) {
-                __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2);
-            } else {
-                SDL_SetError("Couldn't find IRacingWheelStatics: 0x%lx", hr);
-            }
-        }
-    }
+    WGI_LoadRawGameControllerStatics();
 
     if (wgi.statics) {
         __FIVectorView_1_Windows__CGaming__CInput__CRawGameController *controllers;

+ 14 - 7
Engine/lib/sdl/src/joystick/windows/SDL_xinputjoystick.c

@@ -235,6 +235,20 @@ static void AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pC
     JoyStick_DeviceData *pPrevJoystick = NULL;
     JoyStick_DeviceData *pNewJoystick = *pContext;
 
+#ifdef SDL_JOYSTICK_RAWINPUT
+    if (RAWINPUT_IsEnabled()) {
+        /* The raw input driver handles more than 4 controllers, so prefer that when available */
+        /* We do this check here rather than at the top of SDL_XINPUT_JoystickDetect() because
+           we need to check XInput state before RAWINPUT gets a hold of the device, otherwise
+           when a controller is connected via the wireless adapter, it will shut down at the
+           first subsequent XInput call. This seems like a driver stack bug?
+
+           Reference: https://github.com/libsdl-org/SDL/issues/3468
+         */
+        return;
+    }
+#endif
+
     if (SDL_XInputUseOldJoystickMapping() && SubType != XINPUT_DEVSUBTYPE_GAMEPAD) {
         return;
     }
@@ -322,13 +336,6 @@ void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
         return;
     }
 
-#ifdef SDL_JOYSTICK_RAWINPUT
-    if (RAWINPUT_IsEnabled()) {
-        /* The raw input driver handles more than 4 controllers, so prefer that when available */
-        return;
-    }
-#endif
-
     /* iterate in reverse, so these are in the final list in ascending numeric order. */
     for (iuserid = XUSER_MAX_COUNT - 1; iuserid >= 0; iuserid--) {
         const Uint8 userid = (Uint8)iuserid;

+ 1 - 1
Engine/lib/sdl/src/main/windows/SDL_windows_main.c

@@ -103,7 +103,7 @@ int console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
 #endif
 
 /* This is where execution begins [windowed apps] */
-int WINAPI
+int WINAPI MINGW32_FORCEALIGN
 WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) /* NOLINT(readability-inconsistent-declaration-parameter-name) */
 {
     return main_getcmdline();

+ 4 - 4
Engine/lib/sdl/src/main/windows/version.rc

@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,28,1,0
- PRODUCTVERSION 2,28,1,0
+ FILEVERSION 2,28,4,0
+ PRODUCTVERSION 2,28,4,0
  FILEFLAGSMASK 0x3fL
  FILEFLAGS 0x0L
  FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "\0"
             VALUE "FileDescription", "SDL\0"
-            VALUE "FileVersion", "2, 28, 1, 0\0"
+            VALUE "FileVersion", "2, 28, 4, 0\0"
             VALUE "InternalName", "SDL\0"
             VALUE "LegalCopyright", "Copyright (C) 2023 Sam Lantinga\0"
             VALUE "OriginalFilename", "SDL2.dll\0"
             VALUE "ProductName", "Simple DirectMedia Layer\0"
-            VALUE "ProductVersion", "2, 28, 1, 0\0"
+            VALUE "ProductVersion", "2, 28, 4, 0\0"
         END
     END
     BLOCK "VarFileInfo"

+ 3 - 5
Engine/lib/sdl/src/misc/emscripten/SDL_sysurl.c

@@ -23,13 +23,11 @@
 
 #include <emscripten/emscripten.h>
 
+EM_JS_DEPS(sdlsysurl, "$UTF8ToString");
+
 int SDL_SYS_OpenURL(const char *url)
 {
-    EM_ASM({
-        window.open(UTF8ToString($0), "_blank");
-    },
-           url);
-
+    EM_ASM(window.open(UTF8ToString($0), "_blank"), url);
     return 0;
 }
 

+ 13 - 0
Engine/lib/sdl/src/misc/unix/SDL_sysurl.c

@@ -32,6 +32,18 @@ int SDL_SYS_OpenURL(const char *url)
 {
     const pid_t pid1 = fork();
     if (pid1 == 0) { /* child process */
+#ifdef USE_POSIX_SPAWN
+        pid_t pid2;
+        const char *args[] = { "xdg-open", url, NULL };
+        /* Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam */
+        unsetenv("LD_PRELOAD");
+        if (posix_spawnp(&pid2, args[0], NULL, NULL, (char **)args, environ) == 0) {
+            /* Child process doesn't wait for possibly-blocking grandchild. */
+            _exit(EXIT_SUCCESS);
+        } else {
+            _exit(EXIT_FAILURE);
+        }
+#else
         pid_t pid2;
         /* Clear LD_PRELOAD so Chrome opens correctly when this application is launched by Steam */
         unsetenv("LD_PRELOAD");
@@ -46,6 +58,7 @@ int SDL_SYS_OpenURL(const char *url)
             /* Child process doesn't wait for possibly-blocking grandchild. */
             _exit(EXIT_SUCCESS);
         }
+#endif /* USE_POSIX_SPAWN */
     } else if (pid1 < 0) {
         return SDL_SetError("fork() failed: %s", strerror(errno));
     } else {

+ 1 - 1
Engine/lib/sdl/src/render/SDL_render.c

@@ -2481,7 +2481,7 @@ int SDL_RenderSetClipRect(SDL_Renderer *renderer, const SDL_Rect *rect)
     int retval;
     CHECK_RENDERER_MAGIC(renderer, -1)
 
-    if (rect && rect->w > 0 && rect->h > 0) {
+    if (rect && rect->w >= 0 && rect->h >= 0) {
         renderer->clipping_enabled = SDL_TRUE;
         renderer->clip_rect.x = (double)rect->x * renderer->scale.x;
         renderer->clip_rect.y = (double)rect->y * renderer->scale.y;

+ 1 - 1
Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c

@@ -2143,7 +2143,7 @@ static int D3D11_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect,
     D3D11_BOX srcBox;
     D3D11_MAPPED_SUBRESOURCE textureMemory;
 
-    ID3D11DeviceContext_OMGetRenderTargets(data->d3dContext, 1, &renderTargetView, NULL);
+    renderTargetView = D3D11_GetCurrentRenderTargetView(renderer);
     if (renderTargetView == NULL) {
         SDL_SetError("%s, ID3D11DeviceContext::OMGetRenderTargets failed", __FUNCTION__);
         goto done;

+ 6 - 1
Engine/lib/sdl/src/render/direct3d12/SDL_render_d3d12.c

@@ -2609,6 +2609,7 @@ static int D3D12_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
         case SDL_RENDERCMD_SETCLIPRECT:
         {
             const SDL_Rect *rect = &cmd->data.cliprect.rect;
+            SDL_Rect viewport_cliprect;
             if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) {
                 rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled;
                 rendererData->cliprectDirty = SDL_TRUE;
@@ -2616,7 +2617,11 @@ static int D3D12_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd,
             if (!rendererData->currentCliprectEnabled) {
                 /* If the clip rect is disabled, then the scissor rect should be the whole viewport,
                    since direct3d12 doesn't allow disabling the scissor rectangle */
-                rect = &rendererData->currentViewport;
+                viewport_cliprect.x = 0;
+                viewport_cliprect.y = 0;
+                viewport_cliprect.w = rendererData->currentViewport.w;
+                viewport_cliprect.h = rendererData->currentViewport.h;
+                rect = &viewport_cliprect;
             }
             if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof(*rect)) != 0) {
                 SDL_copyp(&rendererData->currentCliprect, rect);

+ 16 - 2
Engine/lib/sdl/src/render/metal/SDL_render_metal.m

@@ -1654,8 +1654,22 @@ static SDL_Renderer *METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
         return NULL;
     }
 
-    // !!! FIXME: MTLCopyAllDevices() can find other GPUs on macOS...
-    mtldevice = MTLCreateSystemDefaultDevice();
+#ifdef __MACOSX__
+    if (SDL_GetHintBoolean(SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE, SDL_TRUE)) {
+        NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
+
+        for (id<MTLDevice> device in devices) {
+            if (device.isLowPower) {
+                mtldevice = device;
+                break;
+            }
+        }
+    }
+#endif
+
+    if (mtldevice == nil) {
+        mtldevice = MTLCreateSystemDefaultDevice();
+    }
 
     if (mtldevice == nil) {
         SDL_free(renderer);

+ 6 - 10
Engine/lib/sdl/src/stdlib/SDL_iconv.c

@@ -795,17 +795,13 @@ char *SDL_iconv_string(const char *tocode, const char *fromcode, const char *inb
     size_t outbytesleft;
     size_t retCode = 0;
 
-    cd = SDL_iconv_open(tocode, fromcode);
-    if (cd == (SDL_iconv_t)-1) {
-        /* See if we can recover here (fixes iconv on Solaris 11) */
-        if (tocode == NULL || !*tocode) {
-            tocode = "UTF-8";
-        }
-        if (fromcode == NULL || !*fromcode) {
-            fromcode = "UTF-8";
-        }
-        cd = SDL_iconv_open(tocode, fromcode);
+    if (tocode == NULL || !*tocode) {
+        tocode = "UTF-8";
+    }
+    if (fromcode == NULL || !*fromcode) {
+        fromcode = "UTF-8";
     }
+    cd = SDL_iconv_open(tocode, fromcode);
     if (cd == (SDL_iconv_t)-1) {
         return NULL;
     }

+ 3 - 1
Engine/lib/sdl/src/stdlib/SDL_string.c

@@ -1190,7 +1190,9 @@ int SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                     suppress = SDL_TRUE;
                     break;
                 case 'h':
-                    if (inttype > DO_SHORT) {
+                    if (inttype == DO_INT) {
+                        inttype = DO_SHORT;
+                    } else if (inttype > DO_SHORT) {
                         ++inttype;
                     }
                     break;

+ 24 - 2
Engine/lib/sdl/src/test/SDL_test_compare.c

@@ -36,6 +36,25 @@
 /* Counter for _CompareSurface calls; used for filename creation when comparisons fail */
 static int _CompareSurfaceCount = 0;
 
+static Uint32
+GetPixel(Uint8 *p, size_t bytes_per_pixel)
+{
+    Uint32 ret = 0;
+
+    SDL_assert(bytes_per_pixel <= sizeof(ret));
+
+    /* Fill the appropriate number of least-significant bytes of ret,
+     * leaving the most-significant bytes set to zero, so that ret can
+     * be decoded with SDL_GetRGBA afterwards. */
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    SDL_memcpy(((Uint8 *) &ret) + (sizeof(ret) - bytes_per_pixel), p, bytes_per_pixel);
+#else
+    SDL_memcpy(&ret, p, bytes_per_pixel);
+#endif
+
+    return ret;
+}
+
 /* Compare surfaces */
 int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error)
 {
@@ -74,11 +93,14 @@ int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface,
     /* Compare image - should be same format. */
     for (j = 0; j < surface->h; j++) {
         for (i = 0; i < surface->w; i++) {
+            Uint32 pixel;
             p = (Uint8 *)surface->pixels + j * surface->pitch + i * bpp;
             p_reference = (Uint8 *)referenceSurface->pixels + j * referenceSurface->pitch + i * bpp_reference;
 
-            SDL_GetRGBA(*(Uint32 *)p, surface->format, &R, &G, &B, &A);
-            SDL_GetRGBA(*(Uint32 *)p_reference, referenceSurface->format, &Rd, &Gd, &Bd, &Ad);
+            pixel = GetPixel(p, bpp);
+            SDL_GetRGBA(pixel, surface->format, &R, &G, &B, &A);
+            pixel = GetPixel(p_reference, bpp_reference);
+            SDL_GetRGBA(pixel, referenceSurface->format, &Rd, &Gd, &Bd, &Ad);
 
             dist = 0;
             dist += (R - Rd) * (R - Rd);

+ 20 - 30
Engine/lib/sdl/src/thread/windows/SDL_sysmutex.c

@@ -71,10 +71,8 @@ static SDL_mutex *SDL_CreateMutex_srw(void)
 
 static void SDL_DestroyMutex_srw(SDL_mutex *mutex)
 {
-    if (mutex != NULL) {
-        /* There are no kernel allocated resources */
-        SDL_free(mutex);
-    }
+    /* There are no kernel allocated resources */
+    SDL_free(mutex);
 }
 
 static int SDL_LockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
@@ -82,10 +80,6 @@ static int SDL_LockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /*
     SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
     DWORD this_thread;
 
-    if (mutex == NULL) {
-        return 0;
-    }
-
     this_thread = GetCurrentThreadId();
     if (mutex->owner == this_thread) {
         ++mutex->count;
@@ -108,10 +102,6 @@ static int SDL_TryLockMutex_srw(SDL_mutex *_mutex)
     DWORD this_thread;
     int retval = 0;
 
-    if (mutex == NULL) {
-        return 0;
-    }
-
     this_thread = GetCurrentThreadId();
     if (mutex->owner == this_thread) {
         ++mutex->count;
@@ -131,10 +121,6 @@ static int SDL_UnlockMutex_srw(SDL_mutex *_mutex) SDL_NO_THREAD_SAFETY_ANALYSIS
 {
     SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex;
 
-    if (mutex == NULL) {
-        return 0;
-    }
-
     if (mutex->owner == GetCurrentThreadId()) {
         if (--mutex->count == 0) {
             mutex->owner = 0;
@@ -185,19 +171,15 @@ static SDL_mutex *SDL_CreateMutex_cs(void)
 static void SDL_DestroyMutex_cs(SDL_mutex *mutex_)
 {
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
-    if (mutex != NULL) {
-        DeleteCriticalSection(&mutex->cs);
-        SDL_free(mutex);
-    }
+
+    DeleteCriticalSection(&mutex->cs);
+    SDL_free(mutex);
 }
 
 /* Lock the mutex */
 static int SDL_LockMutex_cs(SDL_mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
-    if (mutex == NULL) {
-        return 0;
-    }
 
     EnterCriticalSection(&mutex->cs);
     return 0;
@@ -208,9 +190,6 @@ static int SDL_TryLockMutex_cs(SDL_mutex *mutex_)
 {
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
     int retval = 0;
-    if (mutex == NULL) {
-        return 0;
-    }
 
     if (TryEnterCriticalSection(&mutex->cs) == 0) {
         retval = SDL_MUTEX_TIMEDOUT;
@@ -222,9 +201,6 @@ static int SDL_TryLockMutex_cs(SDL_mutex *mutex_)
 static int SDL_UnlockMutex_cs(SDL_mutex *mutex_) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
 {
     SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_;
-    if (mutex == NULL) {
-        return 0;
-    }
 
     LeaveCriticalSection(&mutex->cs);
     return 0;
@@ -277,21 +253,35 @@ SDL_mutex *SDL_CreateMutex(void)
 
 void SDL_DestroyMutex(SDL_mutex *mutex)
 {
-    SDL_mutex_impl_active.Destroy(mutex);
+    if (mutex) {
+        SDL_mutex_impl_active.Destroy(mutex);
+    }
 }
 
 int SDL_LockMutex(SDL_mutex *mutex)
 {
+    if (mutex == NULL) {
+        return 0;
+    }
+
     return SDL_mutex_impl_active.Lock(mutex);
 }
 
 int SDL_TryLockMutex(SDL_mutex *mutex)
 {
+    if (mutex == NULL) {
+        return 0;
+    }
+
     return SDL_mutex_impl_active.TryLock(mutex);
 }
 
 int SDL_UnlockMutex(SDL_mutex *mutex)
 {
+    if (mutex == NULL) {
+        return 0;
+    }
+
     return SDL_mutex_impl_active.Unlock(mutex);
 }
 

+ 2 - 2
Engine/lib/sdl/src/thread/windows/SDL_systhread.c

@@ -55,12 +55,12 @@ static DWORD RunThread(void *data)
     return 0;
 }
 
-static DWORD WINAPI RunThreadViaCreateThread(LPVOID data)
+static DWORD WINAPI MINGW32_FORCEALIGN RunThreadViaCreateThread(LPVOID data)
 {
     return RunThread(data);
 }
 
-static unsigned __stdcall RunThreadViaBeginThreadEx(void *data)
+static unsigned __stdcall MINGW32_FORCEALIGN RunThreadViaBeginThreadEx(void *data)
 {
     return (unsigned)RunThread(data);
 }

+ 9 - 5
Engine/lib/sdl/src/video/SDL_video.c

@@ -18,6 +18,7 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+
 #include "../SDL_internal.h"
 
 /* The high-level video driver subsystem */
@@ -127,15 +128,15 @@ static VideoBootStrap *bootstrap[] = {
 #if SDL_VIDEO_DRIVER_QNX
     &QNX_bootstrap,
 #endif
-#if SDL_VIDEO_DRIVER_OFFSCREEN
-    &OFFSCREEN_bootstrap,
+#if SDL_VIDEO_DRIVER_OS2
+    &OS2DIVE_bootstrap,
+    &OS2VMAN_bootstrap,
 #endif
 #if SDL_VIDEO_DRIVER_NGAGE
     &NGAGE_bootstrap,
 #endif
-#if SDL_VIDEO_DRIVER_OS2
-    &OS2DIVE_bootstrap,
-    &OS2VMAN_bootstrap,
+#if SDL_VIDEO_DRIVER_OFFSCREEN
+    &OFFSCREEN_bootstrap,
 #endif
 #if SDL_VIDEO_DRIVER_DUMMY
     &DUMMY_bootstrap,
@@ -1398,6 +1399,9 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen)
 #endif
 
     display = SDL_GetDisplayForWindow(window);
+    if (display == NULL) { /* No display connected, nothing to do. */
+        return 0;
+    }
 
     if (fullscreen) {
         /* Hide any other fullscreen windows */

+ 2 - 0
Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.h

@@ -40,6 +40,8 @@ typedef struct {
     /* What location we last saw the cursor move to. */
     CGFloat lastMoveX;
     CGFloat lastMoveY;
+    /* If we just turned on relative mode, and should skip a single mouse motion event. */
+    SDL_bool justEnabledRelative;
 } SDL_MouseData;
 
 @interface NSCursor (InvisibleCursor)

+ 9 - 1
Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.m

@@ -293,8 +293,11 @@ static int Cocoa_SetRelativeMouseMode(SDL_bool enabled)
     if (enabled) {
         if (window) {
             /* make sure the mouse isn't at the corner of the window, as this can confuse things if macOS thinks a window resize is happening on the first click. */
+            SDL_MouseData *mousedriverdata = (SDL_MouseData*)SDL_GetMouse()->driverdata;
             const CGPoint point = CGPointMake((float)(window->x + (window->w / 2)), (float)(window->y + (window->h / 2)));
-            Cocoa_HandleMouseWarp(point.x, point.y);
+            if (mousedriverdata) {
+                mousedriverdata->justEnabledRelative = SDL_TRUE;
+            }
             CGWarpMouseCursorPosition(point);
         }
         DLog("Turning on.");
@@ -465,6 +468,11 @@ void Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
     seenWarp = driverdata->seenWarp;
     driverdata->seenWarp = NO;
 
+    if (driverdata->justEnabledRelative) {
+        driverdata->justEnabledRelative = SDL_FALSE;
+        return;  // dump the first event back.
+    }
+
     location =  [NSEvent mouseLocation];
     lastMoveX = driverdata->lastMoveX;
     lastMoveY = driverdata->lastMoveY;

Some files were not shown because too many files changed in this diff