Browse Source

Re-added WinRT support until we're sure that it's no longer being used

Sam Lantinga 2 năm trước cách đây
mục cha
commit
a635a485bc
92 tập tin đã thay đổi với 8410 bổ sung164 xóa
  1. 3 0
      .github/workflows/msvc.yml
  2. 82 25
      CMakeLists.txt
  3. 1 1
      Makefile.in
  4. 1 0
      VisualC-GDK/SDL/SDL.vcxproj
  5. 3 0
      VisualC-GDK/SDL/SDL.vcxproj.filters
  6. 40 0
      VisualC-WinRT/SDL-UWP.sln
  7. 594 0
      VisualC-WinRT/SDL-UWP.vcxproj
  8. 849 0
      VisualC-WinRT/SDL-UWP.vcxproj.filters
  9. 1 0
      VisualC/SDL/SDL.vcxproj
  10. 3 0
      VisualC/SDL/SDL.vcxproj.filters
  11. 6 0
      build-scripts/fnsince.pl
  12. 2 2
      cmake/test/CMakeLists.txt
  13. 519 0
      docs/README-winrt.md
  14. 1 0
      docs/README.md
  15. 2 0
      include/SDL_config.h
  16. 2 0
      include/SDL_config.h.cmake
  17. 2 0
      include/SDL_config_windows.h
  18. 220 0
      include/SDL_config_winrt.h
  19. 1 1
      include/SDL_cpuinfo.h
  20. 99 0
      include/SDL_hints.h
  21. 28 0
      include/SDL_main.h
  22. 2 1
      include/SDL_platform.h
  23. 103 0
      include/SDL_system.h
  24. 11 0
      include/SDL_syswm.h
  25. 2 2
      include/begin_code.h
  26. 3 1
      src/SDL.c
  27. 7 7
      src/SDL_log.c
  28. 1 1
      src/atomic/SDL_spinlock.c
  29. 29 86
      src/audio/wasapi/SDL_wasapi.c
  30. 17 0
      src/audio/wasapi/SDL_wasapi.h
  31. 162 0
      src/audio/wasapi/SDL_wasapi_win32.c
  32. 447 0
      src/audio/wasapi/SDL_wasapi_winrt.cpp
  33. 4 0
      src/core/windows/SDL_hid.c
  34. 4 0
      src/core/windows/SDL_hid.h
  35. 27 10
      src/core/windows/SDL_windows.c
  36. 2 0
      src/core/windows/SDL_windows.h
  37. 3 3
      src/core/windows/SDL_xinput.c
  38. 67 0
      src/core/winrt/SDL_winrtapp_common.cpp
  39. 31 0
      src/core/winrt/SDL_winrtapp_common.h
  40. 797 0
      src/core/winrt/SDL_winrtapp_direct3d.cpp
  41. 92 0
      src/core/winrt/SDL_winrtapp_direct3d.h
  42. 160 0
      src/core/winrt/SDL_winrtapp_xaml.cpp
  43. 33 0
      src/core/winrt/SDL_winrtapp_xaml.h
  44. 2 2
      src/cpuinfo/SDL_cpuinfo.c
  45. 2 0
      src/dynapi/SDL_dynapi.h
  46. 4 0
      src/dynapi/SDL_dynapi_overrides.h
  47. 8 0
      src/dynapi/SDL_dynapi_procs.h
  48. 3 0
      src/file/SDL_rwops.c
  49. 242 0
      src/filesystem/winrt/SDL_sysfilesystem.cpp
  50. 4 0
      src/joystick/SDL_joystick.c
  51. 5 0
      src/joystick/windows/SDL_rawinputjoystick.c
  52. 22 5
      src/joystick/windows/SDL_windows_gaming_input.c
  53. 9 5
      src/joystick/windows/SDL_windowsjoystick.c
  54. 7 3
      src/joystick/windows/SDL_xinputjoystick.c
  55. 8 0
      src/loadso/windows/SDL_sysloadso.c
  56. 58 0
      src/locale/winrt/SDL_syslocale.c
  57. 0 0
      src/main/winrt/SDL3-WinRTResource_BlankCursor.cur
  58. 3 0
      src/main/winrt/SDL3-WinRTResources.rc
  59. 54 0
      src/main/winrt/SDL_winrt_main_NonXAML.cpp
  60. 41 0
      src/misc/winrt/SDL_sysurl.cpp
  61. 3 0
      src/power/SDL_power.c
  62. 1 0
      src/power/SDL_syspower.h
  63. 44 0
      src/power/winrt/SDL_syspower.cpp
  64. 56 1
      src/render/direct3d11/SDL_render_d3d11.c
  65. 116 0
      src/render/direct3d11/SDL_render_winrt.cpp
  66. 40 0
      src/render/direct3d11/SDL_render_winrt.h
  67. 8 0
      src/render/opengles2/SDL_render_gles2.c
  68. 31 0
      src/thread/stdcpp/SDL_systhread.cpp
  69. 12 0
      src/thread/windows/SDL_syscond_cv.c
  70. 16 0
      src/thread/windows/SDL_sysmutex.c
  71. 15 0
      src/thread/windows/SDL_syssem.c
  72. 3 1
      src/thread/windows/SDL_systhread.c
  73. 12 0
      src/thread/windows/SDL_systls.c
  74. 21 1
      src/timer/windows/SDL_systimer.c
  75. 6 4
      src/video/SDL_egl.c
  76. 1 1
      src/video/SDL_stretch.c
  77. 1 0
      src/video/SDL_sysvideo.h
  78. 54 1
      src/video/SDL_video.c
  79. 153 0
      src/video/winrt/SDL_winrtevents.cpp
  80. 83 0
      src/video/winrt/SDL_winrtevents_c.h
  81. 196 0
      src/video/winrt/SDL_winrtgamebar.cpp
  82. 35 0
      src/video/winrt/SDL_winrtgamebar_cpp.h
  83. 466 0
      src/video/winrt/SDL_winrtkeyboard.cpp
  84. 118 0
      src/video/winrt/SDL_winrtmessagebox.cpp
  85. 29 0
      src/video/winrt/SDL_winrtmessagebox.h
  86. 222 0
      src/video/winrt/SDL_winrtmouse.cpp
  87. 40 0
      src/video/winrt/SDL_winrtmouse_c.h
  88. 203 0
      src/video/winrt/SDL_winrtopengles.cpp
  89. 70 0
      src/video/winrt/SDL_winrtopengles.h
  90. 407 0
      src/video/winrt/SDL_winrtpointerinput.cpp
  91. 907 0
      src/video/winrt/SDL_winrtvideo.cpp
  92. 106 0
      src/video/winrt/SDL_winrtvideo_cpp.h

+ 3 - 0
.github/workflows/msvc.yml

@@ -19,6 +19,8 @@ jobs:
         - { name: Windows (clang-cl x86), flags: -T ClangCL -A Win32 }
         - { name: Windows (ARM),          flags: -A ARM }
         - { name: Windows (ARM64),        flags: -A ARM64 }
+        - { name: UWP (x64),              flags: -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0" -DSDL_TESTS=OFF, nowerror: true,
+            project: VisualC-WinRT/SDL-UWP.sln, projectflags: '/p:Platform=x64 /p:WindowsTargetPlatformVersion=10.0.17763.0' }
 
     steps:
     - uses: actions/checkout@v3
@@ -57,6 +59,7 @@ jobs:
         echo "SDL3_DIR=$Env:GITHUB_WORKSPACE/prefix" >> $Env:GITHUB_ENV
         cmake --install build/
     - name: Verify CMake configuration files
+      if: ${{ !contains(matrix.platform.name, 'UWP') }}  # FIXME: cmake/test/CMakeLists.txt should support UWP
       run: |
         cmake -S cmake/test -B cmake_config_build `
           -DCMAKE_PREFIX_PATH=${{ env.SDL3_DIR }} `

+ 82 - 25
CMakeLists.txt

@@ -26,6 +26,12 @@ set(EXTRA_LDFLAGS)
 #  etc. See https://github.com/libsdl-org/SDL/issues/4150
 add_library(sdl-build-options INTERFACE)
 
+if(WINDOWS_STORE)
+  cmake_minimum_required(VERSION 3.11.0)
+  target_compile_definitions(sdl-build-options INTERFACE "-DSDL_BUILDING_WINRT=1")
+  target_compile_options(sdl-build-options INTERFACE "-ZW")
+endif()
+
 # Build in parallel under Visual Studio. Not enabled by default.
 if(MSVC)
   target_compile_options(sdl-build-options INTERFACE "/MP")
@@ -233,7 +239,7 @@ endif()
 #  so we'll just use libusb when it's available. libusb does not support iOS,
 #  so we default to yes on iOS.
 #  TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
-if(WINDOWS OR IOS OR TVOS OR ANDROID)
+if((WINDOWS AND NOT WINDOWS_STORE) OR IOS OR TVOS OR ANDROID)
   set(HIDAPI_SKIP_LIBUSB TRUE)
 else()
   set(HIDAPI_SKIP_LIBUSB FALSE)
@@ -1664,6 +1670,11 @@ elseif(WINDOWS)
   file(GLOB CORE_SOURCES ${SDL3_SOURCE_DIR}/src/core/windows/*.c)
   list(APPEND SOURCE_FILES ${CORE_SOURCES})
 
+  if(WINDOWS_STORE)
+    file(GLOB WINRT_SOURCE_FILES ${SDL3_SOURCE_DIR}/src/core/winrt/*.c ${SDL3_SOURCE_DIR}/src/core/winrt/*.cpp)
+    list(APPEND SOURCE_FILES ${WINRT_SOURCE_FILES})
+  endif()
+
   if(MSVC AND NOT SDL_LIBC)
     # Prevent codegen that would use the VC runtime libraries.
     set_property(DIRECTORY . APPEND PROPERTY COMPILE_OPTIONS "/GS-")
@@ -1673,7 +1684,11 @@ elseif(WINDOWS)
   endif()
 
   if(SDL_MISC)
-    file(GLOB MISC_SOURCES ${SDL3_SOURCE_DIR}/src/misc/windows/*.c)
+    if(WINDOWS_STORE)
+      file(GLOB MISC_SOURCES ${SDL3_SOURCE_DIR}/src/misc/winrt/*.cpp)
+    else()
+      file(GLOB MISC_SOURCES ${SDL3_SOURCE_DIR}/src/misc/windows/*.c)
+    endif()
     list(APPEND SOURCE_FILES ${MISC_SOURCES})
     set(HAVE_SDL_MISC TRUE)
   endif()
@@ -1703,7 +1718,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(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM")
+    if(WINDOWS_STORE OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM")
       set(HAVE_DINPUT_H 0)
     endif()
     check_include_file(dxgi.h HAVE_DXGI_H)
@@ -1750,7 +1765,7 @@ elseif(WINDOWS)
   check_include_file(shellscalingapi.h HAVE_SHELLSCALINGAPI_H)
 
   if(SDL_AUDIO)
-    if(HAVE_DSOUND_H)
+    if(HAVE_DSOUND_H AND NOT WINDOWS_STORE)
       set(SDL_AUDIO_DRIVER_DSOUND 1)
       file(GLOB DSOUND_AUDIO_SOURCES ${SDL3_SOURCE_DIR}/src/audio/directsound/*.c)
       list(APPEND SOURCE_FILES ${DSOUND_AUDIO_SOURCES})
@@ -1761,6 +1776,9 @@ elseif(WINDOWS)
       set(SDL_AUDIO_DRIVER_WASAPI 1)
       set(HAVE_WASAPI TRUE)
       file(GLOB WASAPI_AUDIO_SOURCES ${SDL3_SOURCE_DIR}/src/audio/wasapi/*.c)
+      if(WINDOWS_STORE)
+        list(APPEND WASAPI_AUDIO_SOURCES ${SDL3_SOURCE_DIR}/src/audio/wasapi/SDL_wasapi_winrt.cpp)
+      endif()
       list(APPEND SOURCE_FILES ${WASAPI_AUDIO_SOURCES})
       set(HAVE_SDL_AUDIO TRUE)
     endif()
@@ -1771,11 +1789,20 @@ elseif(WINDOWS)
     if(NOT SDL_LOADSO)
       message_error("SDL_VIDEO requires SDL_LOADSO, which is not enabled")
     endif()
-    set(SDL_VIDEO_DRIVER_WINDOWS 1)
-    file(GLOB WIN_VIDEO_SOURCES ${SDL3_SOURCE_DIR}/src/video/windows/*.c)
+    if(WINDOWS_STORE)
+      set(SDL_VIDEO_DRIVER_WINRT 1)
+      file(GLOB WIN_VIDEO_SOURCES
+        ${SDL3_SOURCE_DIR}/src/video/winrt/*.c
+        ${SDL3_SOURCE_DIR}/src/video/winrt/*.cpp
+        ${SDL3_SOURCE_DIR}/src/render/direct3d11/*.cpp
+        )
+    else()
+      set(SDL_VIDEO_DRIVER_WINDOWS 1)
+      file(GLOB WIN_VIDEO_SOURCES ${SDL3_SOURCE_DIR}/src/video/windows/*.c)
+    endif()
     list(APPEND SOURCE_FILES ${WIN_VIDEO_SOURCES})
 
-    if(SDL_RENDER_D3D AND HAVE_D3D_H)
+    if(SDL_RENDER_D3D AND HAVE_D3D_H AND NOT WINDOWS_STORE)
       set(SDL_VIDEO_RENDER_D3D 1)
       set(HAVE_RENDER_D3D TRUE)
     endif()
@@ -1783,7 +1810,7 @@ elseif(WINDOWS)
       set(SDL_VIDEO_RENDER_D3D11 1)
       set(HAVE_RENDER_D3D TRUE)
     endif()
-    if(SDL_RENDER_D3D AND HAVE_D3D12_H)
+    if(SDL_RENDER_D3D AND HAVE_D3D12_H AND NOT WINDOWS_STORE)
       set(SDL_VIDEO_RENDER_D3D12 1)
       set(HAVE_RENDER_D3D TRUE)
     endif()
@@ -1803,7 +1830,7 @@ elseif(WINDOWS)
     set(HAVE_SDL_THREADS TRUE)
   endif()
 
-  if(SDL_SENSOR AND HAVE_SENSORSAPI_H)
+  if(SDL_SENSOR AND HAVE_SENSORSAPI_H AND NOT WINDOWS_STORE)
     set(SDL_SENSOR_WINDOWS 1)
     set(HAVE_SDL_SENSORS TRUE)
     file(GLOB WINDOWS_SENSOR_SOURCES ${SDL3_SOURCE_DIR}/src/sensor/windows/*.c)
@@ -1811,26 +1838,50 @@ elseif(WINDOWS)
   endif()
 
   if(SDL_POWER)
-    set(SDL_POWER_WINDOWS 1)
-    list(APPEND SOURCE_FILES ${SDL3_SOURCE_DIR}/src/power/windows/SDL_syspower.c)
-    set(HAVE_SDL_POWER TRUE)
+    if(WINDOWS_STORE)
+      set(SDL_POWER_WINRT 1)
+      list(APPEND SOURCE_FILES ${SDL3_SOURCE_DIR}/src/power/winrt/SDL_syspower.cpp)
+    else()
+      set(SDL_POWER_WINDOWS 1)
+      list(APPEND SOURCE_FILES ${SDL3_SOURCE_DIR}/src/power/windows/SDL_syspower.c)
+      set(HAVE_SDL_POWER TRUE)
+    endif()
   endif()
 
   if(SDL_LOCALE)
-    file(GLOB LOCALE_SOURCES ${SDL3_SOURCE_DIR}/src/locale/windows/*.c)
+    if(WINDOWS_STORE)
+      file(GLOB LOCALE_SOURCES ${SDL3_SOURCE_DIR}/src/locale/winrt/*.c)
+    else()
+      file(GLOB LOCALE_SOURCES ${SDL3_SOURCE_DIR}/src/locale/windows/*.c)
+    endif()
     list(APPEND SOURCE_FILES ${LOCALE_SOURCES})
     set(HAVE_SDL_LOCALE TRUE)
   endif()
 
   if(SDL_FILESYSTEM)
     set(SDL_FILESYSTEM_WINDOWS 1)
-    file(GLOB FILESYSTEM_SOURCES ${SDL3_SOURCE_DIR}/src/filesystem/windows/*.c)
+    if(WINDOWS_STORE)
+      file(GLOB FILESYSTEM_SOURCES ${SDL3_SOURCE_DIR}/src/filesystem/winrt/*.cpp)
+    else()
+      file(GLOB FILESYSTEM_SOURCES ${SDL3_SOURCE_DIR}/src/filesystem/windows/*.c)
+    endif()
     list(APPEND SOURCE_FILES ${FILESYSTEM_SOURCES})
     set(HAVE_SDL_FILESYSTEM TRUE)
   endif()
 
   # Libraries for Win32 native and MinGW
-  list(APPEND EXTRA_LIBS user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)
+  if(NOT WINDOWS_STORE)
+    list(APPEND EXTRA_LIBS user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)
+  endif()
+
+  if(WINDOWS_STORE)
+    list(APPEND EXTRA_LIBS
+      -nodefaultlib:vccorlib$<$<CONFIG:Debug>:d>
+      -nodefaultlib:msvcrt$<$<CONFIG:Debug>:d>
+      vccorlib$<$<CONFIG:Debug>:d>.lib
+      msvcrt$<$<CONFIG:Debug>:d>.lib
+    )
+  endif()
 
   if(SDL_TIMERS)
     set(SDL_TIMER_WINDOWS 1)
@@ -1850,7 +1901,7 @@ elseif(WINDOWS)
   list(APPEND SOURCE_FILES ${CORE_SOURCES})
 
   if(SDL_VIDEO)
-    if(SDL_OPENGL)
+    if(SDL_OPENGL AND NOT WINDOWS_STORE)
       set(SDL_VIDEO_OPENGL 1)
       set(SDL_VIDEO_OPENGL_WGL 1)
       set(SDL_VIDEO_RENDER_OGL 1)
@@ -1878,14 +1929,18 @@ elseif(WINDOWS)
     file(GLOB JOYSTICK_SOURCES ${SDL3_SOURCE_DIR}/src/joystick/windows/*.c)
     list(APPEND SOURCE_FILES ${JOYSTICK_SOURCES})
 
-    set(SDL_JOYSTICK_RAWINPUT 1)
+    if(NOT WINDOWS_STORE)
+      set(SDL_JOYSTICK_RAWINPUT 1)
+    endif()
     if(HAVE_DINPUT_H)
       set(SDL_JOYSTICK_DINPUT 1)
       list(APPEND EXTRA_LIBS dinput8)
     endif()
     if(HAVE_XINPUT_H)
-      set(SDL_JOYSTICK_XINPUT 1)
-      set(HAVE_XINPUT TRUE)
+      if(NOT WINDOWS_STORE)
+        set(SDL_JOYSTICK_XINPUT 1)
+        set(HAVE_XINPUT TRUE)
+      endif()
       if(HAVE_WINDOWS_GAMING_INPUT_H)
         set(SDL_JOYSTICK_WGI 1)
       endif()
@@ -1893,7 +1948,7 @@ elseif(WINDOWS)
     set(HAVE_SDL_JOYSTICK TRUE)
 
     if(SDL_HAPTIC)
-      if(HAVE_DINPUT_H OR HAVE_XINPUT_H)
+      if((HAVE_DINPUT_H OR HAVE_XINPUT_H) AND NOT WINDOWS_STORE)
         file(GLOB HAPTIC_SOURCES ${SDL3_SOURCE_DIR}/src/haptic/windows/*.c)
         if(HAVE_DINPUT_H)
           set(SDL_HAPTIC_DINPUT 1)
@@ -3071,7 +3126,7 @@ endif()
 # Ensure that the extra cflags are used at compile time
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} ${EXTRA_CFLAGS_BUILD}")
 
-if(NOT SDL3_DISABLE_SDL3MAIN)
+if(NOT WINDOWS_STORE AND NOT SDL3_DISABLE_SDL3MAIN)
   # Build SDLmain
   add_library(SDL3main STATIC ${SDLMAIN_SOURCES})
   add_dependencies(SDL3main sdl_headers_copy)
@@ -3153,8 +3208,10 @@ if(SDL_SHARED)
   # 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")
     # Don't try to link with the default set of libraries.
-    set_target_properties(SDL3 PROPERTIES LINK_FLAGS_RELEASE "/NODEFAULTLIB")
-    set_target_properties(SDL3 PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB")
+    if(NOT WINDOWS_STORE)
+      set_target_properties(SDL3 PROPERTIES LINK_FLAGS_RELEASE "/NODEFAULTLIB")
+      set_target_properties(SDL3 PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB")
+    endif()
     set_target_properties(SDL3 PROPERTIES STATIC_LIBRARY_FLAGS "/NODEFAULTLIB")
   endif()
   # FIXME: if CMAKE_VERSION >= 3.13, use target_link_options for EXTRA_LDFLAGS
@@ -3236,7 +3293,7 @@ if(NOT SDL3_DISABLE_INSTALL)
       RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
   endif()
 
-  if(NOT SDL3_DISABLE_SDL3MAIN)
+  if(NOT WINDOWS_STORE AND NOT SDL3_DISABLE_SDL3MAIN)
     install(TARGETS SDL3main EXPORT SDL3mainTargets
       LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
@@ -3289,7 +3346,7 @@ if(NOT SDL3_DISABLE_INSTALL)
     endif()
   endif()
 
-  if(NOT SDL3_DISABLE_SDL3MAIN)
+  if(NOT WINDOWS_STORE AND NOT SDL3_DISABLE_SDL3MAIN)
     install(EXPORT SDL3mainTargets
       FILE SDL3mainTargets.cmake
       NAMESPACE SDL3::

+ 1 - 1
Makefile.in

@@ -51,7 +51,7 @@ WAYLAND_SCANNER_CODE_MODE = @WAYLAND_SCANNER_CODE_MODE@
 
 INSTALL_SDL3_CONFIG = @INSTALL_SDL3_CONFIG@
 
-SRC_DIST = *.md *.txt acinclude Android.mk autogen.sh android-project build-scripts cmake cmake_uninstall.cmake.in configure configure.ac docs include Makefile.* mingw sdl3-config.cmake.in sdl3-config-version.cmake.in sdl3-config.in sdl3.m4 sdl3.pc.in SDL3.spec.in SDL3Config.cmake.in src test VisualC Xcode Xcode-iOS wayland-protocols
+SRC_DIST = *.md *.txt acinclude Android.mk autogen.sh android-project build-scripts cmake cmake_uninstall.cmake.in configure configure.ac docs include Makefile.* mingw sdl3-config.cmake.in sdl3-config-version.cmake.in sdl3-config.in sdl3.m4 sdl3.pc.in SDL3.spec.in SDL3Config.cmake.in src test VisualC VisualC-WinRT Xcode Xcode-iOS wayland-protocols
 GEN_DIST = SDL3.spec
 
 ifneq ($V,1)

+ 1 - 0
VisualC-GDK/SDL/SDL.vcxproj

@@ -534,6 +534,7 @@
     <ClCompile Include="..\..\src\audio\SDL_mixer.c" />
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
+    <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />

+ 3 - 0
VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -1021,6 +1021,9 @@
     <ClCompile Include="..\..\src\audio\dummy\SDL_dummyaudio.c">
       <Filter>audio\dummy</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c">
+      <Filter>audio\wasapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c">
       <Filter>audio\wasapi</Filter>
     </ClCompile>

+ 40 - 0
VisualC-WinRT/SDL-UWP.sln

@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL3-UWP", "SDL-UWP.vcxproj", "{89E9B32E-A86A-47C3-A948-D2B1622925CE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|ARM = Debug|ARM
+		Debug|ARM64 = Debug|ARM64
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|ARM = Release|ARM
+		Release|ARM64 = Release|ARM64
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|ARM.ActiveCfg = Debug|ARM
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|ARM.Build.0 = Debug|ARM
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|ARM64.ActiveCfg = Debug|ARM64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|ARM64.Build.0 = Debug|ARM64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x64.ActiveCfg = Debug|x64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x64.Build.0 = Debug|x64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x86.ActiveCfg = Debug|Win32
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x86.Build.0 = Debug|Win32
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|ARM.ActiveCfg = Release|ARM
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|ARM.Build.0 = Release|ARM
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|ARM64.ActiveCfg = Release|ARM64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|ARM64.Build.0 = Release|ARM64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x64.ActiveCfg = Release|x64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x64.Build.0 = Release|x64
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x86.ActiveCfg = Release|Win32
+		{89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 594 - 0
VisualC-WinRT/SDL-UWP.vcxproj

@@ -0,0 +1,594 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|ARM64">
+      <Configuration>Debug</Configuration>
+      <Platform>ARM64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|ARM">
+      <Configuration>Debug</Configuration>
+      <Platform>ARM</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|ARM">
+      <Configuration>Release</Configuration>
+      <Platform>ARM</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|ARM64">
+      <Configuration>Release</Configuration>
+      <Platform>ARM64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\include\begin_code.h" />
+    <ClInclude Include="..\include\close_code.h" />
+    <ClInclude Include="..\include\SDL.h" />
+    <ClInclude Include="..\include\SDL_assert.h" />
+    <ClInclude Include="..\include\SDL_atomic.h" />
+    <ClInclude Include="..\include\SDL_audio.h" />
+    <ClInclude Include="..\include\SDL_blendmode.h" />
+    <ClInclude Include="..\include\SDL_clipboard.h" />
+    <ClInclude Include="..\include\SDL_config.h" />
+    <ClInclude Include="..\include\SDL_config_minimal.h" />
+    <ClInclude Include="..\include\SDL_config_winrt.h" />
+    <ClInclude Include="..\include\SDL_copying.h" />
+    <ClInclude Include="..\include\SDL_cpuinfo.h" />
+    <ClInclude Include="..\include\SDL_egl.h" />
+    <ClInclude Include="..\include\SDL_endian.h" />
+    <ClInclude Include="..\include\SDL_error.h" />
+    <ClInclude Include="..\include\SDL_events.h" />
+    <ClInclude Include="..\include\SDL_filesystem.h" />
+    <ClInclude Include="..\include\SDL_guid.h" />
+    <ClInclude Include="..\include\SDL_haptic.h" />
+    <ClInclude Include="..\include\SDL_hints.h" />
+    <ClInclude Include="..\include\SDL_hidapi.h" />
+    <ClInclude Include="..\include\SDL_input.h" />
+    <ClInclude Include="..\include\SDL_joystick.h" />
+    <ClInclude Include="..\include\SDL_keyboard.h" />
+    <ClInclude Include="..\include\SDL_keycode.h" />
+    <ClInclude Include="..\include\SDL_loadso.h" />
+    <ClInclude Include="..\include\SDL_locale.h" />
+    <ClInclude Include="..\include\SDL_log.h" />
+    <ClInclude Include="..\include\SDL_main.h" />
+    <ClInclude Include="..\include\SDL_misc.h" />
+    <ClInclude Include="..\include\SDL_mouse.h" />
+    <ClInclude Include="..\include\SDL_mutex.h" />
+    <ClInclude Include="..\include\SDL_name.h" />
+    <ClInclude Include="..\include\SDL_opengles2.h" />
+    <ClInclude Include="..\include\SDL_pixels.h" />
+    <ClInclude Include="..\include\SDL_platform.h" />
+    <ClInclude Include="..\include\SDL_power.h" />
+    <ClInclude Include="..\include\SDL_quit.h" />
+    <ClInclude Include="..\include\SDL_rect.h" />
+    <ClInclude Include="..\include\SDL_render.h" />
+    <ClInclude Include="..\include\SDL_revision.h" />
+    <ClInclude Include="..\include\SDL_rwops.h" />
+    <ClInclude Include="..\include\SDL_scancode.h" />
+    <ClInclude Include="..\include\SDL_sensor.h" />
+    <ClInclude Include="..\include\SDL_shape.h" />
+    <ClInclude Include="..\include\SDL_stdinc.h" />
+    <ClInclude Include="..\include\SDL_surface.h" />
+    <ClInclude Include="..\include\SDL_system.h" />
+    <ClInclude Include="..\include\SDL_syswm.h" />
+    <ClInclude Include="..\include\SDL_thread.h" />
+    <ClInclude Include="..\include\SDL_timer.h" />
+    <ClInclude Include="..\include\SDL_touch.h" />
+    <ClInclude Include="..\include\SDL_types.h" />
+    <ClInclude Include="..\include\SDL_version.h" />
+    <ClInclude Include="..\include\SDL_video.h" />
+    <ClInclude Include="..\src\audio\disk\SDL_diskaudio.h" />
+    <ClInclude Include="..\src\audio\dummy\SDL_dummyaudio.h" />
+    <ClInclude Include="..\src\audio\SDL_audiodev_c.h" />
+    <ClInclude Include="..\src\audio\SDL_audio_c.h" />
+    <ClInclude Include="..\src\audio\SDL_sysaudio.h" />
+    <ClInclude Include="..\src\audio\SDL_wave.h" />
+    <ClInclude Include="..\src\audio\wasapi\SDL_wasapi.h" />
+    <ClInclude Include="..\src\core\windows\SDL_directx.h" />
+    <ClInclude Include="..\src\core\windows\SDL_windows.h" />
+    <ClInclude Include="..\src\core\windows\SDL_xinput.h" />
+    <ClInclude Include="..\src\core\winrt\SDL_winrtapp_common.h" />
+    <ClInclude Include="..\src\core\winrt\SDL_winrtapp_direct3d.h" />
+    <ClInclude Include="..\src\core\winrt\SDL_winrtapp_xaml.h" />
+    <ClInclude Include="..\src\dynapi\SDL_dynapi.h" />
+    <ClInclude Include="..\src\dynapi\SDL_dynapi_overrides.h" />
+    <ClInclude Include="..\src\dynapi\SDL_dynapi_procs.h" />
+    <ClInclude Include="..\src\events\blank_cursor.h" />
+    <ClInclude Include="..\src\events\default_cursor.h" />
+    <ClInclude Include="..\src\events\SDL_clipboardevents_c.h" />
+    <ClInclude Include="..\src\events\SDL_displayevents_c.h" />
+    <ClInclude Include="..\src\events\SDL_dropevents_c.h" />
+    <ClInclude Include="..\src\events\SDL_events_c.h" />
+    <ClInclude Include="..\src\events\SDL_keyboard_c.h" />
+    <ClInclude Include="..\src\events\SDL_mouse_c.h" />
+    <ClInclude Include="..\src\events\SDL_touch_c.h" />
+    <ClInclude Include="..\src\events\SDL_windowevents_c.h" />
+    <ClInclude Include="..\src\haptic\SDL_haptic_c.h" />
+    <ClInclude Include="..\src\haptic\SDL_syshaptic.h" />
+    <ClInclude Include="..\src\haptic\windows\SDL_dinputhaptic_c.h" />
+    <ClInclude Include="..\src\haptic\windows\SDL_windowshaptic_c.h" />
+    <ClInclude Include="..\src\haptic\windows\SDL_xinputhaptic_c.h" />
+    <ClInclude Include="..\src\joystick\controller_type.h" />
+    <ClInclude Include="..\src\joystick\SDL_gamecontrollerdb.h" />
+    <ClInclude Include="..\src\joystick\SDL_joystick_c.h" />
+    <ClInclude Include="..\src\joystick\SDL_sysjoystick.h" />
+    <ClInclude Include="..\src\joystick\virtual\SDL_virtualjoystick_c.h" />
+    <ClInclude Include="..\src\joystick\windows\SDL_dinputjoystick_c.h" />
+    <ClInclude Include="..\src\joystick\windows\SDL_windowsjoystick_c.h" />
+    <ClInclude Include="..\src\joystick\windows\SDL_xinputjoystick_c.h" />
+    <ClInclude Include="..\src\locale\SDL_syslocale.h" />
+    <ClInclude Include="..\src\render\direct3d11\SDL_render_winrt.h" />
+    <ClInclude Include="..\src\render\direct3d11\SDL_shaders_d3d11.h" />
+    <ClInclude Include="..\src\render\opengles2\SDL_gles2funcs.h" />
+    <ClInclude Include="..\src\render\opengles2\SDL_shaders_gles2.h" />
+    <ClInclude Include="..\src\render\SDL_d3dmath.h" />
+    <ClInclude Include="..\src\render\SDL_sysrender.h" />
+    <ClInclude Include="..\src\render\SDL_yuv_sw_c.h" />
+    <ClInclude Include="..\src\render\software\SDL_blendfillrect.h" />
+    <ClInclude Include="..\src\render\software\SDL_blendline.h" />
+    <ClInclude Include="..\src\render\software\SDL_blendpoint.h" />
+    <ClInclude Include="..\src\render\software\SDL_draw.h" />
+    <ClInclude Include="..\src\render\software\SDL_drawline.h" />
+    <ClInclude Include="..\src\render\software\SDL_drawpoint.h" />
+    <ClInclude Include="..\src\render\software\SDL_render_sw_c.h" />
+    <ClInclude Include="..\src\render\software\SDL_rotate.h" />
+    <ClInclude Include="..\src\render\software\SDL_triangle.h" />
+    <ClInclude Include="..\src\SDL_assert_c.h" />
+    <ClInclude Include="..\src\SDL_dataqueue.h" />
+    <ClInclude Include="..\src\SDL_error_c.h" />
+    <ClInclude Include="..\src\SDL_fatal.h" />
+    <ClInclude Include="..\src\SDL_hints_c.h" />
+    <ClInclude Include="..\src\SDL_internal.h" />
+    <ClInclude Include="..\src\SDL_list.h" />
+    <ClInclude Include="..\src\SDL_log_c.h" />
+    <ClInclude Include="..\src\sensor\dummy\SDL_dummysensor.h" />
+    <ClInclude Include="..\src\sensor\SDL_sensor_c.h" />
+    <ClInclude Include="..\src\sensor\SDL_syssensor.h" />
+    <ClInclude Include="..\src\thread\SDL_systhread.h" />
+    <ClInclude Include="..\src\thread\SDL_thread_c.h" />
+    <ClInclude Include="..\src\thread\stdcpp\SDL_sysmutex_c.h" />
+    <ClInclude Include="..\src\thread\stdcpp\SDL_systhread_c.h" />
+    <ClInclude Include="..\src\timer\SDL_timer_c.h" />
+    <ClInclude Include="..\src\video\dummy\SDL_nullevents_c.h" />
+    <ClInclude Include="..\src\video\dummy\SDL_nullframebuffer_c.h" />
+    <ClInclude Include="..\src\video\dummy\SDL_nullvideo.h" />
+    <ClInclude Include="..\src\video\SDL_blit.h" />
+    <ClInclude Include="..\src\video\SDL_blit_auto.h" />
+    <ClInclude Include="..\src\video\SDL_blit_copy.h" />
+    <ClInclude Include="..\src\video\SDL_blit_slow.h" />
+    <ClInclude Include="..\src\video\SDL_egl_c.h" />
+    <ClInclude Include="..\src\video\SDL_pixels_c.h" />
+    <ClInclude Include="..\src\video\SDL_rect_c.h" />
+    <ClInclude Include="..\src\video\SDL_RLEaccel_c.h" />
+    <ClInclude Include="..\src\video\SDL_shape_internals.h" />
+    <ClInclude Include="..\src\video\SDL_sysvideo.h" />
+    <ClInclude Include="..\src\video\SDL_yuv_c.h" />
+    <ClInclude Include="..\src\video\winrt\SDL_winrtevents_c.h" />
+    <ClInclude Include="..\src\video\winrt\SDL_winrtgamebar_cpp.h" />
+    <ClInclude Include="..\src\video\winrt\SDL_winrtmessagebox.h" />
+    <ClInclude Include="..\src\video\winrt\SDL_winrtmouse_c.h" />
+    <ClInclude Include="..\src\video\winrt\SDL_winrtopengles.h" />
+    <ClInclude Include="..\src\video\winrt\SDL_winrtvideo_cpp.h" />
+    <ClInclude Include="..\src\video\yuv2rgb\yuv_rgb.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\src\atomic\SDL_atomic.c" />
+    <ClCompile Include="..\src\atomic\SDL_spinlock.c" />
+    <ClCompile Include="..\src\audio\disk\SDL_diskaudio.c" />
+    <ClCompile Include="..\src\audio\dummy\SDL_dummyaudio.c" />
+    <ClCompile Include="..\src\audio\SDL_audio.c" />
+    <ClCompile Include="..\src\audio\SDL_audiocvt.c" />
+    <ClCompile Include="..\src\audio\SDL_audiodev.c" />
+    <ClCompile Include="..\src\audio\SDL_audiotypecvt.c" />
+    <ClCompile Include="..\src\audio\SDL_mixer.c" />
+    <ClCompile Include="..\src\audio\SDL_wave.c" />
+    <ClCompile Include="..\src\audio\wasapi\SDL_wasapi.c" />
+    <ClCompile Include="..\src\audio\wasapi\SDL_wasapi_winrt.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\core\windows\SDL_windows.c" />
+    <ClCompile Include="..\src\core\windows\SDL_xinput.c" />
+    <ClCompile Include="..\src\core\winrt\SDL_winrtapp_common.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\core\winrt\SDL_winrtapp_direct3d.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\core\winrt\SDL_winrtapp_xaml.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\cpuinfo\SDL_cpuinfo.c" />
+    <ClCompile Include="..\src\dynapi\SDL_dynapi.c" />
+    <ClCompile Include="..\src\events\SDL_clipboardevents.c" />
+    <ClCompile Include="..\src\events\SDL_displayevents.c" />
+    <ClCompile Include="..\src\events\SDL_dropevents.c" />
+    <ClCompile Include="..\src\events\SDL_events.c" />
+    <ClCompile Include="..\src\events\SDL_gesture.c" />
+    <ClCompile Include="..\src\events\SDL_keyboard.c" />
+    <ClCompile Include="..\src\events\SDL_mouse.c" />
+    <ClCompile Include="..\src\events\SDL_quit.c" />
+    <ClCompile Include="..\src\events\SDL_touch.c" />
+    <ClCompile Include="..\src\events\SDL_windowevents.c" />
+    <ClCompile Include="..\src\filesystem\winrt\SDL_sysfilesystem.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\file\SDL_rwops.c" />
+    <ClCompile Include="..\src\haptic\dummy\SDL_syshaptic.c" />
+    <ClCompile Include="..\src\haptic\SDL_haptic.c" />
+    <ClCompile Include="..\src\haptic\windows\SDL_dinputhaptic.c" />
+    <ClCompile Include="..\src\haptic\windows\SDL_windowshaptic.c" />
+    <ClCompile Include="..\src\haptic\windows\SDL_xinputhaptic.c" />
+    <ClCompile Include="..\src\hidapi\SDL_hidapi.c" />
+    <ClCompile Include="..\src\joystick\dummy\SDL_sysjoystick.c" />
+    <ClCompile Include="..\src\joystick\controller_type.c" />
+    <ClCompile Include="..\src\joystick\SDL_gamecontroller.c" />
+    <ClCompile Include="..\src\joystick\SDL_joystick.c" />
+    <ClCompile Include="..\src\joystick\virtual\SDL_virtualjoystick.c" />
+    <ClCompile Include="..\src\joystick\windows\SDL_dinputjoystick.c" />
+    <ClCompile Include="..\src\joystick\windows\SDL_windowsjoystick.c" />
+    <ClCompile Include="..\src\joystick\windows\SDL_windows_gaming_input.c" />
+    <ClCompile Include="..\src\joystick\windows\SDL_xinputjoystick.c" />
+    <ClCompile Include="..\src\loadso\windows\SDL_sysloadso.c" />
+    <ClCompile Include="..\src\locale\SDL_locale.c" />
+    <ClCompile Include="..\src\locale\winrt\SDL_syslocale.c" />
+    <ClCompile Include="..\src\misc\SDL_url.c" />
+    <ClCompile Include="..\src\misc\winrt\SDL_sysurl.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\power\SDL_power.c" />
+    <ClCompile Include="..\src\power\winrt\SDL_syspower.cpp" />
+    <ClCompile Include="..\src\render\direct3d11\SDL_render_d3d11.c" />
+    <ClCompile Include="..\src\render\direct3d11\SDL_render_winrt.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\render\direct3d11\SDL_shaders_d3d11.c" />
+    <ClCompile Include="..\src\render\opengles2\SDL_render_gles2.c" />
+    <ClCompile Include="..\src\render\opengles2\SDL_shaders_gles2.c" />
+    <ClCompile Include="..\src\render\SDL_d3dmath.c" />
+    <ClCompile Include="..\src\render\SDL_render.c" />
+    <ClCompile Include="..\src\render\SDL_yuv_sw.c" />
+    <ClCompile Include="..\src\render\software\SDL_blendfillrect.c" />
+    <ClCompile Include="..\src\render\software\SDL_blendline.c" />
+    <ClCompile Include="..\src\render\software\SDL_blendpoint.c" />
+    <ClCompile Include="..\src\render\software\SDL_drawline.c" />
+    <ClCompile Include="..\src\render\software\SDL_drawpoint.c" />
+    <ClCompile Include="..\src\render\software\SDL_render_sw.c" />
+    <ClCompile Include="..\src\render\software\SDL_rotate.c" />
+    <ClCompile Include="..\src\render\software\SDL_triangle.c" />
+    <ClCompile Include="..\src\SDL.c" />
+    <ClCompile Include="..\src\SDL_assert.c" />
+    <ClCompile Include="..\src\SDL_dataqueue.c" />
+    <ClCompile Include="..\src\SDL_list.c" />
+    <ClCompile Include="..\src\SDL_error.c" />
+    <ClCompile Include="..\src\SDL_guid.c" />
+    <ClCompile Include="..\src\SDL_hints.c" />
+    <ClCompile Include="..\src\SDL_log.c" />
+    <ClCompile Include="..\src\SDL_utils.c" />
+    <ClCompile Include="..\src\sensor\dummy\SDL_dummysensor.c" />
+    <ClCompile Include="..\src\sensor\SDL_sensor.c" />
+    <ClCompile Include="..\src\stdlib\SDL_crc16.c" />
+    <ClCompile Include="..\src\stdlib\SDL_crc32.c" />
+    <ClCompile Include="..\src\stdlib\SDL_getenv.c" />
+    <ClCompile Include="..\src\stdlib\SDL_iconv.c" />
+    <ClCompile Include="..\src\stdlib\SDL_malloc.c" />
+    <ClCompile Include="..\src\stdlib\SDL_mslibc.c" />
+    <ClCompile Include="..\src\stdlib\SDL_qsort.c" />
+    <ClCompile Include="..\src\stdlib\SDL_stdlib.c" />
+    <ClCompile Include="..\src\stdlib\SDL_string.c" />
+    <ClCompile Include="..\src\stdlib\SDL_strtokr.c" />
+    <ClCompile Include="..\src\thread\generic\SDL_syssem.c" />
+    <ClCompile Include="..\src\thread\SDL_thread.c" />
+    <ClCompile Include="..\src\thread\stdcpp\SDL_syscond.cpp" />
+    <ClCompile Include="..\src\thread\stdcpp\SDL_sysmutex.cpp" />
+    <ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp" />
+    <ClCompile Include="..\src\timer\SDL_timer.c" />
+    <ClCompile Include="..\src\timer\windows\SDL_systimer.c" />
+    <ClCompile Include="..\src\video\dummy\SDL_nullevents.c" />
+    <ClCompile Include="..\src\video\dummy\SDL_nullframebuffer.c" />
+    <ClCompile Include="..\src\video\dummy\SDL_nullvideo.c" />
+    <ClCompile Include="..\src\video\SDL_blit.c" />
+    <ClCompile Include="..\src\video\SDL_blit_0.c" />
+    <ClCompile Include="..\src\video\SDL_blit_1.c" />
+    <ClCompile Include="..\src\video\SDL_blit_A.c" />
+    <ClCompile Include="..\src\video\SDL_blit_auto.c" />
+    <ClCompile Include="..\src\video\SDL_blit_copy.c" />
+    <ClCompile Include="..\src\video\SDL_blit_N.c" />
+    <ClCompile Include="..\src\video\SDL_blit_slow.c" />
+    <ClCompile Include="..\src\video\SDL_bmp.c" />
+    <ClCompile Include="..\src\video\SDL_clipboard.c" />
+    <ClCompile Include="..\src\video\SDL_egl.c" />
+    <ClCompile Include="..\src\video\SDL_fillrect.c" />
+    <ClCompile Include="..\src\video\SDL_pixels.c" />
+    <ClCompile Include="..\src\video\SDL_rect.c" />
+    <ClCompile Include="..\src\video\SDL_RLEaccel.c" />
+    <ClCompile Include="..\src\video\SDL_shape.c" />
+    <ClCompile Include="..\src\video\SDL_stretch.c" />
+    <ClCompile Include="..\src\video\SDL_surface.c" />
+    <ClCompile Include="..\src\video\SDL_video.c" />
+    <ClCompile Include="..\src\video\SDL_yuv.c" />
+    <ClCompile Include="..\src\video\winrt\SDL_winrtevents.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtgamebar.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtkeyboard.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtmessagebox.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtmouse.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtopengles.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtpointerinput.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtvideo.cpp">
+      <CompileAsWinRT>true</CompileAsWinRT>
+    </ClCompile>
+    <ClCompile Include="..\src\video\yuv2rgb\yuv_rgb.c" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{89e9b32e-a86a-47c3-a948-d2b1622925ce}</ProjectGuid>
+    <Keyword>DynamicLibrary</Keyword>
+    <ProjectName>SDL3-UWP</ProjectName>
+    <RootNamespace>SDL3</RootNamespace>
+    <DefaultLanguage>en-US</DefaultLanguage>
+    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
+    <AppContainerApplication>true</AppContainerApplication>
+    <ApplicationType>Windows Store</ApplicationType>
+    <ApplicationTypeRevision>8.2</ApplicationTypeRevision>
+    <TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
+    <TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <GenerateManifest>false</GenerateManifest>
+    <IgnoreImportLibrary>false</IgnoreImportLibrary>
+    <TargetName>SDL3</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <CompileAsWinRT>false</CompileAsWinRT>
+      <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>DLL_EXPORT;_CRT_SECURE_NO_WARNINGS;SDL_BUILDING_WINRT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+      <AdditionalOptions>/nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 849 - 0
VisualC-WinRT/SDL-UWP.vcxproj.filters

@@ -0,0 +1,849 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{fa0ff2df-c3d6-498a-96f1-1f88e7ce0da3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{68e1b30b-19ed-4612-93e4-6260c5a979e5}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\include\begin_code.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\close_code.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_assert.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_atomic.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_audio.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_blendmode.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_clipboard.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_config.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_config_minimal.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_config_winrt.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_copying.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_cpuinfo.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_egl.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_endian.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_error.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_events.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_filesystem.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_guid.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_haptic.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_hints.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_hidapi.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_input.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_joystick.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_keyboard.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_keycode.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_loadso.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_locale.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_log.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_main.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_mouse.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_mutex.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_name.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_opengles2.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_pixels.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_platform.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_power.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_quit.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_rect.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_render.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_revision.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_rwops.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_scancode.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_shape.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_stdinc.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_surface.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_system.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_syswm.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_thread.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_timer.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_touch.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_types.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_version.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_video.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\SDL_gamecontrollerdb.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\disk\SDL_diskaudio.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\dummy\SDL_dummyaudio.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\SDL_audiodev_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\SDL_audio_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\SDL_sysaudio.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\SDL_wave.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\core\windows\SDL_directx.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\core\windows\SDL_windows.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\core\windows\SDL_xinput.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\core\winrt\SDL_winrtapp_common.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\core\winrt\SDL_winrtapp_direct3d.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\core\winrt\SDL_winrtapp_xaml.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\dynapi\SDL_dynapi.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\dynapi\SDL_dynapi_overrides.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\dynapi\SDL_dynapi_procs.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\blank_cursor.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\default_cursor.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_clipboardevents_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_dropevents_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_events_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_keyboard_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_mouse_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_touch_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_windowevents_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\haptic\SDL_haptic_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\haptic\SDL_syshaptic.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\SDL_joystick_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\SDL_sysjoystick.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\virtual\SDL_virtualjoystick_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\windows\SDL_dinputjoystick_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\windows\SDL_windowsjoystick_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\joystick\windows\SDL_xinputjoystick_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\direct3d11\SDL_render_winrt.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\opengles2\SDL_gles2funcs.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\opengles2\SDL_shaders_gles2.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\SDL_d3dmath.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\SDL_sysrender.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\SDL_yuv_sw_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_blendfillrect.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_blendline.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_blendpoint.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_draw.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_drawline.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_drawpoint.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_render_sw_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_rotate.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\software\SDL_triangle.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_assert_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_error_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_fatal.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_hints_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_internal.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_log_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\locale\SDL_syslocale.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\thread\SDL_systhread.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\thread\SDL_thread_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\thread\stdcpp\SDL_sysmutex_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\thread\stdcpp\SDL_systhread_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\timer\SDL_timer_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\dummy\SDL_nullevents_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\dummy\SDL_nullframebuffer_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\dummy\SDL_nullvideo.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_blit.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_blit_auto.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_blit_copy.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_blit_slow.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_egl_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_pixels_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_rect_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_RLEaccel_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_shape_internals.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_sysvideo.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\winrt\SDL_winrtevents_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\winrt\SDL_winrtmessagebox.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\winrt\SDL_winrtmouse_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\winrt\SDL_winrtopengles.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\winrt\SDL_winrtvideo_cpp.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\audio\wasapi\SDL_wasapi.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\winrt\SDL_winrtgamebar_cpp.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_dataqueue.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\SDL_list.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\haptic\windows\SDL_xinputhaptic_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\haptic\windows\SDL_dinputhaptic_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\haptic\windows\SDL_windowshaptic_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\SDL_yuv_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\video\yuv2rgb\yuv_rgb.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\render\direct3d11\SDL_shaders_d3d11.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_sensor.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\sensor\SDL_sensor_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\sensor\SDL_syssensor.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\sensor\dummy\SDL_dummysensor.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\src\events\SDL_displayevents_c.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\include\SDL_misc.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClCompile Include="..\src\atomic\SDL_atomic.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\atomic\SDL_spinlock.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\disk\SDL_diskaudio.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\dummy\SDL_dummyaudio.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\SDL_audio.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\SDL_audiocvt.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\SDL_audiodev.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\SDL_audiotypecvt.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\SDL_mixer.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\SDL_wave.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\wasapi\SDL_wasapi_winrt.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\core\windows\SDL_windows.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\core\windows\SDL_xinput.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\core\winrt\SDL_winrtapp_common.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\core\winrt\SDL_winrtapp_direct3d.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\core\winrt\SDL_winrtapp_xaml.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\cpuinfo\SDL_cpuinfo.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\dynapi\SDL_dynapi.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_clipboardevents.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_dropevents.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_events.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_gesture.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_keyboard.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_mouse.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_quit.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_touch.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_windowevents.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\filesystem\winrt\SDL_sysfilesystem.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\file\SDL_rwops.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\haptic\dummy\SDL_syshaptic.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\haptic\SDL_haptic.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\hidapi\SDL_hidapi.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\dummy\SDL_sysjoystick.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\SDL_gamecontroller.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\SDL_joystick.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\virtual\SDL_virtualjoystick.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\windows\SDL_dinputjoystick.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\windows\SDL_windowsjoystick.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\windows\SDL_xinputjoystick.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\loadso\windows\SDL_sysloadso.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\power\SDL_power.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\power\winrt\SDL_syspower.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\direct3d11\SDL_render_d3d11.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\direct3d11\SDL_render_winrt.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\opengles2\SDL_render_gles2.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\opengles2\SDL_shaders_gles2.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\SDL_d3dmath.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\SDL_render.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\SDL_yuv_sw.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_blendfillrect.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_blendline.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_blendpoint.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_drawline.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_drawpoint.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_render_sw.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_rotate.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\software\SDL_triangle.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_assert.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_error.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_guid.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_hints.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_log.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\locale\SDL_locale.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\locale\winrt\SDL_syslocale.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_crc16.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_crc32.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_getenv.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_iconv.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_malloc.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_qsort.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_stdlib.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_string.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_strtokr.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\thread\generic\SDL_syssem.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\thread\SDL_thread.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\thread\stdcpp\SDL_syscond.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\thread\stdcpp\SDL_sysmutex.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\thread\stdcpp\SDL_systhread.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\timer\SDL_timer.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\timer\windows\SDL_systimer.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\dummy\SDL_nullevents.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\dummy\SDL_nullframebuffer.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\dummy\SDL_nullvideo.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_0.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_1.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_A.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_auto.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_copy.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_N.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_blit_slow.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_bmp.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_clipboard.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_egl.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_fillrect.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_pixels.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_rect.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_RLEaccel.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_shape.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_stretch.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_surface.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_video.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtevents.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtkeyboard.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtmessagebox.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtmouse.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtopengles.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtpointerinput.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtvideo.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\audio\wasapi\SDL_wasapi.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\winrt\SDL_winrtgamebar.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_dataqueue.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_list.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\SDL_utils.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\haptic\windows\SDL_dinputhaptic.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\haptic\windows\SDL_windowshaptic.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\haptic\windows\SDL_xinputhaptic.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\SDL_yuv.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\video\yuv2rgb\yuv_rgb.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\render\direct3d11\SDL_shaders_d3d11.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\sensor\SDL_sensor.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\sensor\dummy\SDL_dummysensor.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\events\SDL_displayevents.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\misc\winrt\SDL_sysurl.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\misc\SDL_url.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClInclude Include="..\src\joystick\controller_type.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\src\joystick\windows\SDL_windows_gaming_input.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\joystick\controller_type.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\src\stdlib\SDL_mslibc.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 1 - 0
VisualC/SDL/SDL.vcxproj

@@ -452,6 +452,7 @@
     <ClCompile Include="..\..\src\audio\SDL_mixer.c" />
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
+    <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />

+ 3 - 0
VisualC/SDL/SDL.vcxproj.filters

@@ -1012,6 +1012,9 @@
     <ClCompile Include="..\..\src\audio\dummy\SDL_dummyaudio.c">
       <Filter>audio\dummy</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c">
+      <Filter>audio\wasapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c">
       <Filter>audio\wasapi</Filter>
     </ClCompile>

+ 6 - 0
build-scripts/fnsince.pl

@@ -88,6 +88,12 @@ foreach my $release (@releases) {
     close(PIPEFH);
 }
 
+# these are incorrect in the dynapi header, because we forgot to add them
+#  until a later release, but are available in the older release.
+$funcs{'SDL_WinRTGetFSPathUNICODE'} = '2.0.3';
+$funcs{'SDL_WinRTGetFSPathUTF8'} = '2.0.3';
+$funcs{'SDL_WinRTRunApp'} = '2.0.3';
+
 if (not defined $wikipath) {
     foreach my $release (@releases) {
         foreach my $fn (sort keys %funcs) {

+ 2 - 2
cmake/test/CMakeLists.txt

@@ -29,7 +29,7 @@ add_feature_info("TEST_STATIC" TEST_STATIC "Test linking with static library")
 
 if(TEST_SHARED)
     find_package(SDL3 REQUIRED CONFIG COMPONENTS SDL3)
-    if(EMSCRIPTEN OR WIN32)
+    if(EMSCRIPTEN OR (WIN32 AND NOT WINDOWS_STORE))
         find_package(SDL3 REQUIRED CONFIG COMPONENTS SDL3main)
     endif()
     add_executable(gui-shared WIN32 main_gui.c)
@@ -79,7 +79,7 @@ endif()
 
 if(TEST_STATIC)
     find_package(SDL3 REQUIRED CONFIG COMPONENTS SDL3-static)
-    if(EMSCRIPTEN OR WIN32)
+    if(EMSCRIPTEN OR (WIN32 AND NOT WINDOWS_STORE))
         find_package(SDL3 REQUIRED CONFIG COMPONENTS SDL3main)
     endif()
     add_executable(gui-static WIN32 main_gui.c)

+ 519 - 0
docs/README-winrt.md

@@ -0,0 +1,519 @@
+WinRT
+=====
+
+This port allows SDL applications to run on Microsoft's platforms that require
+use of "Windows Runtime", aka. "WinRT", APIs.  Microsoft may, in some cases,
+refer to them as either "Windows Store", or for Windows 10, "UWP" apps.
+
+In the past, SDL has supported Windows RT 8.x, Windows Phone, etc, but in
+modern times this port is focused on UWP apps, which run on Windows 10,
+and modern Xbox consoles.
+
+
+Requirements
+------------
+
+* Microsoft Visual C++ (aka Visual Studio) 2019.
+  - Free, "Community" or "Express" editions may be used, so long as they
+    include support for either "Windows Store" or "Windows Phone" apps.
+    "Express" versions marked as supporting "Windows Desktop" development
+    typically do not include support for creating WinRT apps, to note.
+    (The "Community" editions of Visual C++ do, however, support both
+    desktop/Win32 and WinRT development).
+* A valid Microsoft account - This requirement is not imposed by SDL, but
+  rather by Microsoft's Visual C++ toolchain.  This is required to launch or 
+  debug apps.
+
+
+Status
+------
+
+Here is a rough list of what works, and what doesn't:
+
+* What works:
+  * compilation via Visual C++ 2019.
+  * compile-time platform detection for SDL programs.  The C/C++ #define,
+    `__WINRT__`, will be set to 1 (by SDL) when compiling for WinRT.
+  * GPU-accelerated 2D rendering, via SDL_Renderer.
+  * OpenGL ES 2, via the ANGLE library (included separately from SDL)
+  * software rendering, via either SDL_Surface (optionally in conjunction with
+    SDL_GetWindowSurface() and SDL_UpdateWindowSurface()) or via the
+    SDL_Renderer APIs
+  * threads
+  * timers (via SDL_GetTicks(), SDL_AddTimer(), SDL_GetPerformanceCounter(),
+    SDL_GetPerformanceFrequency(), etc.)
+  * file I/O via SDL_RWops
+  * mouse input  (unsupported on Windows Phone)
+  * audio, via SDL's WASAPI backend (if you want to record, your app must 
+    have "Microphone" capabilities enabled in its manifest, and the user must 
+    not have blocked access. Otherwise, capture devices will fail to work,
+    presenting as a device disconnect shortly after opening it.)
+  * .DLL file loading.  Libraries *MUST* be packaged inside applications.  Loading
+    anything outside of the app is not supported.
+  * system path retrieval via SDL's filesystem APIs
+  * game controllers.  Support is provided via the SDL_Joystick and
+    SDL_GameController APIs, and is backed by Microsoft's XInput API.  Please
+    note, however, that Windows limits game-controller support in UWP apps to,
+    "Xbox compatible controllers" (many controllers that work in Win32 apps,
+    do not work in UWP, due to restrictions in UWP itself.) 
+  * multi-touch input
+  * app events.  SDL_APP_WILLENTER* and SDL_APP_DIDENTER* events get sent out as
+    appropriate.
+  * window events
+  * using Direct3D 11.x APIs outside of SDL.  Non-XAML / Direct3D-only apps can
+    choose to render content directly via Direct3D, using SDL to manage the
+    internal WinRT window, as well as input and audio.  (Use
+    SDL_GetWindowWMInfo() to get the WinRT 'CoreWindow', and pass it into
+    IDXGIFactory2::CreateSwapChainForCoreWindow() as appropriate.)
+
+* What partially works:
+  * keyboard input.  Most of WinRT's documented virtual keys are supported, as
+    well as many keys with documented hardware scancodes.  Converting
+    SDL_Scancodes to or from SDL_Keycodes may not work, due to missing APIs
+    (MapVirtualKey()) in Microsoft's Windows Store / UWP APIs.
+  * SDLmain.  WinRT uses a different signature for each app's main() function.
+    SDL-based apps that use this port must compile in SDL_winrt_main_NonXAML.cpp
+    (in `SDL\src\main\winrt\`) directly in order for their C-style main()
+    functions to be called.
+
+* What doesn't work:
+  * compilation with anything other than Visual C++
+  * programmatically-created custom cursors.  These don't appear to be supported
+    by WinRT.  Different OS-provided cursors can, however, be created via
+    SDL_CreateSystemCursor() (unsupported on Windows Phone)
+  * SDL_WarpMouseInWindow() or SDL_WarpMouseGlobal().  This are not currently
+    supported by WinRT itself.
+  * joysticks and game controllers that either are not supported by
+    Microsoft's XInput API, or are not supported within UWP apps (many
+    controllers that work in Win32, do not work in UWP, due to restrictions in
+    UWP itself).
+  * turning off VSync when rendering on Windows Phone.  Attempts to turn VSync
+    off on Windows Phone result either in Direct3D not drawing anything, or it
+    forcing VSync back on.  As such, SDL_RENDERER_PRESENTVSYNC will always get
+    turned-on on Windows Phone.  This limitation is not present in non-Phone
+    WinRT (such as Windows 8.x), where turning off VSync appears to work.
+  * probably anything else that's not listed as supported
+
+
+
+Upgrade Notes
+-------------
+
+#### SDL_GetPrefPath() usage when upgrading WinRT apps from SDL 2.0.3
+
+SDL 2.0.4 fixes two bugs found in the WinRT version of SDL_GetPrefPath().
+The fixes may affect older, SDL 2.0.3-based apps' save data.  Please note
+that these changes only apply to SDL-based WinRT apps, and not to apps for
+any other platform.
+
+1. SDL_GetPrefPath() would return an invalid path, one in which the path's
+   directory had not been created.  Attempts to create files there
+   (via fopen(), for example), would fail, unless that directory was
+   explicitly created beforehand.
+
+2. SDL_GetPrefPath(), for non-WinPhone-based apps, would return a path inside
+   a WinRT 'Roaming' folder, the contents of which get automatically
+   synchronized across multiple devices.  This process can occur while an
+   application runs, and can cause existing save-data to be overwritten
+   at unexpected times, with data from other devices.  (Windows Phone apps
+   written with SDL 2.0.3 did not utilize a Roaming folder, due to API
+   restrictions in Windows Phone 8.0).
+
+
+SDL_GetPrefPath(), starting with SDL 2.0.4, addresses these by:
+
+1. making sure that SDL_GetPrefPath() returns a directory in which data
+   can be written to immediately, without first needing to create directories.
+
+2. basing SDL_GetPrefPath() off of a different, non-Roaming folder, the
+   contents of which do not automatically get synchronized across devices
+   (and which require less work to use safely, in terms of data integrity).
+
+Apps that wish to get their Roaming folder's path can do so either by using
+SDL_WinRTGetFSPathUTF8(), SDL_WinRTGetFSPathUNICODE() (which returns a
+UCS-2/wide-char string), or directly through the WinRT class,
+Windows.Storage.ApplicationData.
+
+
+
+Setup, High-Level Steps
+-----------------------
+
+The steps for setting up a project for an SDL/WinRT app looks like the
+following, at a high-level:
+
+1. create a new Visual C++ project using Microsoft's template for a,
+   "Direct3D App".
+2. remove most of the files from the project.
+3. make your app's project directly reference SDL/WinRT's own Visual C++
+   project file, via use of Visual C++'s "References" dialog.  This will setup
+   the linker, and will copy SDL's .dll files to your app's final output.
+4. adjust your app's build settings, at minimum, telling it where to find SDL's
+   header files.
+5. add files that contains a WinRT-appropriate main function, along with some
+   data to make sure mouse-cursor-hiding (via SDL_ShowCursor(SDL_DISABLE) calls)
+   work properly.
+6. add SDL-specific app code.
+7. build and run your app.
+
+
+Setup, Detailed Steps
+---------------------
+
+### 1. Create a new project ###
+
+Create a new project using one of Visual C++'s templates for a plain, non-XAML,
+"Direct3D App" (XAML support for SDL/WinRT is not yet ready for use).  If you
+don't see one of these templates, in Visual C++'s 'New Project' dialog, try
+using the textbox titled, 'Search Installed Templates' to look for one.
+
+
+### 2. Remove unneeded files from the project ###
+
+In the new project, delete any file that has one of the following extensions:
+
+- .cpp
+- .h
+- .hlsl
+
+When you are done, you should be left with a few files, each of which will be a
+necessary part of your app's project.  These files will consist of:
+
+- an .appxmanifest file, which contains metadata on your WinRT app.  This is
+  similar to an Info.plist file on iOS, or an AndroidManifest.xml on Android.
+- a few .png files, one of which is a splash screen (displayed when your app
+  launches), others are app icons.
+- a .pfx file, used for code signing purposes.
+
+
+### 3. Add references to SDL's project files ###
+
+SDL/WinRT can be built in multiple variations, spanning across three different
+CPU architectures (x86, x64, and ARM) and two different configurations
+(Debug and Release).  WinRT and Visual C++ do not currently provide a means
+for combining multiple variations of one library into a single file.
+Furthermore, it does not provide an easy means for copying pre-built .dll files
+into your app's final output (via Post-Build steps, for example).  It does,
+however, provide a system whereby an app can reference the MSVC projects of
+libraries such that, when the app is built:
+
+1. each library gets built for the appropriate CPU architecture(s) and WinRT
+   platform(s).
+2. each library's output, such as .dll files, get copied to the app's build 
+   output.
+
+To set this up for SDL/WinRT, you'll need to run through the following steps:
+
+1. open up the Solution Explorer inside Visual C++ (under the "View" menu, then
+   "Solution Explorer")
+2. right click on your app's solution.
+3. navigate to "Add", then to "Existing Project..."
+4. find SDL/WinRT's Visual C++ project file and open it, in the `VisualC-WinRT`
+   directory.
+5. once the project has been added, right-click on your app's project and
+   select, "References..."
+6. click on the button titled, "Add New Reference..."
+7. check the box next to SDL
+8. click OK to close the dialog
+9. SDL will now show up in the list of references.  Click OK to close that
+   dialog.
+
+Your project is now linked to SDL's project, insofar that when the app is
+built, SDL will be built as well, with its build output getting included with
+your app.
+
+
+### 4. Adjust Your App's Build Settings ###
+
+Some build settings need to be changed in your app's project.  This guide will
+outline the following:
+
+- making sure that the compiler knows where to find SDL's header files
+- **Optional for C++, but NECESSARY for compiling C code:** telling the
+  compiler not to use Microsoft's C++ extensions for WinRT development.
+- **Optional:** telling the compiler not generate errors due to missing
+  precompiled header files.
+
+To change these settings:
+
+1. right-click on the project
+2. choose "Properties"
+3. in the drop-down box next to "Configuration", choose, "All Configurations"
+4. in the drop-down box next to "Platform", choose, "All Platforms"
+5. in the left-hand list, expand the "C/C++" section
+6. select "General"
+7. edit the "Additional Include Directories" setting, and add a path to SDL's
+   "include" directory
+8. **Optional: to enable compilation of C code:** change the setting for
+   "Consume Windows Runtime Extension" from "Yes (/ZW)" to "No".  If you're 
+   working with a completely C++ based project, this step can usually be 
+   omitted.
+9. **Optional: to disable precompiled headers (which can produce 
+   'stdafx.h'-related build errors, if setup incorrectly:** in the left-hand 
+   list, select "Precompiled Headers", then change the setting for "Precompiled 
+   Header" from "Use (/Yu)" to "Not Using Precompiled Headers".
+10. close the dialog, saving settings, by clicking the "OK" button
+
+
+### 5. Add a WinRT-appropriate main function, and a blank-cursor image, to the app. ###
+
+A few files should be included directly in your app's MSVC project, specifically:
+1. a WinRT-appropriate main function (which is different than main() functions on
+   other platforms)
+2. a Win32-style cursor resource, used by SDL_ShowCursor() to hide the mouse cursor
+   (if and when the app needs to do so).  *If this cursor resource is not
+   included, mouse-position reporting may fail if and when the cursor is
+   hidden, due to possible bugs/design-oddities in Windows itself.*
+
+To include these files for C/C++ projects:
+
+1. right-click on your project (again, in Visual C++'s Solution Explorer), 
+   navigate to "Add", then choose "Existing Item...".
+2. navigate to the directory containing SDL's source code, then into its
+   subdirectory, 'src/main/winrt/'.  Select, then add, the following files:
+   - `SDL_winrt_main_NonXAML.cpp`
+   - `SDL3-WinRTResources.rc`
+   - `SDL3-WinRTResource_BlankCursor.cur`
+3. right-click on the file `SDL_winrt_main_NonXAML.cpp` (as listed in your
+   project), then click on "Properties...".
+4. in the drop-down box next to "Configuration", choose, "All Configurations"
+5. in the drop-down box next to "Platform", choose, "All Platforms"
+6. in the left-hand list, click on "C/C++"
+7. change the setting for "Consume Windows Runtime Extension" to "Yes (/ZW)".
+8. click the OK button.  This will close the dialog.
+
+**NOTE: C++/CX compilation is currently required in at least one file of your 
+app's project.  This is to make sure that Visual C++'s linker builds a 'Windows 
+Metadata' file (.winmd) for your app.  Not doing so can lead to build errors.**
+
+For non-C++ projects, you will need to call SDL_WinRTRunApp from your language's
+main function, and generate SDL3-WinRTResources.res manually by using `rc` via
+the Developer Command Prompt and including it as a <Win32Resource> within the
+first <PropertyGroup> block in your Visual Studio project file.
+
+### 6. Add app code and assets ###
+
+At this point, you can add in SDL-specific source code.  Be sure to include a 
+C-style main function (ie: `int main(int argc, char *argv[])`).  From there you 
+should be able to create a single `SDL_Window` (WinRT apps can only have one 
+window, at present), as well as an `SDL_Renderer`.  Direct3D will be used to 
+draw content.  Events are received via SDL's usual event functions 
+(`SDL_PollEvent`, etc.)  If you have a set of existing source files and assets, 
+you can start adding them to the project now.  If not, or if you would like to 
+make sure that you're setup correctly, some short and simple sample code is 
+provided below.
+
+
+#### 6.A. ... when creating a new app ####
+
+If you are creating a new app (rather than porting an existing SDL-based app), 
+or if you would just like a simple app to test SDL/WinRT with before trying to 
+get existing code working, some working SDL/WinRT code is provided below.  To 
+set this up:
+
+1. right click on your app's project
+2. select Add, then New Item.  An "Add New Item" dialog will show up.
+3. from the left-hand list, choose "Visual C++"
+4. from the middle/main list, choose "C++ File (.cpp)"
+5. near the bottom of the dialog, next to "Name:", type in a name for your 
+source file, such as, "main.cpp".
+6. click on the Add button.  This will close the dialog, add the new file to 
+your project, and open the file in Visual C++'s text editor.
+7. Copy and paste the following code into the new file, then save it.
+
+```c
+#include <SDL.h>
+    
+int main(int argc, char **argv)
+{
+    SDL_DisplayMode mode;
+    SDL_Window * window = NULL;
+    SDL_Renderer * renderer = NULL;
+    SDL_Event evt;
+    SDL_bool keep_going = SDL_TRUE;
+  
+    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+        return 1;
+    } else if (SDL_GetCurrentDisplayMode(0, &mode) != 0) {
+        return 1;
+    } else if (SDL_CreateWindowAndRenderer(mode.w, mode.h, SDL_WINDOW_FULLSCREEN, &window, &renderer) != 0) {
+        return 1;
+    }
+    
+    while (keep_going) {
+        while (SDL_PollEvent(&evt)) {
+            if ((evt.type == SDL_KEYDOWN) && (evt.key.keysym.sym == SDLK_ESCAPE)) {
+                keep_going = SDL_FALSE;
+            } 
+        }
+    
+        SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
+        SDL_RenderClear(renderer);
+        SDL_RenderPresent(renderer);
+    }
+
+    SDL_Quit();
+    return 0;
+}
+```
+
+#### 6.B. Adding code and assets ####
+
+If you have existing code and assets that you'd like to add, you should be able 
+to add them now.  The process for adding a set of files is as such.
+
+1. right click on the app's project
+2. select Add, then click on "New Item..."
+3. open any source, header, or asset files as appropriate.  Support for C and 
+C++ is available.
+
+Do note that WinRT only supports a subset of the APIs that are available to 
+Win32-based apps.  Many portions of the Win32 API and the C runtime are not 
+available.
+
+A list of unsupported C APIs can be found at 
+<http://msdn.microsoft.com/en-us/library/windows/apps/jj606124.aspx>
+
+General information on using the C runtime in WinRT can be found at 
+<https://msdn.microsoft.com/en-us/library/hh972425.aspx>
+
+A list of supported Win32 APIs for WinRT apps can be found at 
+<http://msdn.microsoft.com/en-us/library/windows/apps/br205757.aspx>.  To note, 
+the list of supported Win32 APIs for Windows Phone 8.0 is different.  
+That list can be found at 
+<http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj662956(v=vs.105).aspx>
+
+
+### 7. Build and run your app ###
+
+Your app project should now be setup, and you should be ready to build your app.  
+To run it on the local machine, open the Debug menu and choose "Start 
+Debugging".  This will build your app, then run your app full-screen.  To switch 
+out of your app, press the Windows key.  Alternatively, you can choose to run 
+your app in a window.  To do this, before building and running your app, find 
+the drop-down menu in Visual C++'s toolbar that says, "Local Machine".  Expand 
+this by clicking on the arrow on the right side of the list, then click on 
+Simulator.  Once you do that, any time you build and run the app, the app will 
+launch in window, rather than full-screen.
+
+
+#### 7.A. Running apps on older, ARM-based, "Windows RT" devices ####
+
+**These instructions do not include Windows Phone, despite Windows Phone
+typically running on ARM processors.**  They are specifically for devices
+that use the "Windows RT" operating system, which was a modified version of
+Windows 8.x that ran primarily on ARM-based tablet computers.
+
+To build and run the app on ARM-based, "Windows RT" devices, you'll need to:
+
+- install Microsoft's "Remote Debugger" on the device.  Visual C++ installs and 
+  debugs ARM-based apps via IP networks.
+- change a few options on the development machine, both to make sure it builds 
+  for ARM (rather than x86 or x64), and to make sure it knows how to find the 
+  Windows RT device (on the network).
+
+Microsoft's Remote Debugger can be found at 
+<https://msdn.microsoft.com/en-us/library/hh441469.aspx>.  Please note 
+that separate versions of this debugger exist for different versions of Visual 
+C++, one each for MSVC 2015, 2013, and 2012.
+
+To setup Visual C++ to launch your app on an ARM device:
+
+1. make sure the Remote Debugger is running on your ARM device, and that it's on 
+   the same IP network as your development machine.
+2. from Visual C++'s toolbar, find a drop-down menu that says, "Win32".  Click 
+   it, then change the value to "ARM".
+3. make sure Visual C++ knows the hostname or IP address of the ARM device.  To 
+   do this:
+    1. open the app project's properties
+    2. select "Debugging"
+    3. next to "Machine Name", enter the hostname or IP address of the ARM 
+       device
+    4. if, and only if, you've turned off authentication in the Remote Debugger,
+       then change the setting for "Require Authentication" to No
+    5. click "OK"
+4. build and run the app (from Visual C++).  The first time you do this, a 
+   prompt will show up on the ARM device, asking for a Microsoft Account.  You 
+   do, unfortunately, need to log in here, and will need to follow the 
+   subsequent registration steps in order to launch the app.  After you do so, 
+   if the app didn't already launch, try relaunching it again from within Visual 
+   C++.
+
+
+Troubleshooting
+---------------
+
+#### Build fails with message, "error LNK2038: mismatch detected for 'vccorlib_lib_should_be_specified_before_msvcrt_lib_to_linker'"
+
+Try adding the following to your linker flags.  In MSVC, this can be done by
+right-clicking on the app project, navigating to Configuration Properties ->
+Linker -> Command Line, then adding them to the Additional Options
+section.
+
+* For Release builds / MSVC-Configurations, add:
+
+    /nodefaultlib:vccorlib /nodefaultlib:msvcrt vccorlib.lib msvcrt.lib
+
+* For Debug builds / MSVC-Configurations, add:
+
+    /nodefaultlib:vccorlibd /nodefaultlib:msvcrtd vccorlibd.lib msvcrtd.lib
+
+
+#### Mouse-motion events fail to get sent, or SDL_GetMouseState() fails to return updated values
+
+This may be caused by a bug in Windows itself, whereby hiding the mouse
+cursor can cause mouse-position reporting to fail.
+
+SDL provides a workaround for this, but it requires that an app links to a
+set of Win32-style cursor image-resource files.  A copy of suitable resource
+files can be found in `src/main/winrt/`.  Adding them to an app's Visual C++
+project file should be sufficient to get the app to use them.
+
+
+#### SDL's Visual Studio project file fails to open, with message, "The system can't find the file specified."
+
+This can be caused for any one of a few reasons, which Visual Studio can
+report, but won't always do so in an up-front manner.
+
+To help determine why this error comes up:
+
+1. open a copy of Visual Studio without opening a project file.  This can be
+   accomplished via Windows' Start Menu, among other means.
+2. show Visual Studio's Output window.  This can be done by going to VS'
+   menu bar, then to View, and then to Output.
+3. try opening the SDL project file directly by going to VS' menu bar, then
+   to File, then to Open, then to Project/Solution.  When a File-Open dialog
+   appears, open the SDL project (such as the one in SDL's source code, in its
+   directory, VisualC-WinRT/UWP_VS2015/).
+4. after attempting to open SDL's Visual Studio project file, additional error
+   information will be output to the Output window.
+
+If Visual Studio reports (via its Output window) that the project:
+
+"could not be loaded because it's missing install components. To fix this launch Visual Studio setup with the following selections:
+Microsoft.VisualStudio.ComponentGroup.UWP.VC"
+
+... then you will need to re-launch Visual Studio's installer, and make sure that
+the workflow for "Universal Windows Platform development" is checked, and that its
+optional component, "C++ Universal Windows Platform tools" is also checked.  While
+you are there, if you are planning on targeting UWP / Windows 10, also make sure
+that you check the optional component, "Windows 10 SDK (10.0.10240.0)".  After
+making sure these items are checked as-appropriate, install them.
+
+Once you install these components, try re-launching Visual Studio, and re-opening
+the SDL project file.  If you still get the error dialog, try using the Output
+window, again, seeing what Visual Studio says about it.
+
+
+#### Game controllers / joysticks aren't working!
+
+Windows only permits certain game controllers and joysticks to work within
+WinRT / UWP apps.  Even if a game controller or joystick works in a Win32
+app, that device is not guaranteed to work inside a WinRT / UWP app.
+
+According to Microsoft, "Xbox compatible controllers" should work inside
+UWP apps, potentially with more working in the future.  This includes, but
+may not be limited to, Microsoft-made Xbox controllers and USB adapters.
+(Source: https://social.msdn.microsoft.com/Forums/en-US/9064838b-e8c3-4c18-8a83-19bf0dfe150d/xinput-fails-to-detect-game-controllers?forum=wpdevelop)
+
+

+ 1 - 0
docs/README.md

@@ -41,6 +41,7 @@ More documentation and FAQs are available online at [the wiki](http://wiki.libsd
 - [Touch](README-touch.md)
 - [Versions](README-versions.md)
 - [Windows](README-windows.md)
+- [WinRT](README-winrt.md)
 - [PSVita](README-vita.md)
 - [Nokia N-Gage](README-ngage.md)
 

+ 2 - 0
include/SDL_config.h

@@ -31,6 +31,8 @@
 /* Add any platform that doesn't build using the configure system. */
 #if defined(__WIN32__)
 #include "SDL_config_windows.h"
+#elif defined(__WINRT__)
+#include "SDL_config_winrt.h"
 #elif defined(__WINGDK__)
 #include "SDL_config_wingdk.h"
 #elif defined(__XBOXONE__) || defined(__XBOXSERIES__)

+ 2 - 0
include/SDL_config.h.cmake

@@ -390,6 +390,7 @@
 #cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
 #cmakedefine SDL_VIDEO_DRIVER_OFFSCREEN @SDL_VIDEO_DRIVER_OFFSCREEN@
 #cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
+#cmakedefine SDL_VIDEO_DRIVER_WINRT @SDL_VIDEO_DRIVER_WINRT@
 #cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
 #cmakedefine SDL_VIDEO_DRIVER_RPI @SDL_VIDEO_DRIVER_RPI@
 #cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@
@@ -463,6 +464,7 @@
 #cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@
 #cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@
 #cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@
+#cmakedefine SDL_POWER_WINRT @SDL_POWER_WINRT@
 #cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@
 #cmakedefine SDL_POWER_UIKIT @SDL_POWER_UIKIT@
 #cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@

+ 2 - 0
include/SDL_config_windows.h

@@ -240,7 +240,9 @@ typedef unsigned int uintptr_t;
 /* Enable various input drivers */
 #define SDL_JOYSTICK_DINPUT 1
 #define SDL_JOYSTICK_HIDAPI 1
+#ifndef __WINRT__
 #define SDL_JOYSTICK_RAWINPUT   1
+#endif
 #define SDL_JOYSTICK_VIRTUAL    1
 #ifdef HAVE_WINDOWS_GAMING_INPUT_H
 #define SDL_JOYSTICK_WGI    1

+ 220 - 0
include/SDL_config_winrt.h

@@ -0,0 +1,220 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_config_winrt_h_
+#define SDL_config_winrt_h_
+#define SDL_config_h_
+
+#include "SDL_platform.h"
+
+/* Make sure the Windows SDK's NTDDI_VERSION macro gets defined.  This is used
+   by SDL to determine which version of the Windows SDK is being used.
+*/
+#include <sdkddkver.h>
+
+/* Define possibly-undefined NTDDI values (used when compiling SDL against
+   older versions of the Windows SDK.
+*/
+#ifndef NTDDI_WINBLUE
+#define NTDDI_WINBLUE 0x06030000
+#endif
+#ifndef NTDDI_WIN10
+#define NTDDI_WIN10 0x0A000000
+#endif
+
+/* This is a set of defines to configure the SDL features */
+
+#ifdef _WIN64
+# define SIZEOF_VOIDP 8
+#else
+# define SIZEOF_VOIDP 4
+#endif
+
+#ifdef __clang__
+# define HAVE_GCC_ATOMICS 1
+#endif
+
+/* Useful headers */
+#define HAVE_DXGI_H 1
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+#define HAVE_XINPUT_H 1
+#endif
+
+#define HAVE_MMDEVICEAPI_H 1
+#define HAVE_AUDIOCLIENT_H 1
+#define HAVE_TPCSHRD_H 1
+
+#define HAVE_LIBC 1
+#define STDC_HEADERS 1
+#define HAVE_CTYPE_H 1
+#define HAVE_FLOAT_H 1
+#define HAVE_LIMITS_H 1
+#define HAVE_MATH_H 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDIO_H 1
+#define HAVE_STRING_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_QSORT 1
+#define HAVE_BSEARCH 1
+#define HAVE_ABS 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE__STRREV 1
+#define HAVE__STRUPR 1
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+/* #undef HAVE_STRTOLL */
+/* #undef HAVE_STRTOULL */
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE__STRICMP 1
+#define HAVE__STRNICMP 1
+#define HAVE_VSNPRINTF 1
+/* TODO, WinRT: consider using ??_s versions of the following */
+/* #undef HAVE__STRLWR */
+/* #undef HAVE_ITOA */
+/* #undef HAVE__LTOA */
+/* #undef HAVE__ULTOA */
+/* #undef HAVE_SSCANF */
+#define HAVE_M_PI 1
+#define HAVE_ACOS   1
+#define HAVE_ACOSF  1
+#define HAVE_ASIN   1
+#define HAVE_ASINF  1
+#define HAVE_ATAN   1
+#define HAVE_ATANF  1
+#define HAVE_ATAN2  1
+#define HAVE_ATAN2F 1
+#define HAVE_CEIL   1
+#define HAVE_CEILF  1
+#define HAVE__COPYSIGN 1
+#define HAVE_COS    1
+#define HAVE_COSF   1
+#define HAVE_EXP    1
+#define HAVE_EXPF   1
+#define HAVE_FABS   1
+#define HAVE_FABSF  1
+#define HAVE_FLOOR  1
+#define HAVE_FLOORF 1
+#define HAVE_FMOD   1
+#define HAVE_FMODF  1
+#define HAVE_LOG    1
+#define HAVE_LOGF   1
+#define HAVE_LOG10  1
+#define HAVE_LOG10F 1
+#define HAVE_LROUND 1
+#define HAVE_LROUNDF 1
+#define HAVE_POW    1
+#define HAVE_POWF   1
+#define HAVE_ROUND 1
+#define HAVE_ROUNDF 1
+#define HAVE__SCALB 1
+#define HAVE_SIN    1
+#define HAVE_SINF   1
+#define HAVE_SQRT   1
+#define HAVE_SQRTF  1
+#define HAVE_TAN    1
+#define HAVE_TANF   1
+#define HAVE_TRUNC  1
+#define HAVE_TRUNCF 1
+#define HAVE__FSEEKI64 1
+
+#define HAVE_ROAPI_H  1
+
+/* Enable various audio drivers */
+#define SDL_AUDIO_DRIVER_WASAPI 1
+#define SDL_AUDIO_DRIVER_DISK   1
+#define SDL_AUDIO_DRIVER_DUMMY  1
+
+/* Enable various input drivers */
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+#define SDL_JOYSTICK_DISABLED 1
+#define SDL_HAPTIC_DISABLED 1
+#else
+#define SDL_JOYSTICK_VIRTUAL    1
+#if (NTDDI_VERSION >= NTDDI_WIN10)
+#define SDL_JOYSTICK_WGI    1
+#define SDL_HAPTIC_DISABLED 1
+#else
+#define SDL_JOYSTICK_XINPUT 1
+#define SDL_HAPTIC_XINPUT   1
+#endif /* WIN10 */
+#endif
+
+/* WinRT doesn't have HIDAPI available */
+#define SDL_HIDAPI_DISABLED    1
+
+/* Enable the dummy sensor driver */
+#define SDL_SENSOR_DUMMY  1
+
+/* Enable various shared object loading systems */
+#define SDL_LOADSO_WINDOWS  1
+
+/* Enable various threading systems */
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+#define SDL_THREAD_GENERIC_COND_SUFFIX 1
+#define SDL_THREAD_WINDOWS  1
+#else
+/* WinRT on Windows 8.0 and Windows Phone 8.0 don't support CreateThread() */
+#define SDL_THREAD_STDCPP   1
+#endif
+
+/* Enable various timer systems */
+#define SDL_TIMER_WINDOWS   1
+
+/* Enable various video drivers */
+#define SDL_VIDEO_DRIVER_WINRT  1
+#define SDL_VIDEO_DRIVER_DUMMY  1
+
+/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */
+#define SDL_VIDEO_OPENGL_ES2 1
+#define SDL_VIDEO_OPENGL_EGL 1
+
+/* Enable appropriate renderer(s) */
+#define SDL_VIDEO_RENDER_D3D11  1
+
+/* Disable D3D12 as it's not implemented for WinRT */
+#define SDL_VIDEO_RENDER_D3D12  0
+
+#if SDL_VIDEO_OPENGL_ES2
+#define SDL_VIDEO_RENDER_OGL_ES2 1
+#endif
+
+/* Enable system power support */
+#define SDL_POWER_WINRT 1
+
+#endif /* SDL_config_winrt_h_ */

+ 1 - 1
include/SDL_cpuinfo.h

@@ -79,7 +79,7 @@ _m_prefetch(void *__P)
 #if !defined(SDL_DISABLE_ARM_NEON_H)
 #  if defined(__ARM_NEON)
 #    include <arm_neon.h>
-#  elif defined(__WINDOWS__) || defined(__GDK__)
+#  elif defined(__WINDOWS__) || defined(__WINRT__) || defined(__GDK__)
 /* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
 #    if defined(_M_ARM)
 #      include <armintr.h>

+ 99 - 0
include/SDL_hints.h

@@ -2112,6 +2112,105 @@ extern "C" {
 */
 #define SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN    "SDL_WINDOW_NO_ACTIVATION_WHEN_SHOWN"
 
+/** \brief Allows back-button-press events on Windows Phone to be marked as handled
+ *
+ *  Windows Phone devices typically feature a Back button.  When pressed,
+ *  the OS will emit back-button-press events, which apps are expected to
+ *  handle in an appropriate manner.  If apps do not explicitly mark these
+ *  events as 'Handled', then the OS will invoke its default behavior for
+ *  unhandled back-button-press events, which on Windows Phone 8 and 8.1 is to
+ *  terminate the app (and attempt to switch to the previous app, or to the
+ *  device's home screen).
+ *
+ *  Setting the SDL_HINT_WINRT_HANDLE_BACK_BUTTON hint to "1" will cause SDL
+ *  to mark back-button-press events as Handled, if and when one is sent to
+ *  the app.
+ *
+ *  Internally, Windows Phone sends back button events as parameters to
+ *  special back-button-press callback functions.  Apps that need to respond
+ *  to back-button-press events are expected to register one or more
+ *  callback functions for such, shortly after being launched (during the
+ *  app's initialization phase).  After the back button is pressed, the OS
+ *  will invoke these callbacks.  If the app's callback(s) do not explicitly
+ *  mark the event as handled by the time they return, or if the app never
+ *  registers one of these callback, the OS will consider the event
+ *  un-handled, and it will apply its default back button behavior (terminate
+ *  the app).
+ *
+ *  SDL registers its own back-button-press callback with the Windows Phone
+ *  OS.  This callback will emit a pair of SDL key-press events (SDL_KEYDOWN
+ *  and SDL_KEYUP), each with a scancode of SDL_SCANCODE_AC_BACK, after which
+ *  it will check the contents of the hint, SDL_HINT_WINRT_HANDLE_BACK_BUTTON.
+ *  If the hint's value is set to "1", the back button event's Handled
+ *  property will get set to 'true'.  If the hint's value is set to something
+ *  else, or if it is unset, SDL will leave the event's Handled property
+ *  alone.  (By default, the OS sets this property to 'false', to note.)
+ *
+ *  SDL apps can either set SDL_HINT_WINRT_HANDLE_BACK_BUTTON well before a
+ *  back button is pressed, or can set it in direct-response to a back button
+ *  being pressed.
+ *
+ *  In order to get notified when a back button is pressed, SDL apps should
+ *  register a callback function with SDL_AddEventWatch(), and have it listen
+ *  for SDL_KEYDOWN events that have a scancode of SDL_SCANCODE_AC_BACK.
+ *  (Alternatively, SDL_KEYUP events can be listened-for.  Listening for
+ *  either event type is suitable.)  Any value of SDL_HINT_WINRT_HANDLE_BACK_BUTTON
+ *  set by such a callback, will be applied to the OS' current
+ *  back-button-press event.
+ *
+ *  More details on back button behavior in Windows Phone apps can be found
+ *  at the following page, on Microsoft's developer site:
+ *  http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj247550(v=vs.105).aspx
+ */
+#define SDL_HINT_WINRT_HANDLE_BACK_BUTTON "SDL_WINRT_HANDLE_BACK_BUTTON"
+
+/** \brief Label text for a WinRT app's privacy policy link
+ *
+ *  Network-enabled WinRT apps must include a privacy policy.  On Windows 8, 8.1, and RT,
+ *  Microsoft mandates that this policy be available via the Windows Settings charm.
+ *  SDL provides code to add a link there, with its label text being set via the
+ *  optional hint, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL.
+ *
+ *  Please note that a privacy policy's contents are not set via this hint.  A separate
+ *  hint, SDL_HINT_WINRT_PRIVACY_POLICY_URL, is used to link to the actual text of the
+ *  policy.
+ *
+ *  The contents of this hint should be encoded as a UTF8 string.
+ *
+ *  The default value is "Privacy Policy".  This hint should only be set during app
+ *  initialization, preferably before any calls to SDL_Init().
+ *
+ *  For additional information on linking to a privacy policy, see the documentation for
+ *  SDL_HINT_WINRT_PRIVACY_POLICY_URL.
+ */
+#define SDL_HINT_WINRT_PRIVACY_POLICY_LABEL "SDL_WINRT_PRIVACY_POLICY_LABEL"
+
+/**
+ *  \brief A URL to a WinRT app's privacy policy
+ *
+ *  All network-enabled WinRT apps must make a privacy policy available to its
+ *  users.  On Windows 8, 8.1, and RT, Microsoft mandates that this policy be
+ *  be available in the Windows Settings charm, as accessed from within the app.
+ *  SDL provides code to add a URL-based link there, which can point to the app's
+ *  privacy policy.
+ *
+ *  To setup a URL to an app's privacy policy, set SDL_HINT_WINRT_PRIVACY_POLICY_URL
+ *  before calling any SDL_Init() functions.  The contents of the hint should
+ *  be a valid URL.  For example, "http://www.example.com".
+ *
+ *  The default value is "", which will prevent SDL from adding a privacy policy
+ *  link to the Settings charm.  This hint should only be set during app init.
+ *
+ *  The label text of an app's "Privacy Policy" link may be customized via another
+ *  hint, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL.
+ *
+ *  Please note that on Windows Phone, Microsoft does not provide standard UI
+ *  for displaying a privacy policy link, and as such, SDL_HINT_WINRT_PRIVACY_POLICY_URL
+ *  will not get used on that platform.  Network-enabled phone apps should display
+ *  their privacy policy through some other, in-app means.
+ */
+#define SDL_HINT_WINRT_PRIVACY_POLICY_URL "SDL_WINRT_PRIVACY_POLICY_URL"
+
 /**
  *  \brief Mark X11 windows as override-redirect.
  *

+ 28 - 0
include/SDL_main.h

@@ -39,6 +39,18 @@
  */
 #define SDL_MAIN_AVAILABLE
 
+#elif defined(__WINRT__)
+/* On WinRT, SDL provides a main function that initializes CoreApplication,
+   creating an instance of IFrameworkView in the process.
+
+   Please note that #include'ing SDL_main.h is not enough to get a main()
+   function working.  In non-XAML apps, the file,
+   src/main/winrt/SDL_WinRT_main_NonXAML.cpp, or a copy of it, must be compiled
+   into the app itself.  In XAML apps, the function, SDL_WinRTRunApp must be
+   called, with a pointer to the Direct3D-hosted XAML control passed in.
+*/
+#define SDL_MAIN_NEEDED
+
 #elif defined(__GDK__)
 /* On GDK, SDL provides a main function that initializes the game runtime.
 
@@ -196,6 +208,22 @@ extern DECLSPEC void SDLCALL SDL_UnregisterApp(void);
 #endif /* defined(__WIN32__) || defined(__GDK__) */
 
 
+#ifdef __WINRT__
+
+/**
+ * Initialize and launch an SDL/WinRT application.
+ *
+ * \param mainFunction the SDL app's C-style main(), an SDL_main_func
+ * \param reserved reserved for future use; should be NULL
+ * \returns 0 on success or -1 on failure; call SDL_GetError() to retrieve
+ *          more information on the failure.
+ *
+ * \since This function is available since SDL 2.0.3.
+ */
+extern DECLSPEC int SDLCALL SDL_WinRTRunApp(SDL_main_func mainFunction, void * reserved);
+
+#endif /* __WINRT__ */
+
 #if defined(__IPHONEOS__)
 
 /**

+ 2 - 1
include/SDL_platform.h

@@ -167,7 +167,8 @@
 #endif /* HAVE_WINAPIFAMILY_H */
 
 #if WINAPI_FAMILY_WINRT
-#error WinRT no longer supported.
+#undef __WINRT__
+#define __WINRT__ 1
 #elif defined(_GAMING_DESKTOP) /* GDK project configuration always defines _GAMING_XXX */
 #undef __WINGDK__
 #define __WINGDK__ 1

+ 103 - 0
include/SDL_system.h

@@ -466,6 +466,109 @@ extern DECLSPEC int SDLCALL SDL_AndroidSendMessage(Uint32 command, int param);
 
 #endif /* __ANDROID__ */
 
+/* Platform specific functions for WinRT */
+#ifdef __WINRT__
+
+/**
+ *  \brief WinRT / Windows Phone path types
+ */
+typedef enum
+{
+    /** \brief The installed app's root directory.
+        Files here are likely to be read-only. */
+    SDL_WINRT_PATH_INSTALLED_LOCATION,
+
+    /** \brief The app's local data store.  Files may be written here */
+    SDL_WINRT_PATH_LOCAL_FOLDER,
+
+    /** \brief The app's roaming data store.  Unsupported on Windows Phone.
+        Files written here may be copied to other machines via a network
+        connection.
+    */
+    SDL_WINRT_PATH_ROAMING_FOLDER,
+
+    /** \brief The app's temporary data store.  Unsupported on Windows Phone.
+        Files written here may be deleted at any time. */
+    SDL_WINRT_PATH_TEMP_FOLDER
+} SDL_WinRT_Path;
+
+
+/**
+ *  \brief WinRT Device Family
+ */
+typedef enum
+{
+    /** \brief Unknown family  */
+    SDL_WINRT_DEVICEFAMILY_UNKNOWN,
+
+    /** \brief Desktop family*/
+    SDL_WINRT_DEVICEFAMILY_DESKTOP,
+
+    /** \brief Mobile family (for example smartphone) */
+    SDL_WINRT_DEVICEFAMILY_MOBILE,
+
+    /** \brief XBox family */
+    SDL_WINRT_DEVICEFAMILY_XBOX,
+} SDL_WinRT_DeviceFamily;
+
+
+/**
+ * Retrieve a WinRT defined path on the local file system.
+ *
+ * Not all paths are available on all versions of Windows. This is especially
+ * true on Windows Phone. Check the documentation for the given SDL_WinRT_Path
+ * for more information on which path types are supported where.
+ *
+ * Documentation on most app-specific path types on WinRT can be found on
+ * MSDN, at the URL:
+ *
+ * https://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
+ *
+ * \param pathType the type of path to retrieve, one of SDL_WinRT_Path
+ * \returns a UCS-2 string (16-bit, wide-char) containing the path, or NULL if
+ *          the path is not available for any reason; call SDL_GetError() for
+ *          more information.
+ *
+ * \since This function is available since SDL 2.0.3.
+ *
+ * \sa SDL_WinRTGetFSPathUTF8
+ */
+extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType);
+
+/**
+ * Retrieve a WinRT defined path on the local file system.
+ *
+ * Not all paths are available on all versions of Windows. This is especially
+ * true on Windows Phone. Check the documentation for the given SDL_WinRT_Path
+ * for more information on which path types are supported where.
+ *
+ * Documentation on most app-specific path types on WinRT can be found on
+ * MSDN, at the URL:
+ *
+ * https://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
+ *
+ * \param pathType the type of path to retrieve, one of SDL_WinRT_Path
+ * \returns a UTF-8 string (8-bit, multi-byte) containing the path, or NULL if
+ *          the path is not available for any reason; call SDL_GetError() for
+ *          more information.
+ *
+ * \since This function is available since SDL 2.0.3.
+ *
+ * \sa SDL_WinRTGetFSPathUNICODE
+ */
+extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
+
+/**
+ * Detects the device family of WinRT platform at runtime.
+ *
+ * \returns a value from the SDL_WinRT_DeviceFamily enum.
+ *
+ * \since This function is available since SDL 2.0.8.
+ */
+extern DECLSPEC SDL_WinRT_DeviceFamily SDLCALL SDL_WinRTGetDeviceFamily();
+
+#endif /* __WINRT__ */
+
 /**
  * Query if the current device is a tablet.
  *

+ 11 - 0
include/SDL_syswm.h

@@ -55,6 +55,10 @@ struct SDL_SysWMinfo;
 #include <windows.h>
 #endif
 
+#if defined(SDL_VIDEO_DRIVER_WINRT)
+#include <Inspectable.h>
+#endif
+
 /* This is the structure for custom window manager events */
 #if defined(SDL_VIDEO_DRIVER_X11)
 #if defined(__APPLE__) && defined(__MACH__)
@@ -128,6 +132,7 @@ typedef enum
     SDL_SYSWM_COCOA,
     SDL_SYSWM_UIKIT,
     SDL_SYSWM_WAYLAND,
+    SDL_SYSWM_WINRT,
     SDL_SYSWM_ANDROID,
     SDL_SYSWM_VIVANTE,
     SDL_SYSWM_HAIKU,
@@ -206,6 +211,12 @@ struct SDL_SysWMinfo
             HINSTANCE hinstance;        /**< The instance handle */
         } win;
 #endif
+#if defined(SDL_VIDEO_DRIVER_WINRT)
+        struct
+        {
+            IInspectable * window;      /**< The WinRT CoreWindow */
+        } winrt;
+#endif
 #if defined(SDL_VIDEO_DRIVER_X11)
         struct
         {

+ 2 - 2
include/begin_code.h

@@ -51,7 +51,7 @@
 
 /* Some compilers use a special export keyword */
 #ifndef DECLSPEC
-# if defined(__WIN32__) || defined(__CYGWIN__) || defined(__GDK__)
+# if defined(__WIN32__) || defined(__WINRT__) || defined(__CYGWIN__) || defined(__GDK__)
 #  ifdef DLL_EXPORT
 #   define DECLSPEC __declspec(dllexport)
 #  else
@@ -68,7 +68,7 @@
 
 /* By default SDL uses the C calling convention */
 #ifndef SDLCALL
-#if (defined(__WIN32__) || defined(__GDK__)) && !defined(__GNUC__)
+#if (defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)) && !defined(__GNUC__)
 #define SDLCALL __cdecl
 #else
 #define SDLCALL

+ 3 - 1
src/SDL.c

@@ -22,7 +22,7 @@
 
 #if defined(__WIN32__) || defined(__GDK__)
 #include "core/windows/SDL_windows.h"
-#else
+#elif !defined(__WINRT__)
 #include <unistd.h> /* _exit(), etc. */
 #endif
 
@@ -575,6 +575,8 @@ SDL_GetPlatform(void)
     return "Solaris";
 #elif __WIN32__
     return "Windows";
+#elif __WINRT__
+    return "WinRT";
 #elif __WINGDK__
     return "WinGDK";
 #elif __XBOXONE__

+ 7 - 7
src/SDL_log.c

@@ -20,7 +20,7 @@
 */
 #include "./SDL_internal.h"
 
-#if defined(__WIN32__) || defined(__GDK__)
+#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
 #include "core/windows/SDL_windows.h"
 #endif
 
@@ -366,7 +366,7 @@ SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list
     }
 }
 
-#if defined(__WIN32__) && !defined(HAVE_STDIO_H) && !defined(__GDK__)
+#if defined(__WIN32__) && !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__)
 /* Flag tracking the attachment of the console: 0=unattached, 1=attached to a console, 2=attached to a file, -1=error */
 static int consoleAttached = 0;
 
@@ -378,7 +378,7 @@ static void SDLCALL
 SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
               const char *message)
 {
-#if defined(__WIN32__) || defined(__GDK__)
+#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
     /* Way too many allocations here, urgh */
     /* Note: One can't call SDL_SetError here, since that function itself logs. */
     {
@@ -387,7 +387,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
         LPTSTR tstr;
         SDL_bool isstack;
 
-#if !defined(HAVE_STDIO_H) && !defined(__GDK__)
+#if !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__)
         BOOL attachResult;
         DWORD attachError;
         DWORD charsWritten;
@@ -426,7 +426,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
                         }
                 }
         }
-#endif /* !defined(HAVE_STDIO_H) && !defined(__GDK__) */
+#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__) */
 
         length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
         output = SDL_small_alloc(char, length, &isstack);
@@ -436,7 +436,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
         /* Output to debugger */
         OutputDebugString(tstr);
        
-#if !defined(HAVE_STDIO_H) && !defined(__GDK__)
+#if !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__)
         /* Screen output to stderr, if console was attached. */
         if (consoleAttached == 1) {
                 if (!WriteConsole(stderrHandle, tstr, (DWORD) SDL_tcslen(tstr), &charsWritten, NULL)) {
@@ -451,7 +451,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
                 OutputDebugString(TEXT("Error calling WriteFile\r\n"));
             }
         }
-#endif /* !defined(HAVE_STDIO_H) && !defined(__GDK__) */
+#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) && !defined(__GDK__) */
 
         SDL_free(tstr);
         SDL_small_free(output, isstack);

+ 1 - 1
src/atomic/SDL_spinlock.c

@@ -20,7 +20,7 @@
 */
 #include "../SDL_internal.h"
 
-#if defined(__WIN32__) || defined(__GDK__)
+#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
 #include "../core/windows/SDL_windows.h"
 #endif
 

+ 29 - 86
src/audio/wasapi/SDL_wasapi.c

@@ -46,27 +46,13 @@
 #endif
 
 /* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
-static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
 static const IID SDL_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483,{ 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2 } };
 static const IID SDL_IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0,{ 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17 } };
 
-/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
-static HMODULE libavrt = NULL;
-typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD);
-typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
-static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
-static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
-
 static void
 WASAPI_DetectDevices(void)
 {
-    SDL_IMMDevice_EnumerateEndpoints(SDL_FALSE);
-}
-
-int
-WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
-{
-    return SDL_IMMDevice_GetDefaultAudioInfo(name, spec, iscapture);
+    WASAPI_EnumerateEndpoints();
 }
 
 static SDL_INLINE SDL_bool
@@ -140,7 +126,7 @@ UpdateAudioStream(_THIS, const SDL_AudioSpec *oldspec)
     return 0;
 }
 
-static int ActivateWasapiDevice(_THIS, SDL_bool isrecovery);
+
 static void ReleaseWasapiDevice(_THIS);
 
 static SDL_bool
@@ -157,7 +143,7 @@ RecoverWasapiDevice(_THIS)
        devices try to reinitialize whatever the new default is, so it's more
        likely to carry on here, but this handles a non-default device that
        simply had its format changed in the Windows Control Panel. */
-    if (ActivateWasapiDevice(this, SDL_TRUE) == -1) {
+    if (WASAPI_ActivateDevice(this, SDL_TRUE) == -1) {
         SDL_OpenedAudioDeviceDisconnected(this);
         return SDL_FALSE;
     }
@@ -363,6 +349,11 @@ ReleaseWasapiDevice(_THIS)
         this->hidden->capturestream = NULL;
     }
 
+    if (this->hidden->activation_handler) {
+        WASAPI_PlatformDeleteActivationHandler(this->hidden->activation_handler);
+        this->hidden->activation_handler = NULL;
+    }
+
     if (this->hidden->event) {
         CloseHandle(this->hidden->event);
         this->hidden->event = NULL;
@@ -371,6 +362,18 @@ ReleaseWasapiDevice(_THIS)
 
 static void
 WASAPI_CloseDevice(_THIS)
+{
+    WASAPI_UnrefDevice(this);
+}
+
+void
+WASAPI_RefDevice(_THIS)
+{
+    SDL_AtomicIncRef(&this->hidden->refcount);
+}
+
+void
+WASAPI_UnrefDevice(_THIS)
 {
     if (!SDL_AtomicDecRef(&this->hidden->refcount)) {
         return;
@@ -387,7 +390,7 @@ WASAPI_CloseDevice(_THIS)
 }
 
 /* This is called once a device is activated, possibly asynchronously. */
-static int
+int
 WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
 {
     /* !!! FIXME: we could request an exclusive mode stream, which is lower latency;
@@ -416,7 +419,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
 
     SDL_assert(client != NULL);
 
-#if defined(__GDK__) /* CreateEventEx() arrived in Vista, so we need an #ifdef for XP. */
+#if defined(__WINRT__) || defined(__GDK__) /* CreateEventEx() arrived in Vista, so we need an #ifdef for XP. */
     this->hidden->event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
 #else
     this->hidden->event = CreateEventW(NULL, 0, 0, NULL);
@@ -538,34 +541,6 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
     return 0;  /* good to go. */
 }
 
-static int
-ActivateWasapiDevice(_THIS, const SDL_bool isrecovery)
-{
-    IMMDevice *device = NULL;
-    HRESULT ret;
-
-    if (SDL_IMMDevice_Get(this->hidden->devid, &device, this->iscapture) < 0) {
-        this->hidden->client = NULL;
-        return -1; /* This is already set by SDL_IMMDevice_Get */
-    }
-
-    /* this is not async in standard win32, yay! */
-    ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &this->hidden->client);
-    IMMDevice_Release(device);
-
-    if (FAILED(ret)) {
-        SDL_assert(this->hidden->client == NULL);
-        return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
-    }
-
-    SDL_assert(this->hidden->client != NULL);
-    if (WASAPI_PrepDevice(this, isrecovery) == -1) {   /* not async, fire it right away. */
-        return -1;
-    }
-
-    return 0;  /* good to go. */
-}
-
 
 static int
 WASAPI_OpenDevice(_THIS, const char *devname)
@@ -580,7 +555,7 @@ WASAPI_OpenDevice(_THIS, const char *devname)
     }
     SDL_zerop(this->hidden);
 
-    SDL_AtomicIncRef(&this->hidden->refcount); /* so CloseDevice() will unref to zero. */
+    WASAPI_RefDevice(this);   /* so CloseDevice() will unref to zero. */
 
     if (!devid) {  /* is default device? */
         this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
@@ -591,7 +566,7 @@ WASAPI_OpenDevice(_THIS, const char *devname)
         }
     }
 
-    if (ActivateWasapiDevice(this, SDL_FALSE) == -1) {
+    if (WASAPI_ActivateDevice(this, SDL_FALSE) == -1) {
         return -1;  /* already set error. */
     }
 
@@ -609,58 +584,26 @@ WASAPI_OpenDevice(_THIS, const char *devname)
 static void
 WASAPI_ThreadInit(_THIS)
 {
-    /* this thread uses COM. */
-    if (SUCCEEDED(WIN_CoInitialize())) {    /* can't report errors, hope it worked! */
-        this->hidden->coinitialized = SDL_TRUE;
-    }
-
-    /* Set this thread to very high "Pro Audio" priority. */
-    if (pAvSetMmThreadCharacteristicsW) {
-        DWORD idx = 0;
-        this->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
-    }
+    WASAPI_PlatformThreadInit(this);
 }
 
 static void
 WASAPI_ThreadDeinit(_THIS)
 {
-    /* Set this thread back to normal priority. */
-    if (this->hidden->task && pAvRevertMmThreadCharacteristics) {
-        pAvRevertMmThreadCharacteristics(this->hidden->task);
-        this->hidden->task = NULL;
-    }
-
-    if (this->hidden->coinitialized) {
-        WIN_CoUninitialize();
-        this->hidden->coinitialized = SDL_FALSE;
-    }
+    WASAPI_PlatformThreadDeinit(this);
 }
 
 static void
 WASAPI_Deinitialize(void)
 {
-    if (libavrt) {
-        FreeLibrary(libavrt);
-        libavrt = NULL;
-    }
-
-    pAvSetMmThreadCharacteristicsW = NULL;
-    pAvRevertMmThreadCharacteristics = NULL;
-
-    SDL_IMMDevice_Quit();
+    WASAPI_PlatformDeinit();
 }
 
 static SDL_bool
 WASAPI_Init(SDL_AudioDriverImpl * impl)
 {
-    if (SDL_IMMDevice_Init() < 0) {
-        return SDL_FALSE; /* Error is set by SDL_IMMDevice_Init */
-    }
-
-    libavrt = LoadLibrary(TEXT("avrt.dll"));  /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */
-    if (libavrt) {
-        pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW) GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
-        pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics) GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
+    if (WASAPI_PlatformInit() == -1) {
+        return SDL_FALSE;
     }
 
     /* Set the function pointers */

+ 17 - 0
src/audio/wasapi/SDL_wasapi.h

@@ -51,8 +51,25 @@ struct SDL_PrivateAudioData
     int framesize;
     int default_device_generation;
     SDL_bool device_lost;
+    void *activation_handler;
+    SDL_atomic_t just_activated;
 };
 
+/* win32 and winrt implementations call into these. */
+int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
+void WASAPI_RefDevice(_THIS);
+void WASAPI_UnrefDevice(_THIS);
+
+/* These are functions that are implemented differently for Windows vs WinRT. */
+int WASAPI_PlatformInit(void);
+void WASAPI_PlatformDeinit(void);
+void WASAPI_EnumerateEndpoints(void);
+int WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture);
+int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery);
+void WASAPI_PlatformThreadInit(_THIS);
+void WASAPI_PlatformThreadDeinit(_THIS);
+void WASAPI_PlatformDeleteActivationHandler(void *handler);
+
 #ifdef __cplusplus
 }
 #endif

+ 162 - 0
src/audio/wasapi/SDL_wasapi_win32.c

@@ -0,0 +1,162 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+/* This is code that Windows uses to talk to WASAPI-related system APIs.
+   This is for non-WinRT desktop apps. The C++/CX implementation of these
+   functions, exclusive to WinRT, are in SDL_wasapi_winrt.cpp.
+   The code in SDL_wasapi.c is used by both standard Windows and WinRT builds
+   to deal with audio and calls into these functions. */
+
+#if SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__)
+
+#include "../../core/windows/SDL_windows.h"
+#include "../../core/windows/SDL_immdevice.h"
+#include "SDL_audio.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+
+#include <audioclient.h>
+
+#include "SDL_wasapi.h"
+
+/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
+static HMODULE libavrt = NULL;
+typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD);
+typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
+static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
+static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
+
+/* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
+static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
+
+int
+WASAPI_PlatformInit(void)
+{
+    if (SDL_IMMDevice_Init() < 0) {
+        return -1; /* This is set by SDL_IMMDevice_Init */
+    }
+
+    libavrt = LoadLibrary(TEXT("avrt.dll"));  /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */
+    if (libavrt) {
+        pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW) GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
+        pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics) GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
+    }
+
+    return 0;
+}
+
+void
+WASAPI_PlatformDeinit(void)
+{
+    if (libavrt) {
+        FreeLibrary(libavrt);
+        libavrt = NULL;
+    }
+
+    pAvSetMmThreadCharacteristicsW = NULL;
+    pAvRevertMmThreadCharacteristics = NULL;
+
+    SDL_IMMDevice_Quit();
+}
+
+void
+WASAPI_PlatformThreadInit(_THIS)
+{
+    /* this thread uses COM. */
+    if (SUCCEEDED(WIN_CoInitialize())) {    /* can't report errors, hope it worked! */
+        this->hidden->coinitialized = SDL_TRUE;
+    }
+
+    /* Set this thread to very high "Pro Audio" priority. */
+    if (pAvSetMmThreadCharacteristicsW) {
+        DWORD idx = 0;
+        this->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
+    }
+}
+
+void
+WASAPI_PlatformThreadDeinit(_THIS)
+{
+    /* Set this thread back to normal priority. */
+    if (this->hidden->task && pAvRevertMmThreadCharacteristics) {
+        pAvRevertMmThreadCharacteristics(this->hidden->task);
+        this->hidden->task = NULL;
+    }
+
+    if (this->hidden->coinitialized) {
+        WIN_CoUninitialize();
+        this->hidden->coinitialized = SDL_FALSE;
+    }
+}
+
+int
+WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
+{
+    IMMDevice *device = NULL;
+    HRESULT ret;
+
+    if (SDL_IMMDevice_Get(this->hidden->devid, &device, this->iscapture) < 0) {
+        this->hidden->client = NULL;
+        return -1; /* This is already set by SDL_IMMDevice_Get */
+    }
+
+    /* this is not async in standard win32, yay! */
+    ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &this->hidden->client);
+    IMMDevice_Release(device);
+
+    if (FAILED(ret)) {
+        SDL_assert(this->hidden->client == NULL);
+        return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
+    }
+
+    SDL_assert(this->hidden->client != NULL);
+    if (WASAPI_PrepDevice(this, isrecovery) == -1) {   /* not async, fire it right away. */
+        return -1;
+    }
+
+    return 0;  /* good to go. */
+}
+
+void
+WASAPI_EnumerateEndpoints(void)
+{
+    SDL_IMMDevice_EnumerateEndpoints(SDL_FALSE);
+}
+
+int
+WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
+{
+    return SDL_IMMDevice_GetDefaultAudioInfo(name, spec, iscapture);
+}
+
+void
+WASAPI_PlatformDeleteActivationHandler(void *handler)
+{
+    /* not asynchronous. */
+    SDL_assert(!"This function should have only been called on WinRT.");
+}
+
+#endif  /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 447 - 0
src/audio/wasapi/SDL_wasapi_winrt.cpp

@@ -0,0 +1,447 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+// This is C++/CX code that the WinRT port uses to talk to WASAPI-related
+//  system APIs. The C implementation of these functions, for non-WinRT apps,
+//  is in SDL_wasapi_win32.c. The code in SDL_wasapi.c is used by both standard
+//  Windows and WinRT builds to deal with audio and calls into these functions.
+
+#if SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
+
+#include <Windows.h>
+#include <windows.ui.core.h>
+#include <windows.devices.enumeration.h>
+#include <windows.media.devices.h>
+#include <wrl/implements.h>
+#include <collection.h>
+
+extern "C" {
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_audio.h"
+#include "SDL_timer.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+}
+
+#define COBJMACROS
+#include <mmdeviceapi.h>
+#include <audioclient.h>
+
+#include "SDL_wasapi.h"
+
+using namespace Windows::Devices::Enumeration;
+using namespace Windows::Media::Devices;
+using namespace Windows::Foundation;
+using namespace Microsoft::WRL;
+
+static Platform::String^ SDL_PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4e27-bc73-6882a1bb8e4c} 0";
+
+static void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid);
+static void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid);
+extern "C" {
+    SDL_atomic_t SDL_IMMDevice_DefaultPlaybackGeneration;
+    SDL_atomic_t SDL_IMMDevice_DefaultCaptureGeneration;
+}
+
+/* This is a list of device id strings we have inflight, so we have consistent pointers to the same device. */
+typedef struct DevIdList
+{
+    WCHAR *str;
+    struct DevIdList *next;
+} DevIdList;
+
+static DevIdList *deviceid_list = NULL;
+
+class SDL_WasapiDeviceEventHandler
+{
+public:
+    SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture);
+    ~SDL_WasapiDeviceEventHandler();
+    void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
+    void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
+    void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
+    void OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args);
+    void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
+    void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
+    SDL_semaphore* completed;
+
+private:
+    const SDL_bool iscapture;
+    DeviceWatcher^ watcher;
+    Windows::Foundation::EventRegistrationToken added_handler;
+    Windows::Foundation::EventRegistrationToken removed_handler;
+    Windows::Foundation::EventRegistrationToken updated_handler;
+    Windows::Foundation::EventRegistrationToken completed_handler;
+    Windows::Foundation::EventRegistrationToken default_changed_handler;
+};
+
+SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
+    : iscapture(_iscapture)
+    , completed(SDL_CreateSemaphore(0))
+{
+    if (!completed)
+        return;  // uhoh.
+
+    Platform::String^ selector = _iscapture ? MediaDevice::GetAudioCaptureSelector() :
+                                              MediaDevice::GetAudioRenderSelector();
+    Platform::Collections::Vector<Platform::String^> properties;
+    properties.Append(SDL_PKEY_AudioEngine_DeviceFormat);
+    watcher = DeviceInformation::CreateWatcher(selector, properties.GetView());
+    if (!watcher)
+        return;  // uhoh.
+
+    // !!! FIXME: this doesn't need a lambda here, I think, if I make SDL_WasapiDeviceEventHandler a proper C++/CX class. --ryan.
+    added_handler = watcher->Added += ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
+    removed_handler = watcher->Removed += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
+    updated_handler = watcher->Updated += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
+    completed_handler = watcher->EnumerationCompleted += ref new TypedEventHandler<DeviceWatcher^, Platform::Object^>([this](DeviceWatcher^ sender, Platform::Object^ args) { OnEnumerationCompleted(sender, args); } );
+    if (iscapture) {
+        default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
+    } else {
+        default_changed_handler = MediaDevice::DefaultAudioRenderDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioRenderDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args) { OnDefaultRenderDeviceChanged(sender, args); } );
+    }
+    watcher->Start();
+}
+
+SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
+{
+    if (watcher) {
+        watcher->Added -= added_handler;
+        watcher->Removed -= removed_handler;
+        watcher->Updated -= updated_handler;
+        watcher->EnumerationCompleted -= completed_handler;
+        watcher->Stop();
+        watcher = nullptr;
+    }
+    if (completed) {
+        SDL_DestroySemaphore(completed);
+        completed = nullptr;
+    }
+
+    if (iscapture) {
+        MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
+    } else {
+        MediaDevice::DefaultAudioRenderDeviceChanged -= default_changed_handler;
+    }
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ info)
+{
+    SDL_assert(sender == this->watcher);
+    char *utf8dev = WIN_StringToUTF8(info->Name->Data());
+    if (utf8dev) {
+        WAVEFORMATEXTENSIBLE fmt;
+        Platform::Object^ obj = info->Properties->Lookup(SDL_PKEY_AudioEngine_DeviceFormat);
+        if (obj) {
+            IPropertyValue^ property = (IPropertyValue^) obj;
+            Platform::Array<unsigned char>^ data;
+            property->GetUInt8Array(&data);
+            SDL_memcpy(&fmt, data->Data, SDL_min(data->Length, sizeof(WAVEFORMATEXTENSIBLE)));
+        } else {
+            SDL_zero(fmt);
+        }
+
+        WASAPI_AddDevice(this->iscapture, utf8dev, &fmt, info->Id->Data());
+        SDL_free(utf8dev);
+    }
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ info)
+{
+    SDL_assert(sender == this->watcher);
+    WASAPI_RemoveDevice(this->iscapture, info->Id->Data());
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args)
+{
+    SDL_assert(sender == this->watcher);
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args)
+{
+    SDL_assert(sender == this->watcher);
+    SDL_SemPost(this->completed);
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
+{
+    SDL_assert(this->iscapture);
+    SDL_AtomicAdd(&SDL_IMMDevice_DefaultPlaybackGeneration, 1);
+}
+
+void
+SDL_WasapiDeviceEventHandler::OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args)
+{
+    SDL_assert(!this->iscapture);
+    SDL_AtomicAdd(&SDL_IMMDevice_DefaultCaptureGeneration, 1);
+}
+
+
+static SDL_WasapiDeviceEventHandler *playback_device_event_handler;
+static SDL_WasapiDeviceEventHandler *capture_device_event_handler;
+
+int WASAPI_PlatformInit(void)
+{
+    SDL_AtomicSet(&SDL_IMMDevice_DefaultPlaybackGeneration, 1);
+    SDL_AtomicSet(&SDL_IMMDevice_DefaultCaptureGeneration, 1);
+    return 0;
+}
+
+void WASAPI_PlatformDeinit(void)
+{
+    DevIdList *devidlist;
+    DevIdList *next;
+
+    delete playback_device_event_handler;
+    playback_device_event_handler = nullptr;
+    delete capture_device_event_handler;
+    capture_device_event_handler = nullptr;
+
+    for (devidlist = deviceid_list; devidlist; devidlist = next) {
+        next = devidlist->next;
+        SDL_free(devidlist->str);
+        SDL_free(devidlist);
+    }
+    deviceid_list = NULL;
+}
+
+void WASAPI_EnumerateEndpoints(void)
+{
+    // DeviceWatchers will fire an Added event for each existing device at
+    //  startup, so we don't need to enumerate them separately before
+    //  listening for updates.
+    playback_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_FALSE);
+    capture_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
+    SDL_SemWait(playback_device_event_handler->completed);
+    SDL_SemWait(capture_device_event_handler->completed);
+}
+
+struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
+{
+    SDL_WasapiActivationHandler() : device(nullptr) {}
+    STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *operation);
+    SDL_AudioDevice *device;
+};
+
+HRESULT
+SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
+{
+    // Just set a flag, since we're probably in a different thread. We'll pick it up and init everything on our own thread to prevent races.
+    SDL_AtomicSet(&device->hidden->just_activated, 1);
+    WASAPI_UnrefDevice(device);
+    return S_OK;
+}
+
+void
+WASAPI_PlatformDeleteActivationHandler(void *handler)
+{
+    ((SDL_WasapiActivationHandler *) handler)->Release();
+}
+
+int
+WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
+{
+    return SDL_Unsupported();
+}
+
+int
+WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
+{
+    LPCWSTR devid = _this->hidden->devid;
+    Platform::String^ defdevid;
+
+    if (devid == nullptr) {
+        defdevid = _this->iscapture ? MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default) : MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+        if (defdevid) {
+            devid = defdevid->Data();
+        }
+    }
+
+    SDL_AtomicSet(&_this->hidden->just_activated, 0);
+
+    ComPtr<SDL_WasapiActivationHandler> handler = Make<SDL_WasapiActivationHandler>();
+    if (handler == nullptr) {
+        return SDL_SetError("Failed to allocate WASAPI activation handler");
+    }
+
+    handler.Get()->AddRef();  // we hold a reference after ComPtr destructs on return, causing a Release, and Release ourselves in WASAPI_PlatformDeleteActivationHandler(), etc.
+    handler.Get()->device = _this;
+    _this->hidden->activation_handler = handler.Get();
+
+    WASAPI_RefDevice(_this);  /* completion handler will unref it. */
+    IActivateAudioInterfaceAsyncOperation *async = nullptr;
+    const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async);
+
+    if (FAILED(ret) || async == nullptr) {
+        if (async != nullptr) {
+            async->Release();
+        }
+        handler.Get()->Release();
+        WASAPI_UnrefDevice(_this);
+        return WIN_SetErrorFromHRESULT("WASAPI can't activate requested audio endpoint", ret);
+    }
+
+    /* Spin until the async operation is complete.
+     * If we don't PrepDevice before leaving this function, the bug list gets LONG:
+     * - device.spec is not filled with the correct information
+     * - The 'obtained' spec will be wrong for ALLOW_CHANGE properties
+     * - SDL_AudioStreams will/will not be allocated at the right time
+     * - SDL_assert(device->callbackspec.size == device->spec.size) will fail
+     * - When the assert is ignored, skipping or a buffer overflow will occur
+     */
+    while (!SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) {
+        SDL_Delay(1);
+    }
+
+    HRESULT activateRes = S_OK;
+    IUnknown *iunknown = nullptr;
+    const HRESULT getActivateRes = async->GetActivateResult(&activateRes, &iunknown);
+    async->Release();
+    if (FAILED(getActivateRes)) {
+        return WIN_SetErrorFromHRESULT("Failed to get WASAPI activate result", getActivateRes);
+    } else if (FAILED(activateRes)) {
+        return WIN_SetErrorFromHRESULT("Failed to activate WASAPI device", activateRes);
+    }
+
+    iunknown->QueryInterface(IID_PPV_ARGS(&_this->hidden->client));
+    if (!_this->hidden->client) {
+        return SDL_SetError("Failed to query WASAPI client interface");
+    }
+
+    if (WASAPI_PrepDevice(_this, isrecovery) == -1) {
+        return -1;
+    }
+
+    return 0;
+}
+
+void
+WASAPI_PlatformThreadInit(_THIS)
+{
+    // !!! FIXME: set this thread to "Pro Audio" priority.
+}
+
+void
+WASAPI_PlatformThreadDeinit(_THIS)
+{
+    // !!! FIXME: set this thread to "Pro Audio" priority.
+}
+
+/* Everything below was copied from SDL_wasapi.c, before it got moved to SDL_immdevice.c! */
+
+static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+
+extern "C" SDL_AudioFormat
+WaveFormatToSDLFormat(WAVEFORMATEX *waveformat)
+{
+    if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
+        return AUDIO_F32SYS;
+    } else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
+        return AUDIO_S16SYS;
+    } else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
+        return AUDIO_S32SYS;
+    } else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
+        const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *)waveformat;
+        if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
+            return AUDIO_F32SYS;
+        } else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
+            return AUDIO_S16SYS;
+        } else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
+            return AUDIO_S32SYS;
+        }
+    }
+    return 0;
+}
+
+static void
+WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
+{
+    DevIdList *i;
+    DevIdList *next;
+    DevIdList *prev = NULL;
+    for (i = deviceid_list; i; i = next) {
+        next = i->next;
+        if (SDL_wcscmp(i->str, devid) == 0) {
+            if (prev) {
+                prev->next = next;
+            }
+            else {
+                deviceid_list = next;
+            }
+            SDL_RemoveAudioDevice(iscapture, i->str);
+            SDL_free(i->str);
+            SDL_free(i);
+        } else {
+            prev = i;
+        }
+    }
+}
+
+static void
+WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid)
+{
+    DevIdList *devidlist;
+    SDL_AudioSpec spec;
+
+    /* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
+       In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
+       phones and tablets, where you might have an internal speaker and a headphone jack and expect both to be
+       available and switch automatically. (!!! FIXME...?) */
+
+       /* see if we already have this one. */
+    for (devidlist = deviceid_list; devidlist; devidlist = devidlist->next) {
+        if (SDL_wcscmp(devidlist->str, devid) == 0) {
+            return;  /* we already have this. */
+        }
+    }
+
+    devidlist = (DevIdList *)SDL_malloc(sizeof(*devidlist));
+    if (!devidlist) {
+        return;  /* oh well. */
+    }
+
+    devid = SDL_wcsdup(devid);
+    if (!devid) {
+        SDL_free(devidlist);
+        return;  /* oh well. */
+    }
+
+    devidlist->str = (WCHAR *)devid;
+    devidlist->next = deviceid_list;
+    deviceid_list = devidlist;
+
+    SDL_zero(spec);
+    spec.channels = (Uint8)fmt->Format.nChannels;
+    spec.freq = fmt->Format.nSamplesPerSec;
+    spec.format = WaveFormatToSDLFormat((WAVEFORMATEX *)fmt);
+    SDL_AddAudioDevice(iscapture, devname, &spec, (void *)devid);
+}
+
+#endif  // SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 4 - 0
src/core/windows/SDL_hid.c

@@ -20,6 +20,8 @@
 */
 #include "../../SDL_internal.h"
 
+#ifndef __WINRT__
+
 #include "SDL_hid.h"
 
 
@@ -83,4 +85,6 @@ WIN_UnloadHIDDLL(void)
     }
 }
 
+#endif /* !__WINRT__ */
+
 /* vi: set ts=4 sw=4 expandtab: */

+ 4 - 0
src/core/windows/SDL_hid.h

@@ -25,6 +25,8 @@
 
 #include "SDL_windows.h"
 
+#ifndef __WINRT__
+
 typedef LONG NTSTATUS;
 typedef USHORT USAGE;
 typedef struct _HIDP_PREPARSED_DATA *PHIDP_PREPARSED_DATA;
@@ -195,6 +197,8 @@ extern HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
 extern HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
 extern HidP_GetData_t SDL_HidP_GetData;
 
+#endif /* !__WINRT__ */
+
 #endif /* SDL_hid_h_ */
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 27 - 10
src/core/windows/SDL_windows.c

@@ -20,7 +20,7 @@
 */
 #include "../../SDL_internal.h"
 
-#if defined(__WIN32__) || defined(__GDK__)
+#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
 
 #include "SDL_windows.h"
 #include "SDL_error.h"
@@ -89,7 +89,14 @@ WIN_CoInitialize(void)
 
        If you need multi-threaded mode, call CoInitializeEx() before SDL_Init()
     */
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#ifdef __WINRT__
+    /* DLudwig: On WinRT, it is assumed that COM was initialized in main().
+       CoInitializeEx is available (not CoInitialize though), however
+       on WinRT, main() is typically declared with the [MTAThread]
+       attribute, which, AFAIK, should initialize COM.
+    */
+    return S_OK;
+#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
     /* On Xbox, there's no need to call CoInitializeEx (and it's not implemented) */
     return S_OK;
 #else
@@ -111,9 +118,12 @@ WIN_CoInitialize(void)
 void
 WIN_CoUninitialize(void)
 {
+#ifndef __WINRT__
     CoUninitialize();
+#endif
 }
 
+#ifndef __WINRT__
 void *
 WIN_LoadComBaseFunction(const char *name)
 {
@@ -130,10 +140,14 @@ WIN_LoadComBaseFunction(const char *name)
         return NULL;
     }
 }
+#endif
 
 HRESULT
 WIN_RoInitialize(void)
 {
+#ifdef __WINRT__
+    return S_OK;
+#else
     typedef HRESULT (WINAPI *RoInitialize_t)(RO_INIT_TYPE initType);
     RoInitialize_t RoInitializeFunc = (RoInitialize_t)WIN_LoadComBaseFunction("RoInitialize");
     if (RoInitializeFunc) {
@@ -153,19 +167,22 @@ WIN_RoInitialize(void)
     } else {
         return E_NOINTERFACE;
     }
+#endif
 }
 
 void
 WIN_RoUninitialize(void)
 {
+#ifndef __WINRT__
     typedef void (WINAPI *RoUninitialize_t)(void);
     RoUninitialize_t RoUninitializeFunc = (RoUninitialize_t)WIN_LoadComBaseFunction("RoUninitialize");
     if (RoUninitializeFunc) {
         RoUninitializeFunc();
     }
+#endif
 }
 
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
 static BOOL
 IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
 {
@@ -189,7 +206,7 @@ IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServiceP
 
 BOOL WIN_IsWindowsVistaOrGreater(void)
 {
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
     return TRUE;
 #else
     return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
@@ -198,7 +215,7 @@ BOOL WIN_IsWindowsVistaOrGreater(void)
 
 BOOL WIN_IsWindows7OrGreater(void)
 {
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
     return TRUE;
 #else
     return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
@@ -207,7 +224,7 @@ BOOL WIN_IsWindows7OrGreater(void)
 
 BOOL WIN_IsWindows8OrGreater(void)
 {
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
     return TRUE;
 #else
     return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
@@ -238,8 +255,8 @@ WASAPI doesn't need this. This is just for DirectSound/WinMM.
 char *
 WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
 {
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
-    return WIN_StringToUTF8(name);  /* No registry access on Xbox, go with what we've got. */
+#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
+    return WIN_StringToUTF8(name);  /* No registry access on WinRT/UWP and Xbox, go with what we've got. */
 #else
     static const GUID nullguid = { 0 };
     const unsigned char *ptr;
@@ -291,7 +308,7 @@ WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
     retval = WIN_StringToUTF8(strw);
     SDL_free(strw);
     return retval ? retval : WIN_StringToUTF8(name);
-#endif /**/
+#endif /* if __WINRT__ / else */
 }
 
 BOOL
@@ -324,6 +341,6 @@ WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect)
     winrect->bottom = sdlrect->y + sdlrect->h - 1;
 }
 
-#endif /* defined(__WIN32__) || defined(__GDK__) */
+#endif /* defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__) */
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 2 - 0
src/core/windows/SDL_windows.h

@@ -120,8 +120,10 @@ extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
 /* Sets an error message based on GetLastError(). Always return -1. */
 extern int WIN_SetError(const char *prefix);
 
+#if !defined(__WINRT__)
 /* Load a function from combase.dll */
 void *WIN_LoadComBaseFunction(const char *name);
+#endif
 
 /* Wrap up the oddities of CoInitialize() into a common function. */
 extern HRESULT WIN_CoInitialize(void);

+ 3 - 3
src/core/windows/SDL_xinput.c

@@ -37,7 +37,7 @@ static HANDLE s_pXInputDLL = 0;
 static int s_XInputDLLRefCount = 0;
 
 
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#if defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
 
 int
 WIN_LoadXInputDLL(void)
@@ -70,7 +70,7 @@ WIN_UnloadXInputDLL(void)
 {
 }
 
-#else /* !(defined(__XBOXONE__) || defined(__XBOXSERIES__)) */
+#else /* !(defined(__WINRT__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)) */
 
 int
 WIN_LoadXInputDLL(void)
@@ -138,7 +138,7 @@ WIN_UnloadXInputDLL(void)
     }
 }
 
-#endif /**/
+#endif /* __WINRT__ */
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus

+ 67 - 0
src/core/winrt/SDL_winrtapp_common.cpp

@@ -0,0 +1,67 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#include "SDL_main.h"
+#include "SDL_system.h"
+#include "SDL_winrtapp_direct3d.h"
+#include "SDL_winrtapp_xaml.h"
+
+#include <wrl.h>
+
+int (*WINRT_SDLAppEntryPoint)(int, char **) = NULL;
+
+extern "C" DECLSPEC int
+SDL_WinRTRunApp(SDL_main_func mainFunction, void * xamlBackgroundPanel)
+{
+    if (xamlBackgroundPanel) {
+        return SDL_WinRTInitXAMLApp(mainFunction, xamlBackgroundPanel);
+    } else {
+        if (FAILED(Windows::Foundation::Initialize(RO_INIT_MULTITHREADED))) {
+            return 1;
+        }
+        return SDL_WinRTInitNonXAMLApp(mainFunction);
+    }
+}
+
+
+extern "C" DECLSPEC SDL_WinRT_DeviceFamily
+SDL_WinRTGetDeviceFamily()
+{
+#if NTDDI_VERSION >= NTDDI_WIN10  /* !!! FIXME: I have no idea if this is the right test. This is a UWP API, I think. Older windows should...just return "mobile"? I don't know. --ryan. */
+    Platform::String^ deviceFamily = Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamily;
+
+    if (deviceFamily->Equals("Windows.Desktop"))
+    {
+        return SDL_WINRT_DEVICEFAMILY_DESKTOP;
+    }
+    else if (deviceFamily->Equals("Windows.Mobile"))
+    {
+        return SDL_WINRT_DEVICEFAMILY_MOBILE;
+    }
+    else if (deviceFamily->Equals("Windows.Xbox"))
+    {
+        return SDL_WINRT_DEVICEFAMILY_XBOX;
+    }
+#endif
+
+    return SDL_WINRT_DEVICEFAMILY_UNKNOWN;
+}

+ 31 - 0
src/core/winrt/SDL_winrtapp_common.h

@@ -0,0 +1,31 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_winrtapp_common_h_
+#define SDL_winrtapp_common_h_
+
+/* A pointer to the app's C-style main() function (which is a different
+   function than the WinRT app's actual entry point).
+ */
+extern int (*WINRT_SDLAppEntryPoint)(int, char **);
+
+#endif // SDL_winrtapp_common_h_

+ 797 - 0
src/core/winrt/SDL_winrtapp_direct3d.cpp

@@ -0,0 +1,797 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+/* Standard C++11 includes */
+#include <functional>
+#include <string>
+#include <sstream>
+using namespace std;
+
+
+/* Windows includes */
+#include "ppltasks.h"
+using namespace concurrency;
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::Devices::Input;
+using namespace Windows::Graphics::Display;
+using namespace Windows::Foundation;
+using namespace Windows::System;
+using namespace Windows::UI::Core;
+using namespace Windows::UI::Input;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+using namespace Windows::Phone::UI::Input;
+#endif
+
+
+/* SDL includes */
+extern "C" {
+#include "SDL_events.h"
+#include "SDL_hints.h"
+#include "SDL_main.h"
+#include "SDL_stdinc.h"
+#include "SDL_render.h"
+#include "../../video/SDL_sysvideo.h"
+//#include "../../SDL_hints_c.h"
+#include "../../events/SDL_events_c.h"
+#include "../../events/SDL_keyboard_c.h"
+#include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_windowevents_c.h"
+#include "../../render/SDL_sysrender.h"
+#include "../windows/SDL_windows.h"
+}
+
+#include "../../video/winrt/SDL_winrtevents_c.h"
+#include "../../video/winrt/SDL_winrtvideo_cpp.h"
+#include "SDL_winrtapp_common.h"
+#include "SDL_winrtapp_direct3d.h"
+
+#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
+/* Calling IDXGIDevice3::Trim on the active Direct3D 11.x device is necessary
+ * when Windows 8.1 apps are about to get suspended.
+ */
+extern "C" void D3D11_Trim(SDL_Renderer *);
+#endif
+
+
+// Compile-time debugging options:
+// To enable, uncomment; to disable, comment them out.
+//#define LOG_POINTER_EVENTS 1
+//#define LOG_WINDOW_EVENTS 1
+//#define LOG_ORIENTATION_EVENTS 1
+
+
+// HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
+// SDL/WinRT will use this throughout its code.
+//
+// TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
+// non-global, such as something created inside
+// SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
+// SDL_CreateWindow().
+SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
+
+ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
+{
+public:
+    virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
+};
+
+IFrameworkView^ SDLApplicationSource::CreateView()
+{
+    // TODO, WinRT: see if this function (CreateView) can ever get called
+    // more than once.  For now, just prevent it from ever assigning
+    // SDL_WinRTGlobalApp more than once.
+    SDL_assert(!SDL_WinRTGlobalApp);
+    SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
+    if (!SDL_WinRTGlobalApp)
+    {
+        SDL_WinRTGlobalApp = app;
+    }
+    return app;
+}
+
+int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **))
+{
+    WINRT_SDLAppEntryPoint = mainFunction;
+    auto direct3DApplicationSource = ref new SDLApplicationSource();
+    CoreApplication::Run(direct3DApplicationSource);
+    return 0;
+}
+
+static void
+WINRT_ProcessWindowSizeChange() // TODO: Pass an SDL_Window-identifying thing into WINRT_ProcessWindowSizeChange()
+{
+    CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
+    if (coreWindow) {
+        if (WINRT_GlobalSDLWindow) {
+            SDL_Window * window = WINRT_GlobalSDLWindow;
+            SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
+
+            int x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
+            int y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
+            int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
+            int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
+
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
+            /* WinPhone 8.0 always keeps its native window size in portrait,
+               regardless of orientation.  This changes in WinPhone 8.1,
+               in which the native window's size changes along with
+               orientation.
+
+               Attempt to emulate WinPhone 8.1's behavior on WinPhone 8.0, with
+               regards to window size.  This fixes a rendering bug that occurs
+               when a WinPhone 8.0 app is rotated to either 90 or 270 degrees.
+            */
+            const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
+            switch (currentOrientation) {
+                case DisplayOrientations::Landscape:
+                case DisplayOrientations::LandscapeFlipped: {
+                    int tmp = w;
+                    w = h;
+                    h = tmp;
+                } break;
+            }
+#endif
+
+            const Uint32 latestFlags = WINRT_DetectWindowFlags(window);
+            if (latestFlags & SDL_WINDOW_MAXIMIZED) {
+                SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
+            } else {
+                SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
+            }
+
+            WINRT_UpdateWindowFlags(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
+
+            /* The window can move during a resize event, such as when maximizing
+               or resizing from a corner */
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
+        }
+    }
+}
+
+SDL_WinRTApp::SDL_WinRTApp() :
+    m_windowClosed(false),
+    m_windowVisible(true)
+{
+}
+
+void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
+{
+    applicationView->Activated +=
+        ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnAppActivated);
+
+    CoreApplication::Suspending +=
+        ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
+
+    CoreApplication::Resuming +=
+        ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
+
+    CoreApplication::Exiting +=
+        ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+    /* HACK ALERT!  Xbox One doesn't seem to detect gamepads unless something
+       gets registered to receive Win10's Windows.Gaming.Input.Gamepad.GamepadAdded
+       events.  We'll register an event handler for these events here, to make
+       sure that gamepad detection works later on, if requested.
+    */
+    Windows::Gaming::Input::Gamepad::GamepadAdded +=
+        ref new Windows::Foundation::EventHandler<Windows::Gaming::Input::Gamepad^>(
+            this, &SDL_WinRTApp::OnGamepadAdded
+        );
+#endif
+}
+
+#if NTDDI_VERSION > NTDDI_WIN8
+void SDL_WinRTApp::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
+#else
+void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
+#endif
+{
+#if LOG_ORIENTATION_EVENTS==1
+    {
+        CoreWindow^ window = CoreWindow::GetForCurrentThread();
+        if (window) {
+            SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Bounds={%f,%f,%f,%f}\n",
+                __FUNCTION__,
+                WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+                WINRT_DISPLAY_PROPERTY(NativeOrientation),
+                WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
+                window->Bounds.X,
+                window->Bounds.Y,
+                window->Bounds.Width,
+                window->Bounds.Height);
+        } else {
+            SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
+                __FUNCTION__,
+                WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+                WINRT_DISPLAY_PROPERTY(NativeOrientation),
+                WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
+        }
+    }
+#endif
+
+    WINRT_ProcessWindowSizeChange();
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    // HACK: Make sure that orientation changes
+    // lead to the Direct3D renderer's viewport getting updated:
+    //
+    // For some reason, this doesn't seem to need to be done on Windows 8.x,
+    // even when going from Landscape to LandscapeFlipped.  It only seems to
+    // be needed on Windows Phone, at least when I tested on my devices.
+    // I'm not currently sure why this is, but it seems to work fine. -- David L.
+    //
+    // TODO, WinRT: do more extensive research into why orientation changes on Win 8.x don't need D3D changes, or if they might, in some cases
+    SDL_Window * window = WINRT_GlobalSDLWindow;
+    if (window) {
+        SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
+        int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
+        int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
+        SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SIZE_CHANGED, w, h);
+    }
+#endif
+
+}
+
+void SDL_WinRTApp::SetWindow(CoreWindow^ window)
+{
+#if LOG_WINDOW_EVENTS==1
+    SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window bounds={%f, %f, %f,%f}\n",
+        __FUNCTION__,
+        WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+        WINRT_DISPLAY_PROPERTY(NativeOrientation),
+        WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
+        window->Bounds.X,
+        window->Bounds.Y,
+        window->Bounds.Width,
+        window->Bounds.Height);
+#endif
+
+    window->SizeChanged += 
+        ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
+
+    window->VisibilityChanged +=
+        ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
+
+    window->Activated +=
+        ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &SDL_WinRTApp::OnWindowActivated);
+
+    window->Closed += 
+        ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+    window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
+#endif
+
+    window->PointerPressed +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
+
+    window->PointerMoved +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
+
+    window->PointerReleased +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
+
+    window->PointerEntered +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerEntered);
+
+    window->PointerExited +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerExited);
+
+    window->PointerWheelChanged +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+    // Retrieves relative-only mouse movements:
+    Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
+        ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
+#endif
+
+    window->KeyDown +=
+        ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
+
+    window->KeyUp +=
+        ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
+
+    window->CharacterReceived +=
+        ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &SDL_WinRTApp::OnCharacterReceived);
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+    Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->BackRequested +=
+        ref new EventHandler<BackRequestedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
+#elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    HardwareButtons::BackPressed +=
+        ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
+#endif
+
+#if NTDDI_VERSION > NTDDI_WIN8
+    DisplayInformation::GetForCurrentView()->OrientationChanged +=
+        ref new TypedEventHandler<Windows::Graphics::Display::DisplayInformation^, Object^>(this, &SDL_WinRTApp::OnOrientationChanged);
+#else
+    DisplayProperties::OrientationChanged +=
+        ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
+#endif
+
+#if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)  // for Windows 8/8.1/RT apps... (and not Phone apps)
+    // Make sure we know when a user has opened the app's settings pane.
+    // This is needed in order to display a privacy policy, which needs
+    // to be done for network-enabled apps, as per Windows Store requirements.
+    using namespace Windows::UI::ApplicationSettings;
+    SettingsPane::GetForCurrentView()->CommandsRequested +=
+        ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^>
+            (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested);
+#endif
+}
+
+void SDL_WinRTApp::Load(Platform::String^ entryPoint)
+{
+}
+
+void SDL_WinRTApp::Run()
+{
+    SDL_SetMainReady();
+    if (WINRT_SDLAppEntryPoint)
+    {
+        // TODO, WinRT: pass the C-style main() a reasonably realistic
+        // representation of command line arguments.
+        int argc = 1;
+        char **argv = (char **)SDL_malloc(2 * sizeof(*argv));
+        if (!argv) {
+            return;
+        }
+        argv[0] = SDL_strdup("WinRTApp");
+        argv[1] = NULL;
+        WINRT_SDLAppEntryPoint(argc, argv);
+        SDL_free(argv[0]);
+        SDL_free(argv);
+    }
+}
+
+static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
+{
+    SDL_Event events[128];
+    const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
+    for (int i = 0; i < count; ++i) {
+        if (events[i].window.event == windowEventID) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
+{
+    /* Don't wait if the app is visible: */
+    if (m_windowVisible) {
+        return false;
+    }
+    
+    /* Don't wait until the window-hide events finish processing.
+     * Do note that if an app-suspend event is sent (as indicated
+     * by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
+     * events), then this code may be a moot point, as WinRT's
+     * own event pump (aka ProcessEvents()) will pause regardless
+     * of what we do here.  This happens on Windows Phone 8, to note.
+     * Windows 8.x apps, on the other hand, may get a chance to run
+     * these.
+     */
+    if (IsSDLWindowEventPending(SDL_WINDOWEVENT_HIDDEN)) {
+        return false;
+    } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_FOCUS_LOST)) {
+        return false;
+    } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_MINIMIZED)) {
+        return false;
+    }
+
+    return true;
+}
+
+void SDL_WinRTApp::PumpEvents()
+{
+    if (!m_windowClosed) {
+        if (!ShouldWaitForAppResumeEvents()) {
+            /* This is the normal way in which events should be pumped.
+             * 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
+             * from zero to N events, and will then return.
+             */
+            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
+        } else {
+            /* This style of event-pumping, with 'ProcessOneAndAllPending',
+             * will cause anywhere from one to N events to be processed.  If
+             * at least one event is processed, the call will return.  If
+             * no events are pending, then the call will wait until one is
+             * available, and will not return (to the caller) until this
+             * happens!  This should only occur when the app is hidden.
+             */
+            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
+        }
+    }
+}
+
+void SDL_WinRTApp::Uninitialize()
+{
+}
+
+#if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
+void SDL_WinRTApp::OnSettingsPaneCommandsRequested(
+    Windows::UI::ApplicationSettings::SettingsPane ^p,
+    Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args)
+{
+    using namespace Platform;
+    using namespace Windows::UI::ApplicationSettings;
+    using namespace Windows::UI::Popups;
+
+    String ^privacyPolicyURL = nullptr;     // a URL to an app's Privacy Policy
+    String ^privacyPolicyLabel = nullptr;   // label/link text
+    const char *tmpHintValue = NULL;        // SDL_GetHint-retrieved value, used immediately
+    wchar_t *tmpStr = NULL;                 // used for UTF8 to UCS2 conversion
+
+    // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint):
+    tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL);
+    if (tmpHintValue && tmpHintValue[0] != '\0') {
+        // Convert the privacy policy's URL to UCS2:
+        tmpStr = WIN_UTF8ToString(tmpHintValue);
+        privacyPolicyURL = ref new String(tmpStr);
+        SDL_free(tmpStr);
+
+        // Optionally retrieve custom label-text for the link.  If this isn't
+        // available, a default value will be used instead.
+        tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL);
+        if (tmpHintValue && tmpHintValue[0] != '\0') {
+            tmpStr = WIN_UTF8ToString(tmpHintValue);
+            privacyPolicyLabel = ref new String(tmpStr);
+            SDL_free(tmpStr);
+        } else {
+            privacyPolicyLabel = ref new String(L"Privacy Policy");
+        }
+
+        // Register the link, along with a handler to be called if and when it is
+        // clicked:
+        auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel,
+            ref new UICommandInvokedHandler([=](IUICommand ^) {
+                Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL));
+        }));
+        args->Request->ApplicationCommands->Append(cmd);
+    }
+}
+#endif // if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
+
+void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+    SDL_Log("%s, size={%f,%f}, bounds={%f,%f,%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
+        __FUNCTION__,
+        args->Size.Width, args->Size.Height,
+        sender->Bounds.X, sender->Bounds.Y, sender->Bounds.Width, sender->Bounds.Height,
+        WINRT_DISPLAY_PROPERTY(CurrentOrientation),
+        WINRT_DISPLAY_PROPERTY(NativeOrientation),
+        WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
+        (WINRT_GlobalSDLWindow ? "yes" : "no"));
+#endif
+
+    WINRT_ProcessWindowSizeChange();
+}
+
+void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+    SDL_Log("%s, visible?=%s, bounds={%f,%f,%f,%f}, WINRT_GlobalSDLWindow?=%s\n",
+        __FUNCTION__,
+        (args->Visible ? "yes" : "no"),
+        sender->Bounds.X, sender->Bounds.Y,
+        sender->Bounds.Width, sender->Bounds.Height,
+        (WINRT_GlobalSDLWindow ? "yes" : "no"));
+#endif
+
+    m_windowVisible = args->Visible;
+    if (WINRT_GlobalSDLWindow) {
+        SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
+        Uint32 latestWindowFlags = WINRT_DetectWindowFlags(WINRT_GlobalSDLWindow);
+        if (args->Visible) {
+            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
+            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
+            if (latestWindowFlags & SDL_WINDOW_MAXIMIZED) {
+                SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
+            } else {
+                SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);
+            }
+        } else {
+            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
+            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
+            SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+        }
+
+        // HACK: Prevent SDL's window-hide handling code, which currently
+        // triggers a fake window resize (possibly erronously), from
+        // marking the SDL window's surface as invalid.
+        //
+        // A better solution to this probably involves figuring out if the
+        // fake window resize can be prevented.
+        WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
+    }
+}
+
+void SDL_WinRTApp::OnWindowActivated(CoreWindow^ sender, WindowActivatedEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+    SDL_Log("%s, WINRT_GlobalSDLWindow?=%s\n\n",
+        __FUNCTION__,
+        (WINRT_GlobalSDLWindow ? "yes" : "no"));
+#endif
+
+    /* There's no property in Win 8.x to tell whether a window is active or
+       not.  [De]activation events are, however, sent to the app.  We'll just
+       record those, in case the CoreWindow gets wrapped by an SDL_Window at
+       some future time.
+    */
+    sender->CustomProperties->Insert("SDLHelperWindowActivationState", args->WindowActivationState);
+
+    SDL_Window * window = WINRT_GlobalSDLWindow;
+    if (window) {
+        if (args->WindowActivationState != CoreWindowActivationState::Deactivated) {
+            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
+            if (SDL_GetKeyboardFocus() != window) {
+                SDL_SetKeyboardFocus(window);
+            }
+        
+            /* Send a mouse-motion event as appropriate.
+               This doesn't work when called from OnPointerEntered, at least
+               not in WinRT CoreWindow apps (as OnPointerEntered doesn't
+               appear to be called after window-reactivation, at least not
+               in Windows 10, Build 10586.3 (November 2015 update, non-beta).
+
+               Don't do it on WinPhone 8.0 though, as CoreWindow's 'PointerPosition'
+               property isn't available.
+             */
+#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION >= NTDDI_WINBLUE)
+            Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize);
+            SDL_SendMouseMotion(window, 0, 0, (int)cursorPos.X, (int)cursorPos.Y);
+#endif
+
+            /* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */
+            //WIN_CheckAsyncMouseRelease(data);
+
+            /* TODO, WinRT: implement clipboard support, if possible */
+            ///*
+            // * FIXME: Update keyboard state
+            // */
+            //WIN_CheckClipboardUpdate(data->videodata);
+
+            // HACK: Resetting the mouse-cursor here seems to fix
+            // https://bugzilla.libsdl.org/show_bug.cgi?id=3217, whereby a
+            // WinRT app's mouse cursor may switch to Windows' 'wait' cursor,
+            // after a user alt-tabs back into a full-screened SDL app.
+            // This bug does not appear to reproduce 100% of the time.
+            // It may be a bug in Windows itself (v.10.0.586.36, as tested,
+            // and the most-recent as of this writing).
+            SDL_SetCursor(NULL);
+        } else {
+            if (SDL_GetKeyboardFocus() == window) {
+                SDL_SetKeyboardFocus(NULL);
+            }
+        }
+    }
+}
+
+void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+    SDL_Log("%s\n", __FUNCTION__);
+#endif
+    m_windowClosed = true;
+}
+
+void SDL_WinRTApp::OnAppActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
+{
+    CoreWindow::GetForCurrentThread()->Activate();
+}
+
+void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
+{
+    // Save app state asynchronously after requesting a deferral. Holding a deferral
+    // indicates that the application is busy performing suspending operations. Be
+    // aware that a deferral may not be held indefinitely. After about five seconds,
+    // the app will be forced to exit.
+
+    // ... but first, let the app know it's about to go to the background.
+    // The separation of events may be important, given that the deferral
+    // runs in a separate thread.  This'll make SDL_APP_WILLENTERBACKGROUND
+    // the only event among the two that runs in the main thread.  Given
+    // that a few WinRT operations can only be done from the main thread
+    // (things that access the WinRT CoreWindow are one example of this),
+    // this could be important.
+    SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
+
+    SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
+    create_task([this, deferral]()
+    {
+        // Send an app did-enter-background event immediately to observers.
+        // CoreDispatcher::ProcessEvents, which is the backbone on which
+        // SDL_WinRTApp::PumpEvents is built, will not return to its caller
+        // once it sends out a suspend event.  Any events posted to SDL's
+        // event queue won't get received until the WinRT app is resumed.
+        // SDL_AddEventWatch() may be used to receive app-suspend events on
+        // WinRT.
+        SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
+
+        // Let the Direct3D 11 renderer prepare for the app to be backgrounded.
+        // This is necessary for Windows 8.1, possibly elsewhere in the future.
+        // More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx
+#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
+        if (WINRT_GlobalSDLWindow) {
+            SDL_Renderer * renderer = SDL_GetRenderer(WINRT_GlobalSDLWindow);
+            if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) {
+                D3D11_Trim(renderer);
+            }
+        }
+#endif
+
+        deferral->Complete();
+    });
+}
+
+void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
+{
+    // Restore any data or state that was unloaded on suspend. By default, data
+    // and state are persisted when resuming from suspend. Note that these events
+    // do not occur if the app was previously terminated.
+    SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
+    SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
+}
+
+void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
+{
+    SDL_SendAppEvent(SDL_APP_TERMINATING);
+}
+
+static void
+WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
+{
+    Uint8 button, pressed;
+    Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint;
+    WINRT_GetSDLButtonForPointerPoint(pt, &button, &pressed);
+    SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d pressed=%d\n",
+        header,
+        pt->Position.X, pt->Position.Y,
+        transformedPoint.X, transformedPoint.Y,
+        pt->Properties->MouseWheelDelta,
+        pt->FrameId,
+        pt->PointerId,
+        button,
+        pressed);
+}
+
+void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+    WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
+#endif
+
+    WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
+}
+
+void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+    WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
+#endif
+
+    WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
+}
+
+void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+    WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
+#endif
+    
+    WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
+}
+
+void SDL_WinRTApp::OnPointerEntered(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+    WINRT_LogPointerEvent("pointer entered", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
+#endif
+
+    WINRT_ProcessPointerEnteredEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
+}
+
+void SDL_WinRTApp::OnPointerExited(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+    WINRT_LogPointerEvent("pointer exited", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
+#endif
+
+    WINRT_ProcessPointerExitedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
+}
+
+void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+    WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
+#endif
+
+    WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
+}
+
+void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
+{
+    WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
+}
+
+void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
+{
+    WINRT_ProcessKeyDownEvent(args);
+}
+
+void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
+{
+    WINRT_ProcessKeyUpEvent(args);
+}
+
+void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args)
+{
+    WINRT_ProcessCharacterReceivedEvent(args);
+}
+
+template <typename BackButtonEventArgs>
+static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
+{
+    SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK);
+    SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK);
+
+    if (SDL_GetHintBoolean(SDL_HINT_WINRT_HANDLE_BACK_BUTTON, SDL_FALSE)) {
+        args->Handled = true;
+    }
+}
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ args)
+
+{
+    WINRT_OnBackButtonPressed(args);
+}
+#elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args)
+
+{
+    WINRT_OnBackButtonPressed(args);
+}
+#endif
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+void SDL_WinRTApp::OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad)
+{
+    /* HACK ALERT: Nothing needs to be done here, as this method currently
+       only exists to allow something to be registered with Win10's
+       GamepadAdded event, an operation that seems to be necessary to get
+       Xinput-based detection to work on Xbox One.
+    */
+}
+#endif
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 92 - 0
src/core/winrt/SDL_winrtapp_direct3d.h

@@ -0,0 +1,92 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include <Windows.h>
+
+extern int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **));
+
+ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFrameworkView
+{
+public:
+    SDL_WinRTApp();
+    
+    // IFrameworkView Methods.
+    virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
+    virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
+    virtual void Load(Platform::String^ entryPoint);
+    virtual void Run();
+    virtual void Uninitialize();
+
+internal:
+    // SDL-specific methods
+    void PumpEvents();
+
+protected:
+    bool ShouldWaitForAppResumeEvents();
+
+    // Event Handlers.
+
+#if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)  // for Windows 8/8.1/RT apps... (and not Phone apps)
+    void OnSettingsPaneCommandsRequested(
+        Windows::UI::ApplicationSettings::SettingsPane ^p,
+        Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args);
+#endif // if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
+
+#if NTDDI_VERSION > NTDDI_WIN8
+    void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
+#else
+    void OnOrientationChanged(Platform::Object^ sender);
+#endif
+    void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
+    void OnLogicalDpiChanged(Platform::Object^ sender);
+    void OnAppActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
+    void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
+    void OnResuming(Platform::Object^ sender, Platform::Object^ args);
+    void OnExiting(Platform::Object^ sender, Platform::Object^ args);
+    void OnWindowActivated(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowActivatedEventArgs^ args);
+    void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
+    void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
+    void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+    void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+    void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+    void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+    void OnPointerEntered(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+    void OnPointerExited(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+    void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args);
+    void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
+    void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
+    void OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args);
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+    void OnBackButtonPressed(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ args);
+#elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
+#endif
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+    void OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad);
+#endif
+
+private:
+    bool m_windowClosed;
+    bool m_windowVisible;
+};
+
+extern SDL_WinRTApp ^ SDL_WinRTGlobalApp;

+ 160 - 0
src/core/winrt/SDL_winrtapp_xaml.cpp

@@ -0,0 +1,160 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* Windows includes */
+#include <agile.h>
+#include <Windows.h>
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+#include <windows.ui.xaml.media.dxinterop.h>
+#endif
+
+
+/* SDL includes */
+#include "../../SDL_internal.h"
+#include "SDL.h"
+#include "../../video/winrt/SDL_winrtevents_c.h"
+#include "../../video/winrt/SDL_winrtvideo_cpp.h"
+#include "SDL_winrtapp_common.h"
+#include "SDL_winrtapp_xaml.h"
+
+
+
+/* SDL-internal globals: */
+SDL_bool WINRT_XAMLWasEnabled = SDL_FALSE;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+extern "C"
+ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative = NULL;
+static Windows::Foundation::EventRegistrationToken  WINRT_XAMLAppEventToken;
+#endif
+
+
+/*
+ * Input event handlers (XAML)
+ */
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+
+static void
+WINRT_OnPointerPressedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
+{
+    WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
+}
+
+static void
+WINRT_OnPointerMovedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
+{
+    WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
+}
+
+static void
+WINRT_OnPointerReleasedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
+{
+    WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
+}
+
+static void
+WINRT_OnPointerWheelChangedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
+{
+    WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
+}
+
+#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP
+
+
+/*
+ * XAML-to-SDL Rendering Callback
+ */
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+
+static void
+WINRT_OnRenderViaXAML(_In_ Platform::Object^ sender, _In_ Platform::Object^ args)
+{
+    WINRT_CycleXAMLThread();
+}
+
+#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP
+
+
+/*
+ * SDL + XAML Initialization
+ */
+
+int
+SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAsIInspectable)
+{
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    return SDL_SetError("XAML support is not yet available in Windows Phone.");
+#else
+    // Declare C++/CX namespaces:
+    using namespace Platform;
+    using namespace Windows::Foundation;
+    using namespace Windows::UI::Core;
+    using namespace Windows::UI::Xaml;
+    using namespace Windows::UI::Xaml::Controls;
+    using namespace Windows::UI::Xaml::Input;
+    using namespace Windows::UI::Xaml::Media;
+
+    // Make sure we have a valid XAML element (to draw onto):
+    if ( ! backgroundPanelAsIInspectable) {
+        return SDL_InvalidParamError("backgroundPanelAsIInspectable");
+    }
+
+    Platform::Object ^ backgroundPanel = reinterpret_cast<Object ^>((IInspectable *) backgroundPanelAsIInspectable);
+    SwapChainBackgroundPanel ^swapChainBackgroundPanel = dynamic_cast<SwapChainBackgroundPanel ^>(backgroundPanel);
+    if ( ! swapChainBackgroundPanel) {
+        return SDL_SetError("An unknown or unsupported type of XAML control was specified.");
+    }
+
+    // Setup event handlers:
+    swapChainBackgroundPanel->PointerPressed += ref new PointerEventHandler(WINRT_OnPointerPressedViaXAML);
+    swapChainBackgroundPanel->PointerReleased += ref new PointerEventHandler(WINRT_OnPointerReleasedViaXAML);
+    swapChainBackgroundPanel->PointerWheelChanged += ref new PointerEventHandler(WINRT_OnPointerWheelChangedViaXAML);
+    swapChainBackgroundPanel->PointerMoved += ref new PointerEventHandler(WINRT_OnPointerMovedViaXAML);
+
+    // Setup for rendering:
+    IInspectable *panelInspectable = (IInspectable*) reinterpret_cast<IInspectable*>(swapChainBackgroundPanel);
+    panelInspectable->QueryInterface(__uuidof(ISwapChainBackgroundPanelNative), (void **)&WINRT_GlobalSwapChainBackgroundPanelNative);
+
+    WINRT_XAMLAppEventToken = CompositionTarget::Rendering::add(ref new EventHandler<Object^>(WINRT_OnRenderViaXAML));
+
+    // Make sure the app is ready to call the SDL-centric main() function:
+    WINRT_SDLAppEntryPoint = mainFunction;
+    SDL_SetMainReady();
+
+    // Make sure video-init knows that we're initializing XAML:
+    SDL_bool oldXAMLWasEnabledValue = WINRT_XAMLWasEnabled;
+    WINRT_XAMLWasEnabled = SDL_TRUE;
+
+    // Make sure video modes are detected now, while we still have access to the WinRT
+    // CoreWindow.  WinRT will not allow the app's CoreWindow to be accessed via the
+    // SDL/WinRT thread.
+    if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
+        // SDL_InitSubSystem will, on error, set the SDL error.  Let that propogate to
+        // the caller to here:
+        WINRT_XAMLWasEnabled = oldXAMLWasEnabledValue;
+        return -1;
+    }
+
+    // All done, for now.
+    return 0;
+#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP  /  else
+}

+ 33 - 0
src/core/winrt/SDL_winrtapp_xaml.h

@@ -0,0 +1,33 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_winrtapp_xaml_h_
+#define SDL_winrtapp_xaml_h_
+
+#include "SDL_stdinc.h"
+
+#ifdef __cplusplus
+extern SDL_bool WINRT_XAMLWasEnabled;
+extern int SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAsIInspectable);
+#endif // ifdef __cplusplus
+
+#endif // SDL_winrtapp_xaml_h_

+ 2 - 2
src/cpuinfo/SDL_cpuinfo.c

@@ -24,7 +24,7 @@
 #include "../SDL_internal.h"
 #endif
 
-#if defined(__WIN32__) || defined(__GDK__)
+#if defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)
 #include "../core/windows/SDL_windows.h"
 #endif
 
@@ -444,7 +444,7 @@ CPU_haveNEON(void)
    query the OS kernel in a platform-specific way. :/ */
 #if defined(SDL_CPUINFO_DISABLED)
    return 0; /* disabled */
-#elif (defined(__WINDOWS__) || defined(__GDK__)) && (defined(_M_ARM) || defined(_M_ARM64))
+#elif (defined(__WINDOWS__) || defined(__WINRT__) || defined(__GDK__)) && (defined(_M_ARM) || defined(_M_ARM64))
 /* Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first. */
 /* Seems to have been removed */
 #  if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)

+ 2 - 0
src/dynapi/SDL_dynapi.h

@@ -49,6 +49,8 @@
 #define SDL_DYNAMIC_API 0
 #elif defined(__EMSCRIPTEN__) && __EMSCRIPTEN__  /* probably not useful on Emscripten. */
 #define SDL_DYNAMIC_API 0
+#elif defined(SDL_BUILDING_WINRT) && SDL_BUILDING_WINRT  /* probably not useful on WinRT, given current .dll loading restrictions */
+#define SDL_DYNAMIC_API 0
 #elif defined(__PS2__) && __PS2__
 #define SDL_DYNAMIC_API 0
 #elif defined(__PSP__) && __PSP__

+ 4 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -571,7 +571,10 @@
 #define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
 #define SDL_DXGIGetOutputInfo SDL_DXGIGetOutputInfo_REAL
 #define SDL_RenderIsClipEnabled SDL_RenderIsClipEnabled_REAL
+#define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
 #define SDL_WarpMouseGlobal SDL_WarpMouseGlobal_REAL
+#define SDL_WinRTGetFSPathUNICODE SDL_WinRTGetFSPathUNICODE_REAL
+#define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL
 #define SDL_sqrtf SDL_sqrtf_REAL
 #define SDL_tan SDL_tan_REAL
 #define SDL_tanf SDL_tanf_REAL
@@ -660,6 +663,7 @@
 #define SDL_RenderGetMetalLayer SDL_RenderGetMetalLayer_REAL
 #define SDL_RenderGetMetalCommandEncoder SDL_RenderGetMetalCommandEncoder_REAL
 #define SDL_IsAndroidTV SDL_IsAndroidTV_REAL
+#define SDL_WinRTGetDeviceFamily SDL_WinRTGetDeviceFamily_REAL
 #define SDL_log10 SDL_log10_REAL
 #define SDL_log10f SDL_log10f_REAL
 #define SDL_GameControllerMappingForDeviceIndex SDL_GameControllerMappingForDeviceIndex_REAL

+ 8 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -604,6 +604,11 @@ SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),retu
 SDL_DYNAPI_PROC(SDL_bool,SDL_DXGIGetOutputInfo,(int a,int *b, int *c),(a,b,c),return)
 #endif
 SDL_DYNAPI_PROC(SDL_bool,SDL_RenderIsClipEnabled,(SDL_Renderer *a),(a),return)
+#ifdef __WINRT__
+SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return)
+SDL_DYNAPI_PROC(const wchar_t*,SDL_WinRTGetFSPathUNICODE,(SDL_WinRT_Path a),(a),return)
+SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return)
+#endif
 SDL_DYNAPI_PROC(int,SDL_WarpMouseGlobal,(int a, int b),(a,b),return)
 SDL_DYNAPI_PROC(float,SDL_sqrtf,(float a),(a),return)
 SDL_DYNAPI_PROC(double,SDL_tan,(double a),(a),return)
@@ -695,6 +700,9 @@ SDL_DYNAPI_PROC(SDL_YUV_CONVERSION_MODE,SDL_GetYUVConversionMode,(void),(),retur
 SDL_DYNAPI_PROC(SDL_YUV_CONVERSION_MODE,SDL_GetYUVConversionModeForResolution,(int a, int b),(a,b),return)
 SDL_DYNAPI_PROC(void*,SDL_RenderGetMetalLayer,(SDL_Renderer *a),(a),return)
 SDL_DYNAPI_PROC(void*,SDL_RenderGetMetalCommandEncoder,(SDL_Renderer *a),(a),return)
+#ifdef __WINRT__
+SDL_DYNAPI_PROC(SDL_WinRT_DeviceFamily,SDL_WinRTGetDeviceFamily,(void),(),return)
+#endif
 #ifdef __ANDROID__
 SDL_DYNAPI_PROC(SDL_bool,SDL_IsAndroidTV,(void),(),return)
 #endif

+ 3 - 0
src/file/SDL_rwops.c

@@ -593,6 +593,9 @@ SDL_RWFromFile(const char *file, const char *mode)
     {
         #if __APPLE__ && !SDL_FILE_DISABLED // TODO: add dummy?
         FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
+        #elif __WINRT__
+        FILE *fp = NULL;
+        fopen_s(&fp, file, mode);
         #elif __3DS__
         FILE *fp = N3DS_FileOpen(file, mode);
         #else

+ 242 - 0
src/filesystem/winrt/SDL_sysfilesystem.cpp

@@ -0,0 +1,242 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+/* TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all
+*/
+
+#ifdef __WINRT__
+
+extern "C" {
+#include "SDL_filesystem.h"
+#include "SDL_error.h"
+#include "SDL_hints.h"
+#include "SDL_stdinc.h"
+#include "SDL_system.h"
+#include "../../core/windows/SDL_windows.h"
+}
+
+#include <string>
+#include <unordered_map>
+
+using namespace std;
+using namespace Windows::Storage;
+
+extern "C" const wchar_t *
+SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType)
+{
+    switch (pathType) {
+        case SDL_WINRT_PATH_INSTALLED_LOCATION:
+        {
+            static wstring path;
+            if (path.empty()) {
+#if defined(NTDDI_WIN10_19H1) && (NTDDI_VERSION >= NTDDI_WIN10_19H1) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) /* Only PC supports mods */
+                /* Windows 1903 supports mods, via the EffectiveLocation API */
+                if (Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8, 0)) {
+                    path = Windows::ApplicationModel::Package::Current->EffectiveLocation->Path->Data();
+                } else {
+                    path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
+                }
+#else
+                path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
+#endif
+            }
+            return path.c_str();
+        }
+
+        case SDL_WINRT_PATH_LOCAL_FOLDER:
+        {
+            static wstring path;
+            if (path.empty()) {
+                path = ApplicationData::Current->LocalFolder->Path->Data();
+            }
+            return path.c_str();
+        }
+
+#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
+        case SDL_WINRT_PATH_ROAMING_FOLDER:
+        {
+            static wstring path;
+            if (path.empty()) {
+                path = ApplicationData::Current->RoamingFolder->Path->Data();
+            }
+            return path.c_str();
+        }
+
+        case SDL_WINRT_PATH_TEMP_FOLDER:
+        {
+            static wstring path;
+            if (path.empty()) {
+                path = ApplicationData::Current->TemporaryFolder->Path->Data();
+            }
+            return path.c_str();
+        }
+#endif
+
+        default:
+            break;
+    }
+
+    SDL_Unsupported();
+    return NULL;
+}
+
+extern "C" const char *
+SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType)
+{
+    typedef unordered_map<SDL_WinRT_Path, string> UTF8PathMap;
+    static UTF8PathMap utf8Paths;
+
+    UTF8PathMap::iterator searchResult = utf8Paths.find(pathType);
+    if (searchResult != utf8Paths.end()) {
+        return searchResult->second.c_str();
+    }
+
+    const wchar_t * ucs2Path = SDL_WinRTGetFSPathUNICODE(pathType);
+    if (!ucs2Path) {
+        return NULL;
+    }
+
+    char * utf8Path = WIN_StringToUTF8(ucs2Path);
+    utf8Paths[pathType] = utf8Path;
+    SDL_free(utf8Path);
+    return utf8Paths[pathType].c_str();
+}
+
+extern "C" char *
+SDL_GetBasePath(void)
+{
+    const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_INSTALLED_LOCATION);
+    size_t destPathLen;
+    char * destPath = NULL;
+
+    if (!srcPath) {
+        SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError());
+        return NULL;
+    }
+
+    destPathLen = SDL_strlen(srcPath) + 2;
+    destPath = (char *) SDL_malloc(destPathLen);
+    if (!destPath) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    SDL_snprintf(destPath, destPathLen, "%s\\", srcPath);
+    return destPath;
+}
+
+extern "C" char *
+SDL_GetPrefPath(const char *org, const char *app)
+{
+    /* WinRT note: The 'SHGetFolderPath' API that is used in Windows 7 and
+     * earlier is not available on WinRT or Windows Phone.  WinRT provides
+     * a similar API, but SHGetFolderPath can't be called, at least not
+     * without violating Microsoft's app-store requirements.
+     */
+
+    const WCHAR * srcPath = NULL;
+    WCHAR path[MAX_PATH];
+    char *retval = NULL;
+    WCHAR* worg = NULL;
+    WCHAR* wapp = NULL;
+    size_t new_wpath_len = 0;
+    BOOL api_result = FALSE;
+
+    if (!app) {
+        SDL_InvalidParamError("app");
+        return NULL;
+    }
+    if (!org) {
+        org = "";
+    }
+
+    srcPath = SDL_WinRTGetFSPathUNICODE(SDL_WINRT_PATH_LOCAL_FOLDER);
+    if ( ! srcPath) {
+        SDL_SetError("Unable to find a source path");
+        return NULL;
+    }
+
+    if (SDL_wcslen(srcPath) >= MAX_PATH) {
+        SDL_SetError("Path too long.");
+        return NULL;
+    }
+    SDL_wcslcpy(path, srcPath, SDL_arraysize(path));
+
+    worg = WIN_UTF8ToString(org);
+    if (worg == NULL) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    wapp = WIN_UTF8ToString(app);
+    if (wapp == NULL) {
+        SDL_free(worg);
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3;
+
+    if ((new_wpath_len + 1) > MAX_PATH) {
+        SDL_free(worg);
+        SDL_free(wapp);
+        SDL_SetError("Path too long.");
+        return NULL;
+    }
+
+    if (*worg) {
+        SDL_wcslcat(path, L"\\", new_wpath_len + 1);
+        SDL_wcslcat(path, worg, new_wpath_len + 1);
+        SDL_free(worg);
+    }
+
+    api_result = CreateDirectoryW(path, NULL);
+    if (api_result == FALSE) {
+        if (GetLastError() != ERROR_ALREADY_EXISTS) {
+            SDL_free(wapp);
+            WIN_SetError("Couldn't create a prefpath.");
+            return NULL;
+        }
+    }
+
+    SDL_wcslcat(path, L"\\", new_wpath_len + 1);
+    SDL_wcslcat(path, wapp, new_wpath_len + 1);
+    SDL_free(wapp);
+
+    api_result = CreateDirectoryW(path, NULL);
+    if (api_result == FALSE) {
+        if (GetLastError() != ERROR_ALREADY_EXISTS) {
+            WIN_SetError("Couldn't create a prefpath.");
+            return NULL;
+        }
+    }
+
+    SDL_wcslcat(path, L"\\", new_wpath_len + 1);
+
+    retval = WIN_StringToUTF8(path);
+
+    return retval;
+}
+
+#endif /* __WINRT__ */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 4 - 0
src/joystick/SDL_joystick.c

@@ -436,6 +436,9 @@ SDL_JoystickGetDevicePlayerIndex(int device_index)
 static SDL_bool
 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
 {
+#ifdef __WINRT__
+    return SDL_TRUE;
+#else
     static Uint32 zero_centered_joysticks[] = {
         MAKE_VIDPID(0x0e8f, 0x3013),    /* HuiJia SNES USB adapter */
         MAKE_VIDPID(0x05a0, 0x3232),    /* 8Bitdo Zero Gamepad */
@@ -458,6 +461,7 @@ SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
         }
     }
     return SDL_FALSE;
+#endif /* __WINRT__ */
 }
 
 /*

+ 5 - 0
src/joystick/windows/SDL_rawinputjoystick.c

@@ -577,8 +577,13 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
             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);
 
+#ifdef __WINRT__
+            WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
+            RoGetActivationFactory_t RoGetActivationFactoryFunc = RoGetActivationFactory;
+#else
             WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
             RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
+#endif
             if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
                 PCWSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
                 HSTRING_HEADER hNamespaceStringHeader;

+ 22 - 5
src/joystick/windows/SDL_windows_gaming_input.c

@@ -282,9 +282,17 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
             typedef PCWSTR (WINAPI *WindowsGetStringRawBuffer_t)(HSTRING string, UINT32 *length);
             typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
 
-            WindowsGetStringRawBuffer_t WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)WIN_LoadComBaseFunction("WindowsGetStringRawBuffer");
-            WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)WIN_LoadComBaseFunction("WindowsDeleteString");
-
+            WindowsGetStringRawBuffer_t WindowsGetStringRawBufferFunc = NULL;
+            WindowsDeleteString_t WindowsDeleteStringFunc = NULL;
+#ifdef __WINRT__
+            WindowsGetStringRawBufferFunc = WindowsGetStringRawBuffer;
+            WindowsDeleteStringFunc = WindowsDeleteString;
+#else
+            {
+                WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)WIN_LoadComBaseFunction("WindowsGetStringRawBuffer");
+                WindowsDeleteStringFunc = (WindowsDeleteString_t)WIN_LoadComBaseFunction("WindowsDeleteString");
+            }
+#endif /* __WINRT__ */
             if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) {
                 HSTRING hString;
                 hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_get_DisplayName(controller2, &hString);
@@ -476,6 +484,7 @@ WGI_JoystickInit(void)
     }
     wgi.ro_initialized = SDL_TRUE;
 
+#ifndef __WINRT__
     {
         /* There seems to be a bug in Windows where a dependency of WGI can be unloaded from memory prior to WGI itself.
          * This results in Windows_Gaming_Input!GameController::~GameController() invoking an unloaded DLL and crashing.
@@ -496,9 +505,17 @@ WGI_JoystickInit(void)
             }
         }
     }
+#endif
 
-    WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference");
-    RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory");
+#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;

+ 9 - 5
src/joystick/windows/SDL_windowsjoystick.c

@@ -41,7 +41,7 @@
 #include "../SDL_sysjoystick.h"
 #include "../../thread/SDL_systhread.h"
 #include "../../core/windows/SDL_windows.h"
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
 #include <dbt.h>
 #endif
 
@@ -146,7 +146,7 @@ static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB,
 
 JoyStick_DeviceData *SYS_Joystick;    /* array to hold joystick ID values */
 
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
 static HMODULE cfgmgr32_lib_handle;
 static CM_Register_NotificationFunc CM_Register_Notification;
 static CM_Unregister_NotificationFunc CM_Unregister_Notification;
@@ -332,8 +332,10 @@ SDL_WaitForDeviceNotification(SDL_DeviceNotificationData *data, SDL_mutex *mutex
     return (lastret != -1) ? SDL_TRUE : SDL_FALSE;
 }
 
-#endif /* !defined(__XBOXONE__) && !defined(__XBOXSERIES__) */
+#endif /* !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__) */
+
 
+#if !defined(__WINRT__)
 
 #if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
 static SDL_DeviceNotificationData s_notification_data;
@@ -443,6 +445,8 @@ SDL_StopJoystickThread(void)
     s_joystickThread = NULL;
 }
 
+#endif /* !defined(__WINRT__) */
+
 void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device)
 {
     device->send_add_event = SDL_TRUE;
@@ -475,7 +479,7 @@ WINDOWS_JoystickInit(void)
 
     WINDOWS_JoystickDetect();
 
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
     SDL_CreateDeviceNotificationFunc();
 
     s_bJoystickThread = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_THREAD, SDL_FALSE);
@@ -767,7 +771,7 @@ WINDOWS_JoystickQuit(void)
     }
     SYS_Joystick = NULL;
 
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
     if (s_bJoystickThread) {
         SDL_StopJoystickThread();
     } else {

+ 7 - 3
src/joystick/windows/SDL_xinputjoystick.c

@@ -46,7 +46,11 @@ static char *s_arrXInputDevicePath[XUSER_MAX_COUNT];
 static SDL_bool
 SDL_XInputUseOldJoystickMapping()
 {
-#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#ifdef __WINRT__
+    /* TODO: remove this __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
+    /* FIXME: Why are Win8/10 different here? -flibit */
+    return (NTDDI_VERSION < NTDDI_WIN10);
+#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
     return SDL_FALSE;
 #else
     static int s_XInputUseOldJoystickMapping = -1;
@@ -129,7 +133,7 @@ GetXInputName(const Uint8 userid, BYTE SubType)
 static void
 GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
 {
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__) /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__) /* TODO: remove this ifndef __WINRT__ block, but only after integrating with UWP/WinRT's HID API */
     PRAWINPUTDEVICELIST devices = NULL;
     UINT i, j, device_count = 0;
 
@@ -227,7 +231,7 @@ GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
         }
     }
     SDL_free(devices);
-#endif
+#endif  /* !__WINRT__ */
 
     /* The device wasn't in the raw HID device list, it's probably Bluetooth */
     *pVID = 0x045e; /* Microsoft */

+ 8 - 0
src/loadso/windows/SDL_sysloadso.c

@@ -40,7 +40,15 @@ SDL_LoadObject(const char *sofile)
         return NULL;
     }
     tstr = WIN_UTF8ToString(sofile);
+#ifdef __WINRT__
+    /* WinRT only publicly supports LoadPackagedLibrary() for loading .dll
+       files.  LoadLibrary() is a private API, and not available for apps
+       (that can be published to MS' Windows Store.)
+    */
+    handle = (void *) LoadPackagedLibrary(tstr, 0);
+#else
     handle = (void *) LoadLibrary(tstr);
+#endif
     SDL_free(tstr);
 
     /* Generate an error message if all loads failed */

+ 58 - 0
src/locale/winrt/SDL_syslocale.c

@@ -0,0 +1,58 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Windows.h>
+
+#include "../../SDL_internal.h"
+#include "../SDL_syslocale.h"
+
+/*using namespace Windows::Graphics::Display;*/
+#include <wchar.h>
+
+void
+SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
+{
+    WCHAR wbuffer[128] = L"";
+    int ret = 0;
+
+    /* !!! FIXME: do we not have GetUserPreferredUILanguages on WinPhone or UWP? */
+# if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    ret = GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SNAME, wbuffer, SDL_arraysize(wbuffer));
+# else
+    ret = GetSystemDefaultLocaleName(wbuffer, SDL_arraysize(wbuffer));
+# endif
+
+    if (ret > 0)
+    {
+        /* Need to convert LPWSTR to LPSTR, that is wide char to char. */
+        int i;
+
+        if ( ((size_t) ret) >= (buflen - 1) ) {
+            ret = (int) (buflen - 1);
+        }
+        for (i = 0; i < ret; i++) {
+            buf[i] = (char) wbuffer[i];  /* assume this was ASCII anyhow. */
+        }
+    }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 0 - 0
src/main/winrt/SDL3-WinRTResource_BlankCursor.cur


+ 3 - 0
src/main/winrt/SDL3-WinRTResources.rc

@@ -0,0 +1,3 @@
+#include "winres.h"
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+5000 CURSOR "SDL3-WinRTResource_BlankCursor.cur"

+ 54 - 0
src/main/winrt/SDL_winrt_main_NonXAML.cpp

@@ -0,0 +1,54 @@
+/*
+    SDL_winrt_main_NonXAML.cpp, placed in the public domain by David Ludwig  3/13/14
+*/
+
+#include "SDL_main.h"
+#include <wrl.h>
+
+/* At least one file in any SDL/WinRT app appears to require compilation
+   with C++/CX, otherwise a Windows Metadata file won't get created, and
+   an APPX0702 build error can appear shortly after linking.
+
+   The following set of preprocessor code forces this file to be compiled
+   as C++/CX, which appears to cause Visual C++ 2012's build tools to
+   create this .winmd file, and will help allow builds of SDL/WinRT apps
+   to proceed without error.
+
+   If other files in an app's project enable C++/CX compilation, then it might
+   be possible for SDL_winrt_main_NonXAML.cpp to be compiled without /ZW,
+   for Visual C++'s build tools to create a winmd file, and for the app to
+   build without APPX0702 errors.  In this case, if
+   SDL_WINRT_METADATA_FILE_AVAILABLE is defined as a C/C++ macro, then
+   the #error (to force C++/CX compilation) will be disabled.
+
+   Please note that /ZW can be specified on a file-by-file basis.  To do this,
+   right click on the file in Visual C++, click Properties, then change the
+   setting through the dialog that comes up.
+*/
+#ifndef SDL_WINRT_METADATA_FILE_AVAILABLE
+#ifndef __cplusplus_winrt
+#error SDL_winrt_main_NonXAML.cpp must be compiled with /ZW, otherwise build errors due to missing .winmd files can occur.
+#endif
+#endif
+
+/* Prevent MSVC++ from warning about threading models when defining our
+   custom WinMain.  The threading model will instead be set via a direct
+   call to Windows::Foundation::Initialize (rather than via an attributed
+   function).
+
+   To note, this warning (C4447) does not seem to come up unless this file
+   is compiled with C++/CX enabled (via the /ZW compiler flag).
+*/
+#ifdef _MSC_VER
+#pragma warning(disable:4447)
+#endif
+
+/* Make sure the function to initialize the Windows Runtime gets linked in. */
+#ifdef _MSC_VER
+#pragma comment(lib, "runtimeobject.lib")
+#endif
+
+int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+    return SDL_WinRTRunApp(SDL_main, NULL);
+}

+ 41 - 0
src/misc/winrt/SDL_sysurl.cpp

@@ -0,0 +1,41 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../SDL_sysurl.h"
+#include "../../core/windows/SDL_windows.h"
+
+int
+SDL_SYS_OpenURL(const char *url)
+{
+    WCHAR *wurl = WIN_UTF8ToStringW(url);
+    if (!wurl) {
+        return SDL_OutOfMemory();
+    }
+    auto strurl = ref new Platform::String(wurl);
+    SDL_free(wurl);
+
+    auto uri = ref new Windows::Foundation::Uri(strurl);
+    Windows::System::Launcher::LaunchUriAsync(uri);
+    return 0;  // oh well, we're not waiting on an async task here.
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 3 - 0
src/power/SDL_power.c

@@ -74,6 +74,9 @@ static SDL_GetPowerInfo_Impl implementations[] = {
 #ifdef SDL_POWER_N3DS        /* handles N3DS. */
     SDL_GetPowerInfo_N3DS,
 #endif
+#ifdef SDL_POWER_WINRT          /* handles WinRT */
+    SDL_GetPowerInfo_WinRT,
+#endif
 #ifdef SDL_POWER_EMSCRIPTEN     /* handles Emscripten */
     SDL_GetPowerInfo_Emscripten,
 #endif

+ 1 - 0
src/power/SDL_syspower.h

@@ -40,6 +40,7 @@ SDL_bool SDL_GetPowerInfo_Android(SDL_PowerState *, int *, int *);
 SDL_bool SDL_GetPowerInfo_PSP(SDL_PowerState *, int *, int *);
 SDL_bool SDL_GetPowerInfo_VITA(SDL_PowerState *, int *, int *);
 SDL_bool SDL_GetPowerInfo_N3DS(SDL_PowerState *, int *, int *);
+SDL_bool SDL_GetPowerInfo_WinRT(SDL_PowerState *, int *, int *);
 SDL_bool SDL_GetPowerInfo_Emscripten(SDL_PowerState *, int *, int *);
 
 /* this one is static in SDL_power.c */

+ 44 - 0
src/power/winrt/SDL_syspower.cpp

@@ -0,0 +1,44 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifndef SDL_POWER_DISABLED
+#if SDL_POWER_WINRT
+
+#include "SDL_power.h"
+
+extern "C"
+SDL_bool
+SDL_GetPowerInfo_WinRT(SDL_PowerState * state, int *seconds, int *percent)
+{
+    /* TODO, WinRT: Battery info is available on at least one WinRT platform (Windows Phone 8).  Implement SDL_GetPowerInfo_WinRT as appropriate. */
+    /* Notes:
+         - the Win32 function, GetSystemPowerStatus, is not available for use on WinRT
+         - Windows Phone 8 has a 'Battery' class, which is documented as available for C++
+             - More info on WP8's Battery class can be found at http://msdn.microsoft.com/library/windowsphone/develop/jj207231
+    */
+    return SDL_FALSE;
+}
+
+#endif /* SDL_POWER_WINRT */
+#endif /* SDL_POWER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 56 - 1
src/render/direct3d11/SDL_render_d3d11.c

@@ -27,7 +27,9 @@
 
 #define COBJMACROS
 #include "../../core/windows/SDL_windows.h"
+#if !defined(__WINRT__)
 #include "../../video/windows/SDL_windowswindow.h"
+#endif
 #include "SDL_hints.h"
 #include "SDL_loadso.h"
 #include "SDL_syswm.h"
@@ -38,6 +40,22 @@
 
 #include "SDL_shaders_d3d11.h"
 
+#ifdef __WINRT__
+
+#if NTDDI_VERSION > NTDDI_WIN8
+#include <DXGI1_3.h>
+#endif
+
+#include "SDL_render_winrt.h"
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+#include <windows.ui.xaml.media.dxinterop.h>
+/* TODO, WinRT, XAML: get the ISwapChainBackgroundPanelNative from something other than a global var */
+extern ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative;
+#endif  /* WINAPI_FAMILY == WINAPI_FAMILY_APP */
+
+#endif  /* __WINRT__ */
+
 
 #if defined(_MSC_VER) && !defined(__clang__)
 #define SDL_COMPOSE_ERROR(str) __FUNCTION__ ", " str
@@ -169,6 +187,9 @@ typedef struct
 
 static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
 static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } };
+#if defined(__WINRT__) && NTDDI_VERSION > NTDDI_WIN8
+static const GUID SDL_IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } };
+#endif
 static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } };
 static const GUID SDL_IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } };
 static const GUID SDL_IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } };
@@ -418,6 +439,10 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer)
     D3D11_SAMPLER_DESC samplerDesc;
     D3D11_RASTERIZER_DESC rasterDesc;
 
+#ifdef __WINRT__
+    CreateDXGIFactoryFunc = CreateDXGIFactory1;
+    D3D11CreateDeviceFunc = D3D11CreateDevice;
+#else
     data->hDXGIMod = SDL_LoadObject("dxgi.dll");
     if (!data->hDXGIMod) {
         result = E_FAIL;
@@ -441,6 +466,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer)
         result = E_FAIL;
         goto done;
     }
+#endif /* __WINRT__ */
 
     result = CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory);
     if (FAILED(result)) {
@@ -728,8 +754,13 @@ static HRESULT
 D3D11_CreateSwapChain(SDL_Renderer * renderer, int w, int h)
 {
     D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
+#ifdef __WINRT__
+    IUnknown *coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer);
+    const BOOL usingXAML = (coreWindow == NULL);
+#else
     IUnknown *coreWindow = NULL;
     const BOOL usingXAML = FALSE;
+#endif
     HRESULT result = S_OK;
 
     /* Create a swap chain using the same adapter as the existing Direct3D device. */
@@ -882,7 +913,11 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
     /* The width and height of the swap chain must be based on the display's
      * non-rotated size.
      */
+#if defined(__WINRT__)
+    SDL_GetWindowSize(renderer->window, &w, &h);
+#else
     SDL_GetWindowSizeInPixels(renderer->window, &w, &h);
+#endif
     data->rotation = D3D11_GetCurrentRotation();
     /* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
     if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
@@ -893,7 +928,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
 
     if (data->swapChain) {
         /* IDXGISwapChain::ResizeBuffers is not available on Windows Phone 8. */
-#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
+#if !defined(__WINRT__) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
         /* If the swap chain already exists, resize it. */
         result = IDXGISwapChain_ResizeBuffers(data->swapChain,
             0,
@@ -997,6 +1032,22 @@ D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
 void
 D3D11_Trim(SDL_Renderer * renderer)
 {
+#ifdef __WINRT__
+#if NTDDI_VERSION > NTDDI_WIN8
+    D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
+    HRESULT result = S_OK;
+    IDXGIDevice3 *dxgiDevice = NULL;
+
+    result = ID3D11Device_QueryInterface(data->d3dDevice, &SDL_IID_IDXGIDevice3, &dxgiDevice);
+    if (FAILED(result)) {
+        //WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to IDXGIDevice3", result);
+        return;
+    }
+
+    IDXGIDevice3_Trim(dxgiDevice);
+    SAFE_RELEASE(dxgiDevice);
+#endif
+#endif
 }
 
 static void
@@ -1007,12 +1058,14 @@ D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
     }
 }
 
+#if !defined(__WINRT__)
 static int
 D3D11_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
 {
     SDL_GetWindowSizeInPixels(renderer->window, w, h);
     return 0;
 }
+#endif
 
 static SDL_bool
 D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
@@ -2331,7 +2384,9 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
     data->identity = MatrixIdentity();
 
     renderer->WindowEvent = D3D11_WindowEvent;
+#if !defined(__WINRT__)
     renderer->GetOutputSize = D3D11_GetOutputSize;
+#endif
     renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
     renderer->CreateTexture = D3D11_CreateTexture;
     renderer->UpdateTexture = D3D11_UpdateTexture;

+ 116 - 0
src/render/direct3d11/SDL_render_winrt.cpp

@@ -0,0 +1,116 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
+
+#include "SDL_syswm.h"
+#include "../../video/winrt/SDL_winrtvideo_cpp.h"
+extern "C" {
+#include "../SDL_sysrender.h"
+}
+
+#include <windows.ui.core.h>
+#include <windows.graphics.display.h>
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+#include <windows.ui.xaml.media.dxinterop.h>
+#endif
+
+using namespace Windows::UI::Core;
+using namespace Windows::Graphics::Display;
+
+#include <DXGI.h>
+
+#include "SDL_render_winrt.h"
+
+
+extern "C" void *
+D3D11_GetCoreWindowFromSDLRenderer(SDL_Renderer * renderer)
+{
+    SDL_Window * sdlWindow = renderer->window;
+    if ( ! renderer->window ) {
+        return NULL;
+    }
+
+    SDL_SysWMinfo sdlWindowInfo;
+    SDL_VERSION(&sdlWindowInfo.version);
+    if ( ! SDL_GetWindowWMInfo(sdlWindow, &sdlWindowInfo) ) {
+        return NULL;
+    }
+
+    if (sdlWindowInfo.subsystem != SDL_SYSWM_WINRT) {
+        return NULL;
+    }
+
+    if (!sdlWindowInfo.info.winrt.window) {
+        return NULL;
+    }
+
+    ABI::Windows::UI::Core::ICoreWindow *coreWindow = NULL;
+    if (FAILED(sdlWindowInfo.info.winrt.window->QueryInterface(&coreWindow))) {
+        return NULL;
+    }
+
+    IUnknown *coreWindowAsIUnknown = NULL;
+    coreWindow->QueryInterface(&coreWindowAsIUnknown);
+    coreWindow->Release();
+
+    return coreWindowAsIUnknown;
+}
+
+extern "C" DXGI_MODE_ROTATION
+D3D11_GetCurrentRotation()
+{
+    const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
+
+    switch (currentOrientation) {
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    /* Windows Phone rotations */
+    case DisplayOrientations::Landscape:
+        return DXGI_MODE_ROTATION_ROTATE90;
+    case DisplayOrientations::Portrait:
+        return DXGI_MODE_ROTATION_IDENTITY;
+    case DisplayOrientations::LandscapeFlipped:
+        return DXGI_MODE_ROTATION_ROTATE270;
+    case DisplayOrientations::PortraitFlipped:
+        return DXGI_MODE_ROTATION_ROTATE180;
+#else
+    /* Non-Windows-Phone rotations (ex: Windows 8, Windows RT) */
+    case DisplayOrientations::Landscape:
+        return DXGI_MODE_ROTATION_IDENTITY;
+    case DisplayOrientations::Portrait:
+        return DXGI_MODE_ROTATION_ROTATE270;
+    case DisplayOrientations::LandscapeFlipped:
+        return DXGI_MODE_ROTATION_ROTATE180;
+    case DisplayOrientations::PortraitFlipped:
+        return DXGI_MODE_ROTATION_ROTATE90;
+#endif /* WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP */
+    }
+
+    return DXGI_MODE_ROTATION_IDENTITY;
+}
+
+
+#endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 40 - 0
src/render/direct3d11/SDL_render_winrt.h

@@ -0,0 +1,40 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
+
+#include "SDL_render.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void * D3D11_GetCoreWindowFromSDLRenderer(SDL_Renderer * renderer);
+DXGI_MODE_ROTATION D3D11_GetCurrentRotation();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 8 - 0
src/render/opengles2/SDL_render_gles2.c

@@ -2152,6 +2152,14 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
         goto error;
     }
 
+#if __WINRT__
+    /* DLudwig, 2013-11-29: ANGLE for WinRT doesn't seem to work unless VSync
+     * is turned on.  Not doing so will freeze the screen's contents to that
+     * of the first drawn frame.
+     */
+    flags |= SDL_RENDERER_PRESENTVSYNC;
+#endif
+
     if (flags & SDL_RENDERER_PRESENTVSYNC) {
         SDL_GL_SetSwapInterval(1);
     } else {

+ 31 - 0
src/thread/stdcpp/SDL_systhread.cpp

@@ -32,6 +32,10 @@ extern "C" {
 #include <thread>
 #include <system_error>
 
+#ifdef __WINRT__
+#include <Windows.h>
+#endif
+
 static void
 RunThread(void *args)
 {
@@ -67,6 +71,9 @@ extern "C"
 SDL_threadID
 SDL_ThreadID(void)
 {
+#ifdef __WINRT__
+    return GetCurrentThreadId();
+#else
     // HACK: Mimick a thread ID, if one isn't otherwise available.
     static thread_local SDL_threadID current_thread_id = 0;
     static SDL_threadID next_thread_id = 1;
@@ -79,13 +86,37 @@ SDL_ThreadID(void)
     }
 
     return current_thread_id;
+#endif
 }
 
 extern "C"
 int
 SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
 {
+#ifdef __WINRT__
+    int value;
+
+    if (priority == SDL_THREAD_PRIORITY_LOW) {
+        value = THREAD_PRIORITY_LOWEST;
+    }
+    else if (priority == SDL_THREAD_PRIORITY_HIGH) {
+        value = THREAD_PRIORITY_HIGHEST;
+    }
+    else if (priority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
+        // FIXME: WinRT does not support TIME_CRITICAL! -flibit
+        SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM, "TIME_CRITICAL unsupported, falling back to HIGHEST");
+        value = THREAD_PRIORITY_HIGHEST;
+    }
+    else {
+        value = THREAD_PRIORITY_NORMAL;
+    }
+    if (!SetThreadPriority(GetCurrentThread(), value)) {
+        return WIN_SetError("SetThreadPriority()");
+    }
+    return 0;
+#else
     return SDL_Unsupported();
+#endif
 }
 
 extern "C"

+ 12 - 0
src/thread/windows/SDL_syscond_cv.c

@@ -58,6 +58,12 @@ typedef struct CONDITION_VARIABLE {
 } CONDITION_VARIABLE, *PCONDITION_VARIABLE;
 #endif
 
+#if __WINRT__
+#define pWakeConditionVariable WakeConditionVariable
+#define pWakeAllConditionVariable WakeAllConditionVariable
+#define pSleepConditionVariableSRW SleepConditionVariableSRW
+#define pSleepConditionVariableCS SleepConditionVariableCS
+#else
 typedef VOID(WINAPI *pfnWakeConditionVariable)(PCONDITION_VARIABLE);
 typedef VOID(WINAPI *pfnWakeAllConditionVariable)(PCONDITION_VARIABLE);
 typedef BOOL(WINAPI *pfnSleepConditionVariableSRW)(PCONDITION_VARIABLE, PSRWLOCK, DWORD, ULONG);
@@ -67,6 +73,7 @@ static pfnWakeConditionVariable pWakeConditionVariable = NULL;
 static pfnWakeAllConditionVariable pWakeAllConditionVariable = NULL;
 static pfnSleepConditionVariableSRW pSleepConditionVariableSRW = NULL;
 static pfnSleepConditionVariableCS pSleepConditionVariableCS = NULL;
+#endif
 
 typedef struct SDL_cond_cv
 {
@@ -235,6 +242,10 @@ SDL_CreateCond(void)
             SDL_assert(SDL_mutex_impl_active.Type != SDL_MUTEX_INVALID);
         }
 
+#if __WINRT__
+        /* Link statically on this platform */
+        impl = &SDL_cond_impl_cv;
+#else
         {
             HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
             if (kernel32) {
@@ -248,6 +259,7 @@ SDL_CreateCond(void)
                 }
             }
         }
+#endif
 
         SDL_copyp(&SDL_cond_impl_active, impl);
     }

+ 16 - 0
src/thread/windows/SDL_sysmutex.c

@@ -44,12 +44,19 @@ SDL_mutex_impl_t SDL_mutex_impl_active = {0};
  * Implementation based on Slim Reader/Writer (SRW) Locks for Win 7 and newer.
  */
 
+#if __WINRT__
+/* Functions are guaranteed to be available */
+#define pReleaseSRWLockExclusive ReleaseSRWLockExclusive
+#define pAcquireSRWLockExclusive AcquireSRWLockExclusive
+#define pTryAcquireSRWLockExclusive TryAcquireSRWLockExclusive
+#else
 typedef VOID(WINAPI *pfnReleaseSRWLockExclusive)(PSRWLOCK);
 typedef VOID(WINAPI *pfnAcquireSRWLockExclusive)(PSRWLOCK);
 typedef BOOLEAN(WINAPI *pfnTryAcquireSRWLockExclusive)(PSRWLOCK);
 static pfnReleaseSRWLockExclusive pReleaseSRWLockExclusive = NULL;
 static pfnAcquireSRWLockExclusive pAcquireSRWLockExclusive = NULL;
 static pfnTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive = NULL;
+#endif
 
 static SDL_mutex *
 SDL_CreateMutex_srw(void)
@@ -173,7 +180,11 @@ SDL_CreateMutex_cs(void)
     if (mutex) {
         /* Initialize */
         /* On SMP systems, a non-zero spin count generally helps performance */
+#if __WINRT__
+        InitializeCriticalSectionEx(&mutex->cs, 2000, 0);
+#else
         InitializeCriticalSectionAndSpinCount(&mutex->cs, 2000);
+#endif
     } else {
         SDL_OutOfMemory();
     }
@@ -256,6 +267,10 @@ SDL_CreateMutex(void)
         const SDL_mutex_impl_t * impl = &SDL_mutex_impl_cs;
 
         if (!SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS, SDL_FALSE)) {
+#if __WINRT__
+            /* Link statically on this platform */
+            impl = &SDL_mutex_impl_srw;
+#else
             /* Try faster implementation for Windows 7 and newer */
             HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
             if (kernel32) {
@@ -268,6 +283,7 @@ SDL_CreateMutex(void)
                     impl = &SDL_mutex_impl_srw;
                 }
             }
+#endif
         }
 
         /* Copy instead of using pointer to save one level of indirection */

+ 15 - 0
src/thread/windows/SDL_syssem.c

@@ -76,11 +76,17 @@ static SDL_sem_impl_t SDL_sem_impl_active = {0};
 #endif
 
 #if !SDL_WINAPI_FAMILY_PHONE
+#if __WINRT__
+/* Functions are guaranteed to be available */
+#define pWaitOnAddress WaitOnAddress
+#define pWakeByAddressSingle WakeByAddressSingle
+#else
 typedef BOOL(WINAPI *pfnWaitOnAddress)(volatile VOID*, PVOID, SIZE_T, DWORD);
 typedef VOID(WINAPI *pfnWakeByAddressSingle)(PVOID);
 
 static pfnWaitOnAddress pWaitOnAddress = NULL;
 static pfnWakeByAddressSingle pWakeByAddressSingle = NULL;
+#endif
 
 typedef struct SDL_semaphore_atom
 {
@@ -268,7 +274,11 @@ SDL_CreateSemaphore_kern(Uint32 initial_value)
     sem = (SDL_sem_kern *) SDL_malloc(sizeof(*sem));
     if (sem) {
         /* Create the semaphore, with max value 32K */
+#if __WINRT__
+        sem->id = CreateSemaphoreEx(NULL, initial_value, 32 * 1024, NULL, 0, SEMAPHORE_ALL_ACCESS);
+#else
         sem->id = CreateSemaphore(NULL, initial_value, 32 * 1024, NULL);
+#endif
         sem->count = initial_value;
         if (!sem->id) {
             SDL_SetError("Couldn't create semaphore");
@@ -395,6 +405,10 @@ SDL_CreateSemaphore(Uint32 initial_value)
 
 #if !SDL_WINAPI_FAMILY_PHONE
         if (!SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_SEMAPHORE_KERNEL, SDL_FALSE)) {
+#if __WINRT__
+            /* Link statically on this platform */
+            impl = &SDL_sem_impl_atom;
+#else
             /* We already statically link to features from this Api
              * Set (e.g. WaitForSingleObject). Dynamically loading
              * API Sets is not explicitly documented but according to
@@ -411,6 +425,7 @@ SDL_CreateSemaphore(Uint32 initial_value)
                     impl = &SDL_sem_impl_atom;
                 }
             }
+#endif
         }
 #endif
 

+ 3 - 1
src/thread/windows/SDL_systhread.c

@@ -87,7 +87,7 @@ SDL_SYS_CreateThread(SDL_Thread * thread,
                      pfnSDL_CurrentBeginThread pfnBeginThread,
                      pfnSDL_CurrentEndThread pfnEndThread)
 {
-#elif defined(__CYGWIN__)
+#elif defined(__CYGWIN__) || defined(__WINRT__)
 int
 SDL_SYS_CreateThread(SDL_Thread * thread)
 {
@@ -141,6 +141,7 @@ void
 SDL_SYS_SetupThread(const char *name)
 {
     if (name != NULL) {
+        #ifndef __WINRT__   /* !!! FIXME: There's no LoadLibrary() in WinRT; don't know if SetThreadDescription is available there at all at the moment. */
         static pfnSetThreadDescription pSetThreadDescription = NULL;
         static HMODULE kernel32 = 0;
 
@@ -158,6 +159,7 @@ SDL_SYS_SetupThread(const char *name)
                 SDL_free(strw);
             }
         }
+        #endif
 
         /* Presumably some version of Visual Studio will understand SetThreadDescription(),
            but we still need to deal with older OSes and debuggers. Set it with the arcane

+ 12 - 0
src/thread/windows/SDL_systls.c

@@ -28,6 +28,18 @@
 #include "SDL_thread.h"
 #include "../SDL_thread_c.h"
 
+#if WINAPI_FAMILY_WINRT
+#include <fibersapi.h>
+
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES  FLS_OUT_OF_INDEXES
+#endif
+
+#define TlsAlloc()  FlsAlloc(NULL)
+#define TlsSetValue FlsSetValue
+#define TlsGetValue FlsGetValue
+#endif
+
 static DWORD thread_local_storage = TLS_OUT_OF_INDEXES;
 static SDL_bool generic_local_storage = SDL_FALSE;
 

+ 21 - 1
src/timer/windows/SDL_systimer.c

@@ -41,7 +41,7 @@ static LARGE_INTEGER ticks_per_second;
 static void
 SDL_SetSystemTimerResolution(const UINT uPeriod)
 {
-#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
+#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
     static UINT timer_period = 0;
 
     if (uPeriod != timer_period) {
@@ -146,11 +146,31 @@ SDL_GetPerformanceFrequency(void)
 void
 SDL_Delay(Uint32 ms)
 {
+    /* Sleep() is not publicly available to apps in early versions of WinRT.
+     *
+     * Visual C++ 2013 Update 4 re-introduced Sleep() for Windows 8.1 and
+     * Windows Phone 8.1.
+     *
+     * Use the compiler version to determine availability.
+     *
+     * NOTE #1: _MSC_FULL_VER == 180030723 for Visual C++ 2013 Update 3.
+     * NOTE #2: Visual C++ 2013, when compiling for Windows 8.0 and
+     *    Windows Phone 8.0, uses the Visual C++ 2012 compiler to build
+     *    apps and libraries.
+     */
+#if defined(__WINRT__) && defined(_MSC_FULL_VER) && (_MSC_FULL_VER <= 180030723)
+    static HANDLE mutex = 0;
+    if (!mutex) {
+        mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS);
+    }
+    WaitForSingleObjectEx(mutex, ms, FALSE);
+#else
     if (!ticks_started) {
         SDL_TicksInit();
     }
 
     Sleep(ms);
+#endif
 }
 
 #endif /* SDL_TIMER_WINDOWS */

+ 6 - 4
src/video/SDL_egl.c

@@ -22,7 +22,7 @@
 
 #if SDL_VIDEO_OPENGL_EGL
 
-#if SDL_VIDEO_DRIVER_WINDOWS
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
 #include "../core/windows/SDL_windows.h"
 #endif
 #if SDL_VIDEO_DRIVER_ANDROID
@@ -73,7 +73,7 @@
 #define DEFAULT_OGL_ES_PVR "libGLES_CM.so"
 #define DEFAULT_OGL_ES "libGLESv1_CM.so"
 
-#elif SDL_VIDEO_DRIVER_WINDOWS
+#elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
 /* EGL AND OpenGL ES support via ANGLE */
 #define DEFAULT_EGL "libEGL.dll"
 #define DEFAULT_OGL_ES2 "libGLESv2.dll"
@@ -297,14 +297,14 @@ SDL_EGL_LoadLibraryInternal(_THIS, const char *egl_path)
 {
     void *egl_dll_handle = NULL, *opengl_dll_handle = NULL;
     const char *path = NULL;
-#if SDL_VIDEO_DRIVER_WINDOWS
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
     const char *d3dcompiler;
 #endif
 #if SDL_VIDEO_DRIVER_RPI
     SDL_bool vc4 = (0 == access("/sys/module/vc4/", F_OK));
 #endif
 
-#if SDL_VIDEO_DRIVER_WINDOWS
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT
     d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER);
     if (d3dcompiler) {
         if (SDL_strcasecmp(d3dcompiler, "none") != 0) {
@@ -510,6 +510,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
 
     _this->egl_data->egl_display = EGL_NO_DISPLAY;
 
+#if !defined(__WINRT__)
 #if !defined(SDL_VIDEO_DRIVER_VITA)
     if (platform) {
         /* EGL 1.5 allows querying for client version with EGL_NO_DISPLAY
@@ -551,6 +552,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
         *_this->gl_config.driver_path = '\0';
         return SDL_SetError("Could not initialize EGL");
     }
+#endif
 
     /* Get the EGL version with a valid egl_display, for EGL <= 1.4 */
     SDL_EGL_GetVersion(_this);

+ 1 - 1
src/video/SDL_stretch.c

@@ -352,7 +352,7 @@ scale_mat(const Uint32 *src, int src_w, int src_h, int src_pitch,
 #  define CAST_uint32x2_t (uint32x2_t)
 #endif
 
-#if defined(_MSC_VER)
+#if defined(__WINRT__) || defined(_MSC_VER)
 #  if defined(HAVE_NEON_INTRINSICS)
 #    undef CAST_uint8x8_t
 #    undef CAST_uint32x2_t

+ 1 - 0
src/video/SDL_sysvideo.h

@@ -451,6 +451,7 @@ typedef struct VideoBootStrap
 extern VideoBootStrap COCOA_bootstrap;
 extern VideoBootStrap X11_bootstrap;
 extern VideoBootStrap WINDOWS_bootstrap;
+extern VideoBootStrap WINRT_bootstrap;
 extern VideoBootStrap HAIKU_bootstrap;
 extern VideoBootStrap PND_bootstrap;
 extern VideoBootStrap UIKIT_bootstrap;

+ 54 - 1
src/video/SDL_video.c

@@ -80,6 +80,9 @@ static VideoBootStrap *bootstrap[] = {
 #if SDL_VIDEO_DRIVER_WINDOWS
     &WINDOWS_bootstrap,
 #endif
+#if SDL_VIDEO_DRIVER_WINRT
+    &WINRT_bootstrap,
+#endif
 #if SDL_VIDEO_DRIVER_HAIKU
     &HAIKU_bootstrap,
 #endif
@@ -1336,6 +1339,10 @@ SDL_RestoreMousePosition(SDL_Window *window)
     }
 }
 
+#if __WINRT__
+extern Uint32 WINRT_DetectWindowFlags(SDL_Window * window);
+#endif
+
 static int
 SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
 {
@@ -1378,6 +1385,30 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
             return 0;
         }
     }
+#elif __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
+    /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
+       or not.  The user can choose this, via OS-provided UI, but this can't
+       be set programmatically.
+
+       Just look at what SDL's WinRT video backend code detected with regards
+       to fullscreen (being active, or not), and figure out a return/error code
+       from that.
+    */
+    if (fullscreen == !(WINRT_DetectWindowFlags(window) & FULLSCREEN_MASK)) {
+        /* Uh oh, either:
+            1. fullscreen was requested, and we're already windowed
+            2. windowed-mode was requested, and we're already fullscreen
+
+            WinRT 8.x can't resolve either programmatically, so we're
+            giving up.
+        */
+        return -1;
+    } else {
+        /* Whatever was requested, fullscreen or windowed mode, is already
+            in-place.
+        */
+        return 0;
+    }
 #endif
 
     display = SDL_GetDisplayForWindow(window);
@@ -1731,6 +1762,18 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
     }
 #endif
 
+#if __WINRT__ && (NTDDI_VERSION < NTDDI_WIN10)
+    /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen
+       or not.  The user can choose this, via OS-provided UI, but this can't
+       be set programmatically.
+
+       Just look at what SDL's WinRT video backend code detected with regards
+       to fullscreen (being active, or not), and figure out a return/error code
+       from that.
+    */
+    flags = window->flags;
+#endif
+
     if (title) {
         SDL_SetWindowTitle(window, title);
     }
@@ -4382,6 +4425,9 @@ SDL_GetMessageBoxCount(void)
 #if SDL_VIDEO_DRIVER_WINDOWS
 #include "windows/SDL_windowsmessagebox.h"
 #endif
+#if SDL_VIDEO_DRIVER_WINRT
+#include "winrt/SDL_winrtmessagebox.h"
+#endif
 #if SDL_VIDEO_DRIVER_COCOA
 #include "cocoa/SDL_cocoamessagebox.h"
 #endif
@@ -4404,7 +4450,7 @@ SDL_GetMessageBoxCount(void)
 #include "vita/SDL_vitamessagebox.h"
 #endif
 
-#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 || SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_HAIKU || SDL_VIDEO_DRIVER_RISCOS
+#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 || SDL_VIDEO_DRIVER_WAYLAND || SDL_VIDEO_DRIVER_HAIKU || SDL_VIDEO_DRIVER_RISCOS
 static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype)
 {
     SDL_SysWMinfo info;
@@ -4477,6 +4523,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
         retval = 0;
     }
 #endif
+#if SDL_VIDEO_DRIVER_WINRT
+    if (retval == -1 &&
+        SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINRT) &&
+        WINRT_ShowMessageBox(messageboxdata, buttonid) == 0) {
+        retval = 0;
+    }
+#endif
 #if SDL_VIDEO_DRIVER_COCOA
     if (retval == -1 &&
         SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) &&

+ 153 - 0
src/video/winrt/SDL_winrtevents.cpp

@@ -0,0 +1,153 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/*
+ * Windows includes:
+ */
+#include <Windows.h>
+using namespace Windows::UI::Core;
+using Windows::UI::Core::CoreCursor;
+
+/*
+ * SDL includes:
+ */
+#include "SDL_winrtevents_c.h"
+#include "../../core/winrt/SDL_winrtapp_common.h"
+#include "../../core/winrt/SDL_winrtapp_direct3d.h"
+#include "../../core/winrt/SDL_winrtapp_xaml.h"
+#include "SDL_system.h"
+
+extern "C" {
+#include "../../thread/SDL_systhread.h"
+#include "../SDL_sysvideo.h"
+#include "../../events/SDL_events_c.h"
+}
+
+
+/* Forward declarations */
+static void WINRT_YieldXAMLThread();
+
+
+/* Global event management */
+
+void
+WINRT_PumpEvents(_THIS)
+{
+    if (SDL_WinRTGlobalApp) {
+        SDL_WinRTGlobalApp->PumpEvents();
+    } else if (WINRT_XAMLWasEnabled) {
+        WINRT_YieldXAMLThread();
+    }
+}
+
+
+/* XAML Thread management */
+
+enum SDL_XAMLAppThreadState
+{
+    ThreadState_NotLaunched = 0,
+    ThreadState_Running,
+    ThreadState_Yielding
+};
+
+static SDL_XAMLAppThreadState _threadState = ThreadState_NotLaunched;
+static SDL_Thread * _XAMLThread = nullptr;
+static SDL_mutex * _mutex = nullptr;
+static SDL_cond * _cond = nullptr;
+
+static void
+WINRT_YieldXAMLThread()
+{
+    SDL_LockMutex(_mutex);
+    SDL_assert(_threadState == ThreadState_Running);
+    _threadState = ThreadState_Yielding;
+    SDL_UnlockMutex(_mutex);
+
+    SDL_CondSignal(_cond);
+
+    SDL_LockMutex(_mutex);
+    while (_threadState != ThreadState_Running) {
+        SDL_CondWait(_cond, _mutex);
+    }
+    SDL_UnlockMutex(_mutex);
+}
+
+static int
+WINRT_XAMLThreadMain(void * userdata)
+{
+    // TODO, WinRT: pass the C-style main() a reasonably realistic
+    // representation of command line arguments.
+    int argc = 0;
+    char **argv = NULL;
+    return WINRT_SDLAppEntryPoint(argc, argv);
+}
+
+void
+WINRT_CycleXAMLThread(void)
+{
+    switch (_threadState) {
+        case ThreadState_NotLaunched:
+        {
+            _cond = SDL_CreateCond();
+
+            _mutex = SDL_CreateMutex();
+            _threadState = ThreadState_Running;
+            _XAMLThread = SDL_CreateThreadInternal(WINRT_XAMLThreadMain, "SDL/XAML App Thread", 0, nullptr);
+
+            SDL_LockMutex(_mutex);
+            while (_threadState != ThreadState_Yielding) {
+                SDL_CondWait(_cond, _mutex);
+            }
+            SDL_UnlockMutex(_mutex);
+
+            break;
+        }
+
+        case ThreadState_Running:
+        {
+            SDL_assert(false);
+            break;
+        }
+
+        case ThreadState_Yielding:
+        {
+            SDL_LockMutex(_mutex);
+            SDL_assert(_threadState == ThreadState_Yielding);
+            _threadState = ThreadState_Running;
+            SDL_UnlockMutex(_mutex);
+
+            SDL_CondSignal(_cond);
+
+            SDL_LockMutex(_mutex);
+            while (_threadState != ThreadState_Yielding) {
+                SDL_CondWait(_cond, _mutex);
+            }
+            SDL_UnlockMutex(_mutex);
+        }
+    }
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 83 - 0
src/video/winrt/SDL_winrtevents_c.h

@@ -0,0 +1,83 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+extern "C" {
+#include "../SDL_sysvideo.h"
+}
+
+/*
+ * Internal-use, C-style functions:
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void WINRT_InitTouch(_THIS);
+extern void WINRT_PumpEvents(_THIS);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Internal-use, C++/CX functions:
+ */
+#ifdef __cplusplus_winrt
+
+/* Pointers (Mice, Touch, etc.) */
+typedef enum {
+    NormalizeZeroToOne,
+    TransformToSDLWindowSize
+} WINRT_CursorNormalizationType;
+extern Windows::Foundation::Point WINRT_TransformCursorPosition(SDL_Window * window,
+                                                                Windows::Foundation::Point rawPosition,
+                                                                WINRT_CursorNormalizationType normalization);
+extern SDL_bool WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt, Uint8 *button, Uint8 *pressed);
+extern void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
+extern void WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
+extern void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
+extern void WINRT_ProcessPointerEnteredEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
+extern void WINRT_ProcessPointerExitedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
+extern void WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
+extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args);
+
+/* Keyboard */
+extern void WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args);
+extern void WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args);
+extern void WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArgs ^args);
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+extern void WINTRT_InitialiseInputPaneEvents(_THIS);
+extern SDL_bool WINRT_HasScreenKeyboardSupport(_THIS);
+extern void WINRT_ShowScreenKeyboard(_THIS, SDL_Window *window);
+extern void WINRT_HideScreenKeyboard(_THIS, SDL_Window *window);
+extern SDL_bool WINRT_IsScreenKeyboardShown(_THIS, SDL_Window *window);
+#endif  // NTDDI_VERSION >= ...
+
+/* XAML Thread Management */
+extern void WINRT_CycleXAMLThread(void);
+
+#endif // ifdef __cplusplus_winrt
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 196 - 0
src/video/winrt/SDL_winrtgamebar.cpp

@@ -0,0 +1,196 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/* Windows includes */
+#include <roapi.h>
+#include <windows.foundation.h>
+#include <windows.system.h>
+
+
+/* SDL includes */
+extern "C" {
+#include "SDL_mouse.h"
+#include "../SDL_sysvideo.h"
+}
+#include "SDL_winrtvideo_cpp.h"
+
+
+/* Game Bar events can come in off the main thread.  Use the following
+   WinRT CoreDispatcher to deal with them on SDL's thread.
+*/
+static Platform::WeakReference WINRT_MainThreadDispatcher;
+
+
+/* Win10's initial SDK (the 10.0.10240.0 release) does not include references
+   to Game Bar APIs, as the Game Bar was released via Win10 10.0.10586.0.
+
+   Declare its WinRT/COM interface here, to allow compilation with earlier
+   Windows SDKs.
+*/
+MIDL_INTERFACE("1DB9A292-CC78-4173-BE45-B61E67283EA7")
+IGameBarStatics_ : public IInspectable
+{
+public:
+    virtual HRESULT STDMETHODCALLTYPE add_VisibilityChanged( 
+        __FIEventHandler_1_IInspectable *handler,
+        Windows::Foundation::EventRegistrationToken *token) = 0;
+    
+    virtual HRESULT STDMETHODCALLTYPE remove_VisibilityChanged( 
+        Windows::Foundation::EventRegistrationToken token) = 0;
+    
+    virtual HRESULT STDMETHODCALLTYPE add_IsInputRedirectedChanged( 
+        __FIEventHandler_1_IInspectable *handler,
+        Windows::Foundation::EventRegistrationToken *token) = 0;
+    
+    virtual HRESULT STDMETHODCALLTYPE remove_IsInputRedirectedChanged( 
+        Windows::Foundation::EventRegistrationToken token) = 0;
+    
+    virtual HRESULT STDMETHODCALLTYPE get_Visible( 
+        boolean *value) = 0;
+    
+    virtual HRESULT STDMETHODCALLTYPE get_IsInputRedirected( 
+        boolean *value) = 0;
+};
+
+/* Declare the game bar's COM GUID */
+static GUID IID_IGameBarStatics_ = { MAKELONG(0xA292, 0x1DB9), 0xCC78, 0x4173, { 0xBE, 0x45, 0xB6, 0x1E, 0x67, 0x28, 0x3E, 0xA7 } };
+
+/* Retrieves a pointer to the game bar, or NULL if it is not available.
+   If a pointer is returned, it's ->Release() method must be called
+   after the caller has finished using it.
+*/
+static IGameBarStatics_ *
+WINRT_GetGameBar()
+{
+    wchar_t *wClassName = L"Windows.Gaming.UI.GameBar";
+    HSTRING hClassName;
+    IActivationFactory *pActivationFactory = NULL;
+    IGameBarStatics_ *pGameBar = NULL;
+    HRESULT hr;
+
+    hr = ::WindowsCreateString(wClassName, (UINT32)SDL_wcslen(wClassName), &hClassName);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = Windows::Foundation::GetActivationFactory(hClassName, &pActivationFactory);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    pActivationFactory->QueryInterface(IID_IGameBarStatics_, (void **) &pGameBar);
+
+done:
+    if (pActivationFactory) {
+        pActivationFactory->Release();
+    }
+    if (hClassName) {
+        ::WindowsDeleteString(hClassName);
+    }
+    return pGameBar;
+}
+
+static void
+WINRT_HandleGameBarIsInputRedirected_MainThread()
+{
+    IGameBarStatics_ *gameBar;
+    boolean isInputRedirected = 0;
+    if (!WINRT_MainThreadDispatcher) {
+        /* The game bar event handler has been deregistered! */
+        return;
+    }
+    gameBar = WINRT_GetGameBar();
+    if (!gameBar) {
+        /* Shouldn't happen, but just in case... */
+        return;
+    }
+    if (SUCCEEDED(gameBar->get_IsInputRedirected(&isInputRedirected))) {
+        if ( ! isInputRedirected) {
+            /* Input-control is now back to the SDL app. Restore the cursor,
+               in case Windows does not (it does not in either Win10
+               10.0.10240.0 or 10.0.10586.0, maybe later version(s) too.
+            */
+            SDL_Cursor *cursor = SDL_GetCursor();
+            SDL_SetCursor(cursor);
+        }
+    }
+    gameBar->Release();
+}
+
+static void
+WINRT_HandleGameBarIsInputRedirected_NonMainThread(Platform::Object ^ o1, Platform::Object ^o2)
+{
+    Windows::UI::Core::CoreDispatcher ^dispatcher = WINRT_MainThreadDispatcher.Resolve<Windows::UI::Core::CoreDispatcher>();
+    if (dispatcher) {
+        dispatcher->RunAsync(
+            Windows::UI::Core::CoreDispatcherPriority::Normal,
+            ref new Windows::UI::Core::DispatchedHandler(&WINRT_HandleGameBarIsInputRedirected_MainThread));
+    }
+}
+
+void
+WINRT_InitGameBar(_THIS)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata;
+    IGameBarStatics_ *gameBar = WINRT_GetGameBar();
+    if (gameBar) {
+        /* GameBar.IsInputRedirected events can come in via something other than
+           the main/SDL thread.
+
+           Get a WinRT 'CoreDispatcher' that can be used to call back into the
+           SDL thread.
+        */
+        WINRT_MainThreadDispatcher = Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher;
+        Windows::Foundation::EventHandler<Platform::Object ^> ^handler = \
+            ref new Windows::Foundation::EventHandler<Platform::Object ^>(&WINRT_HandleGameBarIsInputRedirected_NonMainThread);
+        __FIEventHandler_1_IInspectable * pHandler = reinterpret_cast<__FIEventHandler_1_IInspectable *>(handler);
+        gameBar->add_IsInputRedirectedChanged(pHandler, &driverdata->gameBarIsInputRedirectedToken);
+        gameBar->Release();
+    }
+}
+
+void
+WINRT_QuitGameBar(_THIS)
+{
+    SDL_VideoData *driverdata;
+    IGameBarStatics_ *gameBar;
+    if (!_this || !_this->driverdata) {
+        return;
+    }
+    gameBar = WINRT_GetGameBar();
+    if (!gameBar) {
+        return;
+    }
+    driverdata = (SDL_VideoData *)_this->driverdata;
+    if (driverdata->gameBarIsInputRedirectedToken.Value) {
+        gameBar->remove_IsInputRedirectedChanged(driverdata->gameBarIsInputRedirectedToken);
+        driverdata->gameBarIsInputRedirectedToken.Value = 0;
+    }
+    WINRT_MainThreadDispatcher = nullptr;
+    gameBar->Release();
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 35 - 0
src/video/winrt/SDL_winrtgamebar_cpp.h

@@ -0,0 +1,35 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_winrtgamebar_h_
+#define SDL_winrtgamebar_h_
+
+#ifdef __cplusplus
+/* These are exported as C++ functions, rather than C, to fix a compilation
+   bug with MSVC 2013, for Windows 8.x builds. */
+extern void WINRT_InitGameBar(_THIS);
+extern void WINRT_QuitGameBar(_THIS);
+#endif
+
+#endif /* SDL_winrtgamebar_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 466 - 0
src/video/winrt/SDL_winrtkeyboard.cpp

@@ -0,0 +1,466 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/* Windows-specific includes */
+#include <Windows.h>
+#include <agile.h>
+
+
+/* SDL-specific includes */
+#include "SDL.h"
+#include "SDL_winrtevents_c.h"
+
+extern "C" {
+#include "../../events/scancodes_windows.h"
+#include "../../events/SDL_keyboard_c.h"
+}
+
+
+static SDL_Scancode WinRT_Official_Keycodes[] = {
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.None -- 0 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.LeftButton -- 1 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.RightButton -- 2 */
+    SDL_SCANCODE_CANCEL,        /* VirtualKey.Cancel -- 3 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.MiddleButton -- 4 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.XButton1 -- 5 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.XButton2 -- 6 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 7 */
+    SDL_SCANCODE_BACKSPACE,     /* VirtualKey.Back -- 8 */
+    SDL_SCANCODE_TAB,           /* VirtualKey.Tab -- 9 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 10 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 11 */
+    SDL_SCANCODE_CLEAR,         /* VirtualKey.Clear -- 12 */
+    SDL_SCANCODE_RETURN,        /* VirtualKey.Enter -- 13 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 14 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 15 */
+    SDL_SCANCODE_LSHIFT,        /* VirtualKey.Shift -- 16 */
+    SDL_SCANCODE_LCTRL,         /* VirtualKey.Control -- 17 */
+    SDL_SCANCODE_MENU,          /* VirtualKey.Menu -- 18 */
+    SDL_SCANCODE_PAUSE,         /* VirtualKey.Pause -- 19 */
+    SDL_SCANCODE_CAPSLOCK,      /* VirtualKey.CapitalLock -- 20 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Kana or VirtualKey.Hangul -- 21 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 22 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Junja -- 23 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Final -- 24 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Hanja or VirtualKey.Kanji -- 25 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 26 */
+    SDL_SCANCODE_ESCAPE,        /* VirtualKey.Escape -- 27 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Convert -- 28 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.NonConvert -- 29 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Accept -- 30 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.ModeChange -- 31  (maybe SDL_SCANCODE_MODE ?) */
+    SDL_SCANCODE_SPACE,         /* VirtualKey.Space -- 32 */
+    SDL_SCANCODE_PAGEUP,        /* VirtualKey.PageUp -- 33 */
+    SDL_SCANCODE_PAGEDOWN,      /* VirtualKey.PageDown -- 34 */
+    SDL_SCANCODE_END,           /* VirtualKey.End -- 35 */
+    SDL_SCANCODE_HOME,          /* VirtualKey.Home -- 36 */
+    SDL_SCANCODE_LEFT,          /* VirtualKey.Left -- 37 */
+    SDL_SCANCODE_UP,            /* VirtualKey.Up -- 38 */
+    SDL_SCANCODE_RIGHT,         /* VirtualKey.Right -- 39 */
+    SDL_SCANCODE_DOWN,          /* VirtualKey.Down -- 40 */
+    SDL_SCANCODE_SELECT,        /* VirtualKey.Select -- 41 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Print -- 42  (maybe SDL_SCANCODE_PRINTSCREEN ?) */
+    SDL_SCANCODE_EXECUTE,       /* VirtualKey.Execute -- 43 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Snapshot -- 44 */
+    SDL_SCANCODE_INSERT,        /* VirtualKey.Insert -- 45 */
+    SDL_SCANCODE_DELETE,        /* VirtualKey.Delete -- 46 */
+    SDL_SCANCODE_HELP,          /* VirtualKey.Help -- 47 */
+    SDL_SCANCODE_0,             /* VirtualKey.Number0 -- 48 */
+    SDL_SCANCODE_1,             /* VirtualKey.Number1 -- 49 */
+    SDL_SCANCODE_2,             /* VirtualKey.Number2 -- 50 */
+    SDL_SCANCODE_3,             /* VirtualKey.Number3 -- 51 */
+    SDL_SCANCODE_4,             /* VirtualKey.Number4 -- 52 */
+    SDL_SCANCODE_5,             /* VirtualKey.Number5 -- 53 */
+    SDL_SCANCODE_6,             /* VirtualKey.Number6 -- 54 */
+    SDL_SCANCODE_7,             /* VirtualKey.Number7 -- 55 */
+    SDL_SCANCODE_8,             /* VirtualKey.Number8 -- 56 */
+    SDL_SCANCODE_9,             /* VirtualKey.Number9 -- 57 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 58 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 59 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 60 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 61 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 62 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 63 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 64 */
+    SDL_SCANCODE_A,             /* VirtualKey.A -- 65 */
+    SDL_SCANCODE_B,             /* VirtualKey.B -- 66 */
+    SDL_SCANCODE_C,             /* VirtualKey.C -- 67 */
+    SDL_SCANCODE_D,             /* VirtualKey.D -- 68 */
+    SDL_SCANCODE_E,             /* VirtualKey.E -- 69 */
+    SDL_SCANCODE_F,             /* VirtualKey.F -- 70 */
+    SDL_SCANCODE_G,             /* VirtualKey.G -- 71 */
+    SDL_SCANCODE_H,             /* VirtualKey.H -- 72 */
+    SDL_SCANCODE_I,             /* VirtualKey.I -- 73 */
+    SDL_SCANCODE_J,             /* VirtualKey.J -- 74 */
+    SDL_SCANCODE_K,             /* VirtualKey.K -- 75 */
+    SDL_SCANCODE_L,             /* VirtualKey.L -- 76 */
+    SDL_SCANCODE_M,             /* VirtualKey.M -- 77 */
+    SDL_SCANCODE_N,             /* VirtualKey.N -- 78 */
+    SDL_SCANCODE_O,             /* VirtualKey.O -- 79 */
+    SDL_SCANCODE_P,             /* VirtualKey.P -- 80 */
+    SDL_SCANCODE_Q,             /* VirtualKey.Q -- 81 */
+    SDL_SCANCODE_R,             /* VirtualKey.R -- 82 */
+    SDL_SCANCODE_S,             /* VirtualKey.S -- 83 */
+    SDL_SCANCODE_T,             /* VirtualKey.T -- 84 */
+    SDL_SCANCODE_U,             /* VirtualKey.U -- 85 */
+    SDL_SCANCODE_V,             /* VirtualKey.V -- 86 */
+    SDL_SCANCODE_W,             /* VirtualKey.W -- 87 */
+    SDL_SCANCODE_X,             /* VirtualKey.X -- 88 */
+    SDL_SCANCODE_Y,             /* VirtualKey.Y -- 89 */
+    SDL_SCANCODE_Z,             /* VirtualKey.Z -- 90 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.LeftWindows -- 91  (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?) */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.RightWindows -- 92  (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?) */
+    SDL_SCANCODE_APPLICATION,   /* VirtualKey.Application -- 93 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 94 */
+    SDL_SCANCODE_SLEEP,         /* VirtualKey.Sleep -- 95 */
+    SDL_SCANCODE_KP_0,          /* VirtualKey.NumberPad0 -- 96 */
+    SDL_SCANCODE_KP_1,          /* VirtualKey.NumberPad1 -- 97 */
+    SDL_SCANCODE_KP_2,          /* VirtualKey.NumberPad2 -- 98 */
+    SDL_SCANCODE_KP_3,          /* VirtualKey.NumberPad3 -- 99 */
+    SDL_SCANCODE_KP_4,          /* VirtualKey.NumberPad4 -- 100 */
+    SDL_SCANCODE_KP_5,          /* VirtualKey.NumberPad5 -- 101 */
+    SDL_SCANCODE_KP_6,          /* VirtualKey.NumberPad6 -- 102 */
+    SDL_SCANCODE_KP_7,          /* VirtualKey.NumberPad7 -- 103 */
+    SDL_SCANCODE_KP_8,          /* VirtualKey.NumberPad8 -- 104 */
+    SDL_SCANCODE_KP_9,          /* VirtualKey.NumberPad9 -- 105 */
+    SDL_SCANCODE_KP_MULTIPLY,   /* VirtualKey.Multiply -- 106 */
+    SDL_SCANCODE_KP_PLUS,       /* VirtualKey.Add -- 107 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Separator -- 108 */
+    SDL_SCANCODE_KP_MINUS,      /* VirtualKey.Subtract -- 109 */
+    SDL_SCANCODE_UNKNOWN,       /* VirtualKey.Decimal -- 110  (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?) */
+    SDL_SCANCODE_KP_DIVIDE,     /* VirtualKey.Divide -- 111 */
+    SDL_SCANCODE_F1,            /* VirtualKey.F1 -- 112 */
+    SDL_SCANCODE_F2,            /* VirtualKey.F2 -- 113 */
+    SDL_SCANCODE_F3,            /* VirtualKey.F3 -- 114 */
+    SDL_SCANCODE_F4,            /* VirtualKey.F4 -- 115 */
+    SDL_SCANCODE_F5,            /* VirtualKey.F5 -- 116 */
+    SDL_SCANCODE_F6,            /* VirtualKey.F6 -- 117 */
+    SDL_SCANCODE_F7,            /* VirtualKey.F7 -- 118 */
+    SDL_SCANCODE_F8,            /* VirtualKey.F8 -- 119 */
+    SDL_SCANCODE_F9,            /* VirtualKey.F9 -- 120 */
+    SDL_SCANCODE_F10,           /* VirtualKey.F10 -- 121 */
+    SDL_SCANCODE_F11,           /* VirtualKey.F11 -- 122 */
+    SDL_SCANCODE_F12,           /* VirtualKey.F12 -- 123 */
+    SDL_SCANCODE_F13,           /* VirtualKey.F13 -- 124 */
+    SDL_SCANCODE_F14,           /* VirtualKey.F14 -- 125 */
+    SDL_SCANCODE_F15,           /* VirtualKey.F15 -- 126 */
+    SDL_SCANCODE_F16,           /* VirtualKey.F16 -- 127 */
+    SDL_SCANCODE_F17,           /* VirtualKey.F17 -- 128 */
+    SDL_SCANCODE_F18,           /* VirtualKey.F18 -- 129 */
+    SDL_SCANCODE_F19,           /* VirtualKey.F19 -- 130 */
+    SDL_SCANCODE_F20,           /* VirtualKey.F20 -- 131 */
+    SDL_SCANCODE_F21,           /* VirtualKey.F21 -- 132 */
+    SDL_SCANCODE_F22,           /* VirtualKey.F22 -- 133 */
+    SDL_SCANCODE_F23,           /* VirtualKey.F23 -- 134 */
+    SDL_SCANCODE_F24,           /* VirtualKey.F24 -- 135 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 136 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 137 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 138 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 139 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 140 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 141 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 142 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 143 */
+    SDL_SCANCODE_NUMLOCKCLEAR,  /* VirtualKey.NumberKeyLock -- 144 */
+    SDL_SCANCODE_SCROLLLOCK,    /* VirtualKey.Scroll -- 145 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 146 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 147 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 148 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 149 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 150 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 151 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 152 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 153 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 154 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 155 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 156 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 157 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 158 */
+    SDL_SCANCODE_UNKNOWN,       /* -- 159 */
+    SDL_SCANCODE_LSHIFT,        /* VirtualKey.LeftShift -- 160 */
+    SDL_SCANCODE_RSHIFT,        /* VirtualKey.RightShift -- 161 */
+    SDL_SCANCODE_LCTRL,         /* VirtualKey.LeftControl -- 162 */
+    SDL_SCANCODE_RCTRL,         /* VirtualKey.RightControl -- 163 */
+    SDL_SCANCODE_MENU,          /* VirtualKey.LeftMenu -- 164 */
+    SDL_SCANCODE_MENU,          /* VirtualKey.RightMenu -- 165 */
+    SDL_SCANCODE_AC_BACK,       /* VirtualKey.GoBack -- 166 : The go back key. */
+    SDL_SCANCODE_AC_FORWARD,    /* VirtualKey.GoForward -- 167 : The go forward key. */
+    SDL_SCANCODE_AC_REFRESH,    /* VirtualKey.Refresh -- 168 : The refresh key. */
+    SDL_SCANCODE_AC_STOP,       /* VirtualKey.Stop -- 169 : The stop key. */
+    SDL_SCANCODE_AC_SEARCH,     /* VirtualKey.Search -- 170 : The search key. */
+    SDL_SCANCODE_AC_BOOKMARKS,  /* VirtualKey.Favorites -- 171 : The favorites key. */
+    SDL_SCANCODE_AC_HOME        /* VirtualKey.GoHome -- 172 : The go home key. */
+};
+
+/* Attempt to translate a keycode that isn't listed in WinRT's VirtualKey enum.
+ */
+static SDL_Scancode
+WINRT_TranslateUnofficialKeycode(int keycode)
+{
+    switch (keycode) {
+        case 173: return SDL_SCANCODE_MUTE;         /* VK_VOLUME_MUTE */
+        case 174: return SDL_SCANCODE_VOLUMEDOWN;   /* VK_VOLUME_DOWN */
+        case 175: return SDL_SCANCODE_VOLUMEUP;     /* VK_VOLUME_UP */
+        case 176: return SDL_SCANCODE_AUDIONEXT;    /* VK_MEDIA_NEXT_TRACK */
+        case 177: return SDL_SCANCODE_AUDIOPREV;    /* VK_MEDIA_PREV_TRACK */
+        // case 178: return ;                       /* VK_MEDIA_STOP */
+        case 179: return SDL_SCANCODE_AUDIOPLAY;    /* VK_MEDIA_PLAY_PAUSE */
+        case 180: return SDL_SCANCODE_MAIL;         /* VK_LAUNCH_MAIL */
+        case 181: return SDL_SCANCODE_MEDIASELECT;  /* VK_LAUNCH_MEDIA_SELECT */
+        // case 182: return ;                       /* VK_LAUNCH_APP1 */
+        case 183: return SDL_SCANCODE_CALCULATOR;   /* VK_LAUNCH_APP2 */
+        // case 184: return ;                       /* ... reserved ... */
+        // case 185: return ;                       /* ... reserved ... */
+        case 186: return SDL_SCANCODE_SEMICOLON;    /* VK_OEM_1, ';:' key on US standard keyboards */
+        case 187: return SDL_SCANCODE_EQUALS;       /* VK_OEM_PLUS */
+        case 188: return SDL_SCANCODE_COMMA;        /* VK_OEM_COMMA */
+        case 189: return SDL_SCANCODE_MINUS;        /* VK_OEM_MINUS */
+        case 190: return SDL_SCANCODE_PERIOD;       /* VK_OEM_PERIOD */
+        case 191: return SDL_SCANCODE_SLASH;        /* VK_OEM_2, '/?' key on US standard keyboards */
+        case 192: return SDL_SCANCODE_GRAVE;        /* VK_OEM_3, '`~' key on US standard keyboards */
+        // ?
+        // ... reserved or unassigned ...
+        // ?
+        case 219: return SDL_SCANCODE_LEFTBRACKET;  /* VK_OEM_4, '[{' key on US standard keyboards */
+        case 220: return SDL_SCANCODE_BACKSLASH;    /* VK_OEM_5, '\|' key on US standard keyboards */
+        case 221: return SDL_SCANCODE_RIGHTBRACKET; /* VK_OEM_6, ']}' key on US standard keyboards */
+        case 222: return SDL_SCANCODE_APOSTROPHE;   /* VK_OEM_7, 'single/double quote' on US standard keyboards */
+        default: break;
+    }
+    return SDL_SCANCODE_UNKNOWN;
+}
+
+static SDL_Scancode
+WINRT_TranslateKeycode(int keycode, unsigned int nativeScancode)
+{
+    // TODO, WinRT: try filling out the WinRT keycode table as much as possible, using the Win32 table for interpretation hints
+
+    SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
+
+    /* HACK ALERT: At least one VirtualKey constant (Shift) with a left/right
+     * designation might not get reported with its correct handedness, however
+     * its hardware scan code can fill in the gaps.  If this is detected,
+     * use the hardware scan code to try telling if the left, or the right
+     * side's key was used.
+     *
+     * If Microsoft ever allows MapVirtualKey or MapVirtualKeyEx to be used
+     * in WinRT apps, or something similar to these (it doesn't appear to be,
+     * at least not for Windows [Phone] 8/8.1, as of Oct 24, 2014), then this
+     * hack might become deprecated, or obsolete.
+     */
+    if (nativeScancode < SDL_arraysize(windows_scancode_table)) {
+        switch (keycode) {
+            case 16:    // VirtualKey.Shift
+                switch (windows_scancode_table[nativeScancode]) {
+                    case SDL_SCANCODE_LSHIFT:
+                    case SDL_SCANCODE_RSHIFT:
+                        return windows_scancode_table[nativeScancode];
+                }
+                break;
+            
+            // Add others, as necessary.
+            //
+            // Unfortunately, this hack doesn't seem to work in determining
+            // handedness with Control keys.
+
+            default:
+                break;
+        }
+    }
+
+    /* Try to get a documented, WinRT, 'VirtualKey' next (as documented at
+       http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.virtualkey.aspx ).
+       If that fails, fall back to a Win32 virtual key.
+       If that fails, attempt to fall back to a scancode-derived key.
+    */
+    if (keycode < SDL_arraysize(WinRT_Official_Keycodes)) {
+        scancode = WinRT_Official_Keycodes[keycode];
+    }
+    if (scancode == SDL_SCANCODE_UNKNOWN) {
+        scancode = WINRT_TranslateUnofficialKeycode(keycode);
+    }
+    if (scancode == SDL_SCANCODE_UNKNOWN) {
+        if (nativeScancode < SDL_arraysize(windows_scancode_table)) {
+            scancode = windows_scancode_table[nativeScancode];
+        }
+    }
+    /*
+    if (scancode == SDL_SCANCODE_UNKNOWN) {
+        SDL_Log("WinRT TranslateKeycode, unknown keycode=%d\n", (int)keycode);
+    }
+    */
+    return scancode;
+}
+
+void
+WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args)
+{
+    SDL_Scancode sdlScancode = WINRT_TranslateKeycode((int)args->VirtualKey, args->KeyStatus.ScanCode);
+#if 0
+    SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode);
+    SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, "
+            "repeat count=%d, native scan code=0x%x, was down?=%s, vkey=%d, "
+            "sdl scan code=%d (%s), sdl key code=%d (%s)\n",
+        (args->Handled ? "1" : "0"),
+        (args->KeyStatus.IsExtendedKey ? "1" : "0"),
+        (args->KeyStatus.IsKeyReleased ? "1" : "0"),
+        (args->KeyStatus.IsMenuKeyDown ? "1" : "0"),
+        args->KeyStatus.RepeatCount,
+        args->KeyStatus.ScanCode,
+        (args->KeyStatus.WasKeyDown ? "1" : "0"),
+        args->VirtualKey,
+        sdlScancode,
+        SDL_GetScancodeName(sdlScancode),
+        keycode,
+        SDL_GetKeyName(keycode));
+    //args->Handled = true;
+#endif
+    SDL_SendKeyboardKey(SDL_PRESSED, sdlScancode);
+}
+
+void
+WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args)
+{
+    SDL_Scancode sdlScancode = WINRT_TranslateKeycode((int)args->VirtualKey, args->KeyStatus.ScanCode);
+#if 0
+    SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode);
+    SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, "
+            "repeat count=%d, native scan code=0x%x, was down?=%s, vkey=%d, "
+            "sdl scan code=%d (%s), sdl key code=%d (%s)\n",
+        (args->Handled ? "1" : "0"),
+        (args->KeyStatus.IsExtendedKey ? "1" : "0"),
+        (args->KeyStatus.IsKeyReleased ? "1" : "0"),
+        (args->KeyStatus.IsMenuKeyDown ? "1" : "0"),
+        args->KeyStatus.RepeatCount,
+        args->KeyStatus.ScanCode,
+        (args->KeyStatus.WasKeyDown ? "1" : "0"),
+        args->VirtualKey,
+        sdlScancode,
+        SDL_GetScancodeName(sdlScancode),
+        keycode,
+        SDL_GetKeyName(keycode));
+    //args->Handled = true;
+#endif
+    SDL_SendKeyboardKey(SDL_RELEASED, sdlScancode);
+}
+
+void
+WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArgs ^args)
+{
+    wchar_t src_ucs2[2];
+    char dest_utf8[16];
+    int result;
+
+    /* Setup src */
+    src_ucs2[0] = args->KeyCode;
+    src_ucs2[1] = L'\0';
+
+    /* Convert the text, then send an SDL_TEXTINPUT event. */
+    result = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)&src_ucs2, -1, (LPSTR)dest_utf8, sizeof(dest_utf8), NULL, NULL);
+    if (result > 0) {
+        SDL_SendKeyboardText(dest_utf8);
+    }
+}
+
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+
+static bool WINRT_InputPaneVisible = false;
+
+void WINTRT_OnInputPaneShowing(Windows::UI::ViewManagement::InputPane ^ sender, Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^ args)
+{
+    WINRT_InputPaneVisible = true;
+}
+
+void WINTRT_OnInputPaneHiding(Windows::UI::ViewManagement::InputPane ^ sender, Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^ args)
+{
+    WINRT_InputPaneVisible = false;
+}
+
+void WINTRT_InitialiseInputPaneEvents(_THIS)
+{
+    using namespace Windows::UI::ViewManagement;
+    InputPane ^ inputPane = InputPane::GetForCurrentView();
+    if (inputPane) {
+        inputPane->Showing += ref new Windows::Foundation::TypedEventHandler<Windows::UI::ViewManagement::InputPane ^, 
+            Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^>(&WINTRT_OnInputPaneShowing);
+        inputPane->Hiding += ref new Windows::Foundation::TypedEventHandler<Windows::UI::ViewManagement::InputPane ^, 
+            Windows::UI::ViewManagement::InputPaneVisibilityEventArgs ^>(&WINTRT_OnInputPaneHiding);
+    }
+}
+
+SDL_bool WINRT_HasScreenKeyboardSupport(_THIS)
+{
+    return SDL_TRUE;
+}
+
+void WINRT_ShowScreenKeyboard(_THIS, SDL_Window *window)
+{
+    using namespace Windows::UI::ViewManagement;
+    InputPane ^ inputPane = InputPane::GetForCurrentView();
+    if (inputPane) {
+        inputPane->TryShow();
+    }
+}
+
+void WINRT_HideScreenKeyboard(_THIS, SDL_Window *window)
+{
+    using namespace Windows::UI::ViewManagement;
+    InputPane ^ inputPane = InputPane::GetForCurrentView();
+    if (inputPane) {
+        inputPane->TryHide();
+    }
+}
+
+SDL_bool WINRT_IsScreenKeyboardShown(_THIS, SDL_Window *window)
+{
+    using namespace Windows::UI::ViewManagement;
+    InputPane ^ inputPane = InputPane::GetForCurrentView();
+    if (inputPane) {
+        switch (SDL_WinRTGetDeviceFamily()) {
+        case SDL_WINRT_DEVICEFAMILY_XBOX:
+            //Documentation recommends using inputPane->Visible 
+            //https://learn.microsoft.com/en-us/uwp/api/windows.ui.viewmanagement.inputpane.visible?view=winrt-22621
+            //This does not seem to work on latest UWP/Xbox.
+            //Workaround: Listen to Showing/Hiding events
+            if (WINRT_InputPaneVisible) {
+                return SDL_TRUE;
+            }
+            break;
+        default:
+            //OccludedRect is recommend on universal apps per docs
+            //https://learn.microsoft.com/en-us/uwp/api/windows.ui.viewmanagement.inputpane.visible?view=winrt-22621
+            Windows::Foundation::Rect rect = inputPane->OccludedRect;
+            if (rect.Width > 0 && rect.Height > 0) {
+                return SDL_TRUE;
+            }
+            break;
+        }
+    }
+    return SDL_FALSE;
+}
+
+#endif  // NTDDI_VERSION >= ...
+
+#endif // SDL_VIDEO_DRIVER_WINRT

+ 118 - 0
src/video/winrt/SDL_winrtmessagebox.cpp

@@ -0,0 +1,118 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+extern "C" {
+#include "SDL_messagebox.h"
+#include "../../core/windows/SDL_windows.h"
+}
+
+#include "SDL_winrtevents_c.h"
+
+#include <windows.ui.popups.h>
+using namespace Platform;
+using namespace Windows::Foundation;
+using namespace Windows::UI::Popups;
+
+static String ^
+WINRT_UTF8ToPlatformString(const char * str)
+{
+    wchar_t * wstr = WIN_UTF8ToString(str);
+    String ^ rtstr = ref new String(wstr);
+    SDL_free(wstr);
+    return rtstr;
+}
+
+extern "C" int
+WINRT_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
+{
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
+    /* Sadly, Windows Phone 8 doesn't include the MessageDialog class that
+     * Windows 8.x/RT does, even though MSDN's reference documentation for
+     * Windows Phone 8 mentions it.
+     * 
+     * The .NET runtime on Windows Phone 8 does, however, include a
+     * MessageBox class.  Perhaps this could be called, somehow?
+     */
+    return SDL_SetError("SDL_messagebox support is not available for Windows Phone 8.0");
+#else
+    SDL_VideoDevice *_this = SDL_GetVideoDevice();
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    const int maxbuttons = 2;
+    const char * platform = "Windows Phone 8.1+";
+#else
+    const int maxbuttons = 3;
+    const char * platform = "Windows 8.x";
+#endif
+
+    if (messageboxdata->numbuttons > maxbuttons) {
+        return SDL_SetError("WinRT's MessageDialog only supports %d buttons, at most, on %s. %d were requested.",
+            maxbuttons, platform, messageboxdata->numbuttons);
+    }
+
+    /* Build a MessageDialog object and its buttons */
+    MessageDialog ^ dialog = ref new MessageDialog(WINRT_UTF8ToPlatformString(messageboxdata->message));
+    dialog->Title = WINRT_UTF8ToPlatformString(messageboxdata->title);
+    for (int i = 0; i < messageboxdata->numbuttons; ++i) {
+        const SDL_MessageBoxButtonData *sdlButton;
+        if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
+            sdlButton = &messageboxdata->buttons[messageboxdata->numbuttons - 1 - i];
+        } else {
+            sdlButton = &messageboxdata->buttons[i];
+        }
+        UICommand ^ button = ref new UICommand(WINRT_UTF8ToPlatformString(sdlButton->text));
+        button->Id = IntPtr((int)((size_t)(sdlButton - messageboxdata->buttons)));
+        dialog->Commands->Append(button);
+        if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
+            dialog->CancelCommandIndex = i;
+        }
+        if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
+            dialog->DefaultCommandIndex = i;
+        }
+    }
+
+    /* Display the MessageDialog, then wait for it to be closed */
+    /* TODO, WinRT: Find a way to redraw MessageDialog instances if a GPU device-reset occurs during the following event-loop */
+    auto operation = dialog->ShowAsync();
+    while (operation->Status == Windows::Foundation::AsyncStatus::Started) {
+        WINRT_PumpEvents(_this);
+    }
+
+    /* Retrieve results from the MessageDialog and process them accordingly */
+    if (operation->Status != Windows::Foundation::AsyncStatus::Completed) {
+        return SDL_SetError("An unknown error occurred in displaying the WinRT MessageDialog");
+    }
+    if (buttonid) {
+        IntPtr results = safe_cast<IntPtr>(operation->GetResults()->Id);
+        int clicked_index = results.ToInt32();
+        *buttonid = messageboxdata->buttons[clicked_index].buttonid;
+    }
+    return 0;
+#endif /* if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP / else */
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 29 - 0
src/video/winrt/SDL_winrtmessagebox.h

@@ -0,0 +1,29 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+extern int WINRT_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 222 - 0
src/video/winrt/SDL_winrtmouse.cpp

@@ -0,0 +1,222 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/*
+ * Windows includes:
+ */
+#include <Windows.h>
+#include <windows.ui.core.h>
+using namespace Windows::UI::Core;
+using Windows::UI::Core::CoreCursor;
+
+/*
+ * SDL includes:
+ */
+extern "C" {
+#include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_touch_c.h"
+#include "../SDL_sysvideo.h"
+#include "SDL_events.h"
+}
+
+#include "../../core/winrt/SDL_winrtapp_direct3d.h"
+#include "SDL_winrtvideo_cpp.h"
+#include "SDL_winrtmouse_c.h"
+
+
+extern "C" SDL_bool WINRT_UsingRelativeMouseMode = SDL_FALSE;
+
+
+static SDL_Cursor *
+WINRT_CreateSystemCursor(SDL_SystemCursor id)
+{
+    SDL_Cursor *cursor;
+    CoreCursorType cursorType = CoreCursorType::Arrow;
+
+    switch(id)
+    {
+    default:
+        SDL_assert(0);
+        return NULL;
+    case SDL_SYSTEM_CURSOR_ARROW:     cursorType = CoreCursorType::Arrow; break;
+    case SDL_SYSTEM_CURSOR_IBEAM:     cursorType = CoreCursorType::IBeam; break;
+    case SDL_SYSTEM_CURSOR_WAIT:      cursorType = CoreCursorType::Wait; break;
+    case SDL_SYSTEM_CURSOR_CROSSHAIR: cursorType = CoreCursorType::Cross; break;
+    case SDL_SYSTEM_CURSOR_WAITARROW: cursorType = CoreCursorType::Wait; break;
+    case SDL_SYSTEM_CURSOR_SIZENWSE:  cursorType = CoreCursorType::SizeNorthwestSoutheast; break;
+    case SDL_SYSTEM_CURSOR_SIZENESW:  cursorType = CoreCursorType::SizeNortheastSouthwest; break;
+    case SDL_SYSTEM_CURSOR_SIZEWE:    cursorType = CoreCursorType::SizeWestEast; break;
+    case SDL_SYSTEM_CURSOR_SIZENS:    cursorType = CoreCursorType::SizeNorthSouth; break;
+    case SDL_SYSTEM_CURSOR_SIZEALL:   cursorType = CoreCursorType::SizeAll; break;
+    case SDL_SYSTEM_CURSOR_NO:        cursorType = CoreCursorType::UniversalNo; break;
+    case SDL_SYSTEM_CURSOR_HAND:      cursorType = CoreCursorType::Hand; break;
+    }
+
+    cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
+    if (cursor) {
+        /* Create a pointer to a COM reference to a cursor.  The extra
+           pointer is used (on top of the COM reference) to allow the cursor
+           to be referenced by the SDL_cursor's driverdata field, which is
+           a void pointer.
+        */
+        CoreCursor ^* theCursor = new CoreCursor^(nullptr);
+        *theCursor = ref new CoreCursor(cursorType, 0);
+        cursor->driverdata = (void *) theCursor;
+    } else {
+        SDL_OutOfMemory();
+    }
+
+    return cursor;
+}
+
+static SDL_Cursor *
+WINRT_CreateDefaultCursor()
+{
+    return WINRT_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
+}
+
+static void
+WINRT_FreeCursor(SDL_Cursor * cursor)
+{
+    if (cursor->driverdata) {
+        CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata;
+        *theCursor = nullptr;       // Release the COM reference to the CoreCursor
+        delete theCursor;           // Delete the pointer to the COM reference
+    }
+    SDL_free(cursor);
+}
+
+static int
+WINRT_ShowCursor(SDL_Cursor * cursor)
+{
+    // TODO, WinRT, XAML: make WINRT_ShowCursor work when XAML support is enabled.
+    if ( ! CoreWindow::GetForCurrentThread()) {
+        return 0;
+    }
+
+    CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
+    if (cursor) {
+        CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata;
+        coreWindow->PointerCursor = *theCursor;
+    } else {
+        // HACK ALERT: TL;DR - Hiding the cursor in WinRT/UWP apps is weird, and
+        //   a Win32-style cursor resource file must be directly included in apps,
+        //   otherwise hiding the cursor will cause mouse-motion data to never be
+        //   received.
+        //
+        // Here's the lengthy explanation:
+        //
+        // There are two ways to hide a cursor in WinRT/UWP apps.
+        // Both involve setting the WinRT CoreWindow's (which is somewhat analogous
+        // to a Win32 HWND) 'PointerCursor' property.
+        //
+        // The first way to hide a cursor sets PointerCursor to nullptr.  This
+        // is, arguably, the easiest to implement for an app.  It does have an
+        // unfortunate side-effect: it'll prevent mouse-motion events from being
+        // sent to the app (via CoreWindow).
+        //
+        // The second way to hide a cursor sets PointerCursor to a transparent
+        // cursor.  This allows mouse-motion events to be sent to the app, but is
+        // more difficult to set up, as:
+        //   1. WinRT/UWP, while providing a few stock cursors, does not provide
+        //      a completely transparent cursor.
+        //   2. WinRT/UWP allows apps to provide custom-built cursors, but *ONLY*
+        //      if they are linked directly inside the app, via Win32-style
+        //      cursor resource files.  APIs to create cursors at runtime are
+        //      not provided to apps, and attempting to link-to or use Win32
+        //      cursor-creation APIs could cause an app to fail Windows Store
+        //      certification.
+        //
+        // SDL can use either means of hiding the cursor.  It provides a Win32-style
+        // set of cursor resource files in its source distribution, inside
+        // src/main/winrt/.  If those files are linked to an SDL-for-WinRT/UWP app
+        // (by including them in a MSVC project, for example), SDL will attempt to
+        // use those, if and when the cursor is hidden via SDL APIs.  If those
+        // files are not linked in, SDL will attempt to hide the cursor via the
+        // 'set PointerCursor to nullptr' means (which, if you recall, causes
+        // mouse-motion data to NOT be sent to the app!).
+        //
+        // Tech notes:
+        //  - SDL's blank cursor resource uses a resource ID of 5000.
+        //  - SDL's cursor resources consist of the following two files:
+        //     - src/main/winrt/SDL3-WinRTResource_BlankCursor.cur -- cursor pixel data
+        //     - src/main/winrt/SDL3-WinRTResources.rc             -- declares the cursor resource, and its ID (of 5000)
+        //
+
+        const unsigned int win32CursorResourceID = 5000;  
+        CoreCursor ^ blankCursor = ref new CoreCursor(CoreCursorType::Custom, win32CursorResourceID);
+
+        // Set 'PointerCursor' to 'blankCursor' in a way that shouldn't throw
+        // an exception if the app hasn't loaded that resource.
+        ABI::Windows::UI::Core::ICoreCursor * iblankCursor = reinterpret_cast<ABI::Windows::UI::Core::ICoreCursor *>(blankCursor);
+        ABI::Windows::UI::Core::ICoreWindow * icoreWindow = reinterpret_cast<ABI::Windows::UI::Core::ICoreWindow *>(coreWindow);
+        HRESULT hr = icoreWindow->put_PointerCursor(iblankCursor);
+        if (FAILED(hr)) {
+            // The app doesn't contain the cursor resource, or some other error
+            // occurred.  Just use the other, but mouse-motion-preventing, means of
+            // hiding the cursor.
+            coreWindow->PointerCursor = nullptr;
+        }
+    }
+    return 0;
+}
+
+static int
+WINRT_SetRelativeMouseMode(SDL_bool enabled)
+{
+    WINRT_UsingRelativeMouseMode = enabled;
+    return 0;
+}
+
+void
+WINRT_InitMouse(_THIS)
+{
+    SDL_Mouse *mouse = SDL_GetMouse();
+
+    /* DLudwig, Dec 3, 2012: WinRT does not currently provide APIs for
+       the following features, AFAIK:
+        - custom cursors  (multiple system cursors are, however, available)
+        - programmatically moveable cursors
+    */
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+    //mouse->CreateCursor = WINRT_CreateCursor;
+    mouse->CreateSystemCursor = WINRT_CreateSystemCursor;
+    mouse->ShowCursor = WINRT_ShowCursor;
+    mouse->FreeCursor = WINRT_FreeCursor;
+    //mouse->WarpMouse = WINRT_WarpMouse;
+    mouse->SetRelativeMouseMode = WINRT_SetRelativeMouseMode;
+
+    SDL_SetDefaultCursor(WINRT_CreateDefaultCursor());
+#endif
+}
+
+void
+WINRT_QuitMouse(_THIS)
+{
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 40 - 0
src/video/winrt/SDL_winrtmouse_c.h

@@ -0,0 +1,40 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_winrtmouse_h_
+#define SDL_winrtmouse_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void WINRT_InitMouse(_THIS);
+extern void WINRT_QuitMouse(_THIS);
+extern SDL_bool WINRT_UsingRelativeMouseMode;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SDL_winrtmouse_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 203 - 0
src/video/winrt/SDL_winrtopengles.cpp

@@ -0,0 +1,203 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL
+
+/* EGL implementation of SDL OpenGL support */
+
+#include "SDL_winrtvideo_cpp.h"
+extern "C" {
+#include "SDL_winrtopengles.h"
+#include "SDL_loadso.h"
+#include "../SDL_egl_c.h"
+}
+
+/* Windows includes */
+#include <wrl/client.h>
+using namespace Windows::UI::Core;
+
+/* ANGLE/WinRT constants */
+static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0;
+#define EGL_PLATFORM_ANGLE_ANGLE                        0x3202
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE                   0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE      0x3204
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE      0x3205
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE             0x3208
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE            0x3209
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE       0x320B
+#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE  0x320F
+
+#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER   0x320B
+
+
+/*
+ * SDL/EGL top-level implementation
+ */
+
+extern "C" int
+WINRT_GLES_LoadLibrary(_THIS, const char *path)
+{
+    SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
+
+    if (SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0) != 0) {
+        return -1;
+    }
+
+    /* Load ANGLE/WinRT-specific functions */
+    CreateWinrtEglWindow_Old_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Old_Function) SDL_LoadFunction(_this->egl_data->opengl_dll_handle, "CreateWinrtEglWindow");
+    if (CreateWinrtEglWindow) {
+        /* 'CreateWinrtEglWindow' was found, which means that an an older
+         * version of ANGLE/WinRT is being used.  Continue setting up EGL,
+         * as appropriate to this version of ANGLE.
+         */
+
+        /* Create an ANGLE/WinRT EGL-window */
+        /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */
+        CoreWindow ^ native_win = CoreWindow::GetForCurrentThread();
+        Microsoft::WRL::ComPtr<IUnknown> cpp_win = reinterpret_cast<IUnknown *>(native_win);
+        HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow));
+        if (FAILED(result)) {
+            return -1;
+        }
+
+        /* Call eglGetDisplay and eglInitialize as appropriate.  On other
+         * platforms, this would probably get done by SDL_EGL_LoadLibrary,
+         * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of
+         * eglGetDisplay requires that a C++ object be passed into it, so the
+         * call will be made in this file, a C++ file, instead.
+         */
+        Microsoft::WRL::ComPtr<IUnknown> cpp_display = video_data->winrtEglWindow;
+        _this->egl_data->egl_display = ((eglGetDisplay_Old_Function)_this->egl_data->eglGetDisplay)(cpp_display);
+        if (!_this->egl_data->egl_display) {
+            return SDL_EGL_SetError("Could not get Windows 8.0 EGL display", "eglGetDisplay");
+        }
+
+        if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
+            return SDL_EGL_SetError("Could not initialize Windows 8.0 EGL", "eglInitialize");
+        }
+    } else {
+        /* Declare some ANGLE/EGL initialization property-sets, as suggested by
+         * MSOpenTech's ANGLE-for-WinRT template apps:
+         */
+        const EGLint defaultDisplayAttributes[] =
+        {
+            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+            EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+            EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+            EGL_NONE,
+        };
+
+        const EGLint fl9_3DisplayAttributes[] =
+        {
+            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+            EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
+            EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
+            EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+            EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+            EGL_NONE,
+        };
+
+        const EGLint warpDisplayAttributes[] =
+        {
+            EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+            EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
+            EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE,
+            EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE,
+            EGL_NONE,
+        };
+
+        /* 'CreateWinrtEglWindow' was NOT found, which either means that a
+         * newer version of ANGLE/WinRT is being used, or that we don't have
+         * a valid copy of ANGLE.
+         *
+         * Try loading ANGLE as if it were the newer version.
+         */
+        eglGetPlatformDisplayEXT_Function eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_Function)_this->egl_data->eglGetProcAddress("eglGetPlatformDisplayEXT");
+        if (!eglGetPlatformDisplayEXT) {
+            return SDL_EGL_SetError("Could not retrieve ANGLE/WinRT display function(s)", "eglGetProcAddress");
+        }
+
+#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
+        /* Try initializing EGL at D3D11 Feature Level 10_0+ (which is not
+         * supported on WinPhone 8.x.
+         */
+        _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes);
+        if (!_this->egl_data->egl_display) {
+            return SDL_EGL_SetError("Could not get EGL display for Direct3D 10_0+", "eglGetPlatformDisplayEXT");
+        }
+
+        if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE)
+#endif
+        {
+            /* Try initializing EGL at D3D11 Feature Level 9_3, in case the
+             * 10_0 init fails, or we're on Windows Phone (which only supports
+             * 9_3).
+             */
+            _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes);
+            if (!_this->egl_data->egl_display) {
+                return SDL_EGL_SetError("Could not get EGL display for Direct3D 9_3", "eglGetPlatformDisplayEXT");
+            }
+
+            if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
+                /* Try initializing EGL at D3D11 Feature Level 11_0 on WARP
+                 * (a Windows-provided, software rasterizer) if all else fails.
+                 */
+                _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes);
+                if (!_this->egl_data->egl_display) {
+                    return SDL_EGL_SetError("Could not get EGL display for Direct3D WARP", "eglGetPlatformDisplayEXT");
+                }
+
+                if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
+                    return SDL_EGL_SetError("Could not initialize WinRT 8.x+ EGL", "eglInitialize");
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+extern "C" void
+WINRT_GLES_UnloadLibrary(_THIS)
+{
+    SDL_VideoData *video_data = (SDL_VideoData *)_this->driverdata;
+
+    /* Release SDL's own COM reference to the ANGLE/WinRT IWinrtEglWindow */
+    if (video_data->winrtEglWindow) {
+        video_data->winrtEglWindow->Release();
+        video_data->winrtEglWindow = nullptr;
+    }
+
+    /* Perform the bulk of the unloading */
+    SDL_EGL_UnloadLibrary(_this);
+}
+
+extern "C" {
+SDL_EGL_CreateContext_impl(WINRT)
+SDL_EGL_SwapWindow_impl(WINRT)
+SDL_EGL_MakeCurrent_impl(WINRT)
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */
+
+/* vi: set ts=4 sw=4 expandtab: */
+

+ 70 - 0
src/video/winrt/SDL_winrtopengles.h

@@ -0,0 +1,70 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifndef SDL_winrtopengles_h_
+#define SDL_winrtopengles_h_
+
+#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL
+
+#include "../SDL_sysvideo.h"
+#include "../SDL_egl_c.h"
+
+/* OpenGLES functions */
+#define WINRT_GLES_GetAttribute SDL_EGL_GetAttribute
+#define WINRT_GLES_GetProcAddress SDL_EGL_GetProcAddress
+#define WINRT_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
+#define WINRT_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
+#define WINRT_GLES_DeleteContext SDL_EGL_DeleteContext
+
+extern int WINRT_GLES_LoadLibrary(_THIS, const char *path);
+extern void WINRT_GLES_UnloadLibrary(_THIS);
+extern SDL_GLContext WINRT_GLES_CreateContext(_THIS, SDL_Window * window);
+extern int WINRT_GLES_SwapWindow(_THIS, SDL_Window * window);
+extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+
+
+#ifdef __cplusplus
+
+/* Typedefs for ANGLE/WinRT's C++-based native-display and native-window types,
+ * which are used when calling eglGetDisplay and eglCreateWindowSurface.
+ */
+typedef Microsoft::WRL::ComPtr<IUnknown> WINRT_EGLNativeWindowType_Old;
+
+/* Function pointer typedefs for 'old' ANGLE/WinRT's functions, which may
+ * require that C++ objects be passed in:
+ */
+typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Old_Function)(WINRT_EGLNativeWindowType_Old);
+typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Old_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType_Old, const EGLint *);
+typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Old_Function)(Microsoft::WRL::ComPtr<IUnknown>, int, IUnknown ** result);
+
+#endif /* __cplusplus */
+
+/* Function pointer typedefs for 'new' ANGLE/WinRT functions, which, unlike
+ * the old functions, do not require C++ support and work with plain C.
+ */
+typedef EGLDisplay (EGLAPIENTRY *eglGetPlatformDisplayEXT_Function)(EGLenum, void *, const EGLint *);
+
+#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */
+
+#endif /* SDL_winrtopengles_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 407 - 0
src/video/winrt/SDL_winrtpointerinput.cpp

@@ -0,0 +1,407 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/* SDL includes */
+#include "SDL_winrtevents_c.h"
+#include "SDL_winrtmouse_c.h"
+#include "SDL_winrtvideo_cpp.h"
+#include "SDL_system.h"
+
+extern "C" {
+#include "../SDL_sysvideo.h"
+#include "../../events/SDL_events_c.h"
+#include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_touch_c.h"
+}
+
+/* File-specific globals: */
+static SDL_TouchID WINRT_TouchID = 1;
+
+
+void
+WINRT_InitTouch(_THIS)
+{
+    SDL_AddTouch(WINRT_TouchID, SDL_TOUCH_DEVICE_DIRECT, "");
+}
+
+
+//
+// Applies necessary geometric transformations to raw cursor positions:
+//
+Windows::Foundation::Point
+WINRT_TransformCursorPosition(SDL_Window * window,
+                              Windows::Foundation::Point rawPosition,
+                              WINRT_CursorNormalizationType normalization)
+{
+    using namespace Windows::UI::Core;
+    using namespace Windows::Graphics::Display;
+
+    if (!window) {
+        return rawPosition;
+    }
+
+    SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata;
+    if (windowData->coreWindow == nullptr) {
+        // For some reason, the window isn't associated with a CoreWindow.
+        // This might end up being the case as XAML support is extended.
+        // For now, if there's no CoreWindow attached to the SDL_Window,
+        // don't do any transforms.
+
+        // TODO, WinRT: make sure touch input coordinate ranges are correct when using XAML support
+        return rawPosition;
+    }
+
+    // The CoreWindow can only be accessed on certain thread(s).
+    SDL_assert(CoreWindow::GetForCurrentThread() != nullptr);
+
+    CoreWindow ^ nativeWindow = windowData->coreWindow.Get();
+    Windows::Foundation::Point outputPosition;
+
+    // Compute coordinates normalized from 0..1.
+    // If the coordinates need to be sized to the SDL window,
+    // we'll do that after.
+#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
+    outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width;
+    outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height;
+#else
+    switch (WINRT_DISPLAY_PROPERTY(CurrentOrientation))
+    {
+        case DisplayOrientations::Portrait:
+            outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width;
+            outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height;
+            break;
+        case DisplayOrientations::PortraitFlipped:
+            outputPosition.X = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width);
+            outputPosition.Y = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height);
+            break;
+        case DisplayOrientations::Landscape:
+            outputPosition.X = rawPosition.Y / nativeWindow->Bounds.Height;
+            outputPosition.Y = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width);
+            break;
+        case DisplayOrientations::LandscapeFlipped:
+            outputPosition.X = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height);
+            outputPosition.Y = rawPosition.X / nativeWindow->Bounds.Width;
+            break;
+        default:
+            break;
+    }
+#endif
+
+    if (normalization == TransformToSDLWindowSize) {
+        outputPosition.X *= ((float32) window->w);
+        outputPosition.Y *= ((float32) window->h);
+    }
+
+    return outputPosition;
+}
+
+SDL_bool
+WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt, Uint8 *button, Uint8 *pressed)
+{
+    using namespace Windows::UI::Input;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    *button = SDL_BUTTON_LEFT;
+    return SDL_TRUE;
+#else
+    switch (pt->Properties->PointerUpdateKind)
+    {
+        case PointerUpdateKind::LeftButtonPressed:
+        case PointerUpdateKind::LeftButtonReleased:
+            *button = SDL_BUTTON_LEFT;
+            *pressed = (pt->Properties->PointerUpdateKind == PointerUpdateKind::LeftButtonPressed);
+            return SDL_TRUE;
+
+        case PointerUpdateKind::RightButtonPressed:
+        case PointerUpdateKind::RightButtonReleased:
+            *button = SDL_BUTTON_RIGHT;
+            *pressed = (pt->Properties->PointerUpdateKind == PointerUpdateKind::RightButtonPressed);
+            return SDL_TRUE;
+
+        case PointerUpdateKind::MiddleButtonPressed:
+        case PointerUpdateKind::MiddleButtonReleased:
+            *button = SDL_BUTTON_MIDDLE;
+            *pressed = (pt->Properties->PointerUpdateKind == PointerUpdateKind::MiddleButtonPressed);
+            return SDL_TRUE;
+
+        case PointerUpdateKind::XButton1Pressed:
+        case PointerUpdateKind::XButton1Released:
+            *button = SDL_BUTTON_X1;
+            *pressed = (pt->Properties->PointerUpdateKind == PointerUpdateKind::XButton1Pressed);
+            return SDL_TRUE;
+
+        case PointerUpdateKind::XButton2Pressed:
+        case PointerUpdateKind::XButton2Released:
+            *button = SDL_BUTTON_X2;
+            *pressed = (pt->Properties->PointerUpdateKind == PointerUpdateKind::XButton2Pressed);
+            return SDL_TRUE;
+
+        default:
+            break;
+    }
+#endif
+
+    *button = 0;
+    *pressed = 0;
+    return SDL_FALSE;
+}
+
+//const char *
+//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind)
+//{
+//    using namespace Windows::UI::Input;
+//
+//    switch (kind)
+//    {
+//        case PointerUpdateKind::Other:
+//            return "Other";
+//        case PointerUpdateKind::LeftButtonPressed:
+//            return "LeftButtonPressed";
+//        case PointerUpdateKind::LeftButtonReleased:
+//            return "LeftButtonReleased";
+//        case PointerUpdateKind::RightButtonPressed:
+//            return "RightButtonPressed";
+//        case PointerUpdateKind::RightButtonReleased:
+//            return "RightButtonReleased";
+//        case PointerUpdateKind::MiddleButtonPressed:
+//            return "MiddleButtonPressed";
+//        case PointerUpdateKind::MiddleButtonReleased:
+//            return "MiddleButtonReleased";
+//        case PointerUpdateKind::XButton1Pressed:
+//            return "XButton1Pressed";
+//        case PointerUpdateKind::XButton1Released:
+//            return "XButton1Released";
+//        case PointerUpdateKind::XButton2Pressed:
+//            return "XButton2Pressed";
+//        case PointerUpdateKind::XButton2Released:
+//            return "XButton2Released";
+//    }
+//
+//    return "";
+//}
+
+static bool
+WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+    return true;
+#else
+    using namespace Windows::Devices::Input;
+    switch (pointerPoint->PointerDevice->PointerDeviceType) {
+        case PointerDeviceType::Touch:
+        case PointerDeviceType::Pen:
+            return true;
+        default:
+            return false;
+    }
+#endif
+}
+
+void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+    if (!window) {
+        return;
+    }
+
+    if ( ! WINRT_IsTouchEvent(pointerPoint)) {
+        Uint8 button, pressed;
+        WINRT_GetSDLButtonForPointerPoint(pointerPoint, &button, &pressed);
+        SDL_assert(pressed == 1);
+        SDL_SendMouseButton(window, 0, SDL_PRESSED, button);
+    } else {
+        Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
+        Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize);
+
+        SDL_SendTouch(
+            WINRT_TouchID,
+            (SDL_FingerID) pointerPoint->PointerId,
+            window,
+            SDL_TRUE,
+            normalizedPoint.X,
+            normalizedPoint.Y,
+            pointerPoint->Properties->Pressure);
+    }
+}
+
+void
+WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+    if (!window || WINRT_UsingRelativeMouseMode) {
+        return;
+    }
+
+    Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
+    Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize);
+
+    if ( ! WINRT_IsTouchEvent(pointerPoint)) {
+        /* For some odd reason Moved events are used for multiple mouse buttons */
+        Uint8 button, pressed;
+        if (WINRT_GetSDLButtonForPointerPoint(pointerPoint, &button, &pressed)) {
+            SDL_SendMouseButton(window, 0, pressed, button);
+        }
+
+        SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y);
+    } else {
+        SDL_SendTouchMotion(
+            WINRT_TouchID,
+            (SDL_FingerID) pointerPoint->PointerId,
+            window,
+            normalizedPoint.X,
+            normalizedPoint.Y,
+            pointerPoint->Properties->Pressure);
+    }
+}
+
+void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+    if (!window) {
+        return;
+    }
+
+    if (!WINRT_IsTouchEvent(pointerPoint)) {
+        Uint8 button, pressed;
+        WINRT_GetSDLButtonForPointerPoint(pointerPoint, &button, &pressed);
+        SDL_assert(pressed == 0);
+        SDL_SendMouseButton(window, 0, SDL_RELEASED, button);
+    } else {
+        Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
+
+        SDL_SendTouch(
+            WINRT_TouchID,
+            (SDL_FingerID) pointerPoint->PointerId,
+            window,
+            SDL_FALSE,
+            normalizedPoint.X,
+            normalizedPoint.Y,
+            pointerPoint->Properties->Pressure);
+    }
+}
+
+void WINRT_ProcessPointerEnteredEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+    if (!window) {
+        return;
+    }
+
+    if (!WINRT_IsTouchEvent(pointerPoint)) {
+        SDL_SetMouseFocus(window);
+    }
+}
+
+void WINRT_ProcessPointerExitedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+    if (!window) {
+        return;
+    }
+
+    if (!WINRT_IsTouchEvent(pointerPoint)) {
+        SDL_SetMouseFocus(NULL);
+    }
+}
+
+void
+WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
+{
+    if (!window) {
+        return;
+    }
+
+    float motion = (float) pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA;
+    SDL_SendMouseWheel(window, 0, 0, (float) motion, SDL_MOUSEWHEEL_NORMAL);
+}
+
+void
+WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args)
+{
+    if (!window || !WINRT_UsingRelativeMouseMode) {
+        return;
+    }
+
+    // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
+    // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
+    // MouseDelta field often reports very large values.  More information
+    // on this can be found at the following pages on MSDN:
+    //  - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
+    //  - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
+    //
+    // The values do not appear to be as large when running on some systems,
+    // most notably a Surface RT.  Furthermore, the values returned by
+    // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
+    // method, do not ever appear to be large, even when MouseEventArgs'
+    // MouseDelta is reporting to the contrary.
+    //
+    // On systems with the large-values behavior, it appears that the values
+    // get reported as if the screen's size is 65536 units in both the X and Y
+    // dimensions.  This can be viewed by using Windows' now-private, "Raw Input"
+    // APIs.  (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
+    //
+    // MSDN's documentation on MouseEventArgs' MouseDelta field (at
+    // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
+    // does not seem to indicate (to me) that its values should be so large.  It
+    // says that its values should be a "change in screen location".  I could
+    // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see:
+    // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
+    // indicates that these values are in DIPs, which is the same unit used
+    // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
+    // property.  See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
+    // for details.)
+    //
+    // To note, PointerMoved events are sent a 'RawPosition' value (via the
+    // CurrentPoint property in MouseEventArgs), however these do not seem
+    // to exhibit the same large-value behavior.
+    //
+    // The values passed via PointerMoved events can't always be used for relative
+    // mouse motion, unfortunately.  Its values are bound to the cursor's position,
+    // which stops when it hits one of the screen's edges.  This can be a problem in
+    // first person shooters, whereby it is normal for mouse motion to travel far
+    // along any one axis for a period of time.  MouseMoved events do not have the
+    // screen-bounding limitation, and can be used regardless of where the system's
+    // cursor is.
+    //
+    // One possible workaround would be to programmatically set the cursor's
+    // position to the screen's center (when SDL's relative mouse mode is enabled),
+    // however WinRT does not yet seem to have the ability to set the cursor's
+    // position via a public API.  Win32 did this via an API call, SetCursorPos,
+    // however WinRT makes this function be private.  Apps that use it won't get
+    // approved for distribution in the Windows Store.  I've yet to be able to find
+    // a suitable, store-friendly counterpart for WinRT.
+    //
+    // There may be some room for a workaround whereby OnPointerMoved's values
+    // are compared to the values from OnMouseMoved in order to detect
+    // when this bug is active.  A suitable transformation could then be made to
+    // OnMouseMoved's values.  For now, however, the system-reported values are sent
+    // to SDL with minimal transformation: from native screen coordinates (in DIPs)
+    // to SDL window coordinates.
+    //
+    const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
+    const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs, TransformToSDLWindowSize);
+    SDL_SendMouseMotion(
+        window,
+        0,
+        1,
+        SDL_lroundf(mouseDeltaInSDLWindowCoords.X),
+        SDL_lroundf(mouseDeltaInSDLWindowCoords.Y));
+}
+
+#endif // SDL_VIDEO_DRIVER_WINRT

+ 907 - 0
src/video/winrt/SDL_winrtvideo.cpp

@@ -0,0 +1,907 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/* WinRT SDL video driver implementation
+
+   Initial work on this was done by David Ludwig (dludwig@pobox.com), and
+   was based off of SDL's "dummy" video driver.
+ */
+
+/* Standard C++11 includes */
+#include <functional>
+#include <string>
+#include <sstream>
+using namespace std;
+
+/* Windows includes */
+#include <agile.h>
+#include <windows.graphics.display.h>
+#include <windows.system.display.h>
+#include <dxgi.h>
+#include <dxgi1_2.h>
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::Foundation;
+using namespace Windows::Graphics::Display;
+using namespace Windows::UI::Core;
+using namespace Windows::UI::ViewManagement;
+
+
+/* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */
+static const GUID SDL_IID_IDisplayRequest   = { 0xe5732044, 0xf49f, 0x4b60, { 0x8d, 0xd4, 0x5e, 0x7e, 0x3a, 0x63, 0x2a, 0xc0 } };
+static const GUID SDL_IID_IDXGIFactory2     = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
+
+
+/* SDL includes */
+extern "C" {
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "../SDL_sysvideo.h"
+#include "../SDL_pixels_c.h"
+#include "../../events/SDL_events_c.h"
+#include "../../render/SDL_sysrender.h"
+#include "SDL_syswm.h"
+#include "SDL_winrtopengles.h"
+#include "../../core/windows/SDL_windows.h"
+}
+
+#include "../../core/winrt/SDL_winrtapp_direct3d.h"
+#include "../../core/winrt/SDL_winrtapp_xaml.h"
+#include "SDL_winrtvideo_cpp.h"
+#include "SDL_winrtevents_c.h"
+#include "SDL_winrtgamebar_cpp.h"
+#include "SDL_winrtmouse_c.h"
+#include "SDL_main.h"
+#include "SDL_system.h"
+#include "SDL_hints.h"
+
+
+/* Initialization/Query functions */
+static int WINRT_VideoInit(_THIS);
+static int WINRT_InitModes(_THIS);
+static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
+static void WINRT_VideoQuit(_THIS);
+
+
+/* Window functions */
+static int WINRT_CreateWindow(_THIS, SDL_Window * window);
+static void WINRT_SetWindowSize(_THIS, SDL_Window * window);
+static void WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
+static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
+static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
+
+
+/* Misc functions */
+static ABI::Windows::System::Display::IDisplayRequest * WINRT_CreateDisplayRequest(_THIS);
+extern void WINRT_SuspendScreenSaver(_THIS);
+
+
+/* SDL-internal globals: */
+SDL_Window * WINRT_GlobalSDLWindow = NULL;
+
+
+/* WinRT driver bootstrap functions */
+
+static void
+WINRT_DeleteDevice(SDL_VideoDevice * device)
+{
+    if (device->driverdata) {
+        SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
+        if (video_data->winrtEglWindow) {
+            video_data->winrtEglWindow->Release();
+        }
+        SDL_free(video_data);
+    }
+
+    SDL_free(device);
+}
+
+static SDL_VideoDevice *
+WINRT_CreateDevice(void)
+{
+    SDL_VideoDevice *device;
+    SDL_VideoData *data;
+
+    /* Initialize all variables that we clean on shutdown */
+    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
+    if (!device) {
+        SDL_OutOfMemory();
+        return (0);
+    }
+
+    data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
+    if (!data) {
+        SDL_OutOfMemory();
+        SDL_free(device);
+        return (0);
+    }
+    device->driverdata = data;
+
+    /* Set the function pointers */
+    device->VideoInit = WINRT_VideoInit;
+    device->VideoQuit = WINRT_VideoQuit;
+    device->CreateSDLWindow = WINRT_CreateWindow;
+    device->SetWindowSize = WINRT_SetWindowSize;
+    device->SetWindowFullscreen = WINRT_SetWindowFullscreen;
+    device->DestroyWindow = WINRT_DestroyWindow;
+    device->SetDisplayMode = WINRT_SetDisplayMode;
+    device->PumpEvents = WINRT_PumpEvents;
+    device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
+    device->SuspendScreenSaver = WINRT_SuspendScreenSaver;
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+    device->HasScreenKeyboardSupport = WINRT_HasScreenKeyboardSupport;
+    device->ShowScreenKeyboard = WINRT_ShowScreenKeyboard;
+    device->HideScreenKeyboard = WINRT_HideScreenKeyboard;
+    device->IsScreenKeyboardShown = WINRT_IsScreenKeyboardShown;
+
+    WINTRT_InitialiseInputPaneEvents(device);
+#endif
+
+#ifdef SDL_VIDEO_OPENGL_EGL
+    device->GL_LoadLibrary = WINRT_GLES_LoadLibrary;
+    device->GL_GetProcAddress = WINRT_GLES_GetProcAddress;
+    device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary;
+    device->GL_CreateContext = WINRT_GLES_CreateContext;
+    device->GL_MakeCurrent = WINRT_GLES_MakeCurrent;
+    device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval;
+    device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval;
+    device->GL_SwapWindow = WINRT_GLES_SwapWindow;
+    device->GL_DeleteContext = WINRT_GLES_DeleteContext;
+#endif
+    device->free = WINRT_DeleteDevice;
+
+    return device;
+}
+
+#define WINRTVID_DRIVER_NAME "winrt"
+VideoBootStrap WINRT_bootstrap = {
+    WINRTVID_DRIVER_NAME, "SDL WinRT video driver",
+    WINRT_CreateDevice
+};
+
+static void SDLCALL
+WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
+{
+    SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0);
+
+    /* HACK: prevent SDL from altering an app's .appxmanifest-set orientation
+     * from being changed on startup, by detecting when SDL_HINT_ORIENTATIONS
+     * is getting registered.
+     *
+     * TODO, WinRT: consider reading in an app's .appxmanifest file, and apply its orientation when 'newValue == NULL'.
+     */
+    if ((oldValue == NULL) && (newValue == NULL)) {
+        return;
+    }
+
+    // Start with no orientation flags, then add each in as they're parsed
+    // from newValue.
+    unsigned int orientationFlags = 0;
+    if (newValue) {
+        std::istringstream tokenizer(newValue);
+        while (!tokenizer.eof()) {
+            std::string orientationName;
+            std::getline(tokenizer, orientationName, ' ');
+            if (orientationName == "LandscapeLeft") {
+                orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
+            } else if (orientationName == "LandscapeRight") {
+                orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
+            } else if (orientationName == "Portrait") {
+                orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
+            } else if (orientationName == "PortraitUpsideDown") {
+                orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
+            }
+        }
+    }
+
+    // If no valid orientation flags were specified, use a reasonable set of defaults:
+    if (!orientationFlags) {
+        // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
+        orientationFlags = (unsigned int) ( \
+            DisplayOrientations::Landscape |
+            DisplayOrientations::LandscapeFlipped |
+            DisplayOrientations::Portrait |
+            DisplayOrientations::PortraitFlipped);
+    }
+
+    // Set the orientation/rotation preferences.  Please note that this does
+    // not constitute a 100%-certain lock of a given set of possible
+    // orientations.  According to Microsoft's documentation on WinRT [1]
+    // when a device is not capable of being rotated, Windows may ignore
+    // the orientation preferences, and stick to what the device is capable of
+    // displaying.
+    //
+    // [1] Documentation on the 'InitialRotationPreference' setting for a
+    // Windows app's manifest file describes how some orientation/rotation
+    // preferences may be ignored.  See
+    // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
+    // for details.  Microsoft's "Display orientation sample" also gives an
+    // outline of how Windows treats device rotation
+    // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
+    WINRT_DISPLAY_PROPERTY(AutoRotationPreferences) = (DisplayOrientations) orientationFlags;
+}
+
+int
+WINRT_VideoInit(_THIS)
+{
+    SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata;
+    if (WINRT_InitModes(_this) < 0) {
+        return -1;
+    }
+
+    // Register the hint, SDL_HINT_ORIENTATIONS, with SDL.
+    // TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly.
+    SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL);
+
+    WINRT_InitMouse(_this);
+    WINRT_InitTouch(_this);
+    WINRT_InitGameBar(_this);
+    if (driverdata) {
+        /* Initialize screensaver-disabling support */
+        driverdata->displayRequest = WINRT_CreateDisplayRequest(_this);
+    }
+    return 0;
+}
+
+extern "C"
+Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
+
+static void
+WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode)
+{
+    SDL_zerop(sdlMode);
+    sdlMode->w = dxgiMode->Width;
+    sdlMode->h = dxgiMode->Height;
+    sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator;
+    sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format);
+}
+
+static int
+WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
+{
+    HRESULT hr;
+    IDXGIOutput * dxgiOutput = NULL;
+    DXGI_OUTPUT_DESC dxgiOutputDesc;
+    SDL_VideoDisplay display;
+    char * displayName = NULL;
+    UINT numModes;
+    DXGI_MODE_DESC * dxgiModes = NULL;
+    int functionResult = -1;        /* -1 for failure, 0 for success */
+    DXGI_MODE_DESC modeToMatch, closestMatch;
+
+    SDL_zero(display);
+
+    hr = dxgiAdapter1->EnumOutputs(outputIndex, &dxgiOutput);
+    if (FAILED(hr)) {
+        if (hr != DXGI_ERROR_NOT_FOUND) {
+            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter1::EnumOutputs failed", hr);
+        }
+        goto done;
+    }
+
+    hr = dxgiOutput->GetDesc(&dxgiOutputDesc);
+    if (FAILED(hr)) {
+        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr);
+        goto done;
+    }
+
+    SDL_zero(modeToMatch);
+    modeToMatch.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+    modeToMatch.Width = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
+    modeToMatch.Height = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
+    hr = dxgiOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, NULL);
+    if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
+        /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE gets returned by IDXGIOutput::FindClosestMatchingMode
+           when running under the Windows Simulator, which uses Remote Desktop (formerly known as Terminal
+           Services) under the hood.  According to the MSDN docs for the similar function,
+           IDXGIOutput::GetDisplayModeList, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE is returned if and
+           when an app is run under a Terminal Services session, hence the assumption.
+
+           In this case, just add an SDL display mode, with approximated values.
+        */
+        SDL_DisplayMode mode;
+        SDL_zero(mode);
+        display.name = "Windows Simulator / Terminal Services Display";
+        mode.w = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
+        mode.h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
+        mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
+        mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
+        display.desktop_mode = mode;
+        display.current_mode = mode;
+        if ( ! SDL_AddDisplayMode(&display, &mode)) {
+            goto done;
+        }
+    } else if (FAILED(hr)) {
+        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr);
+        goto done;
+    } else {
+        displayName = WIN_StringToUTF8(dxgiOutputDesc.DeviceName);
+        display.name = displayName;
+        WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode);
+        display.current_mode = display.desktop_mode;
+
+        hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL);
+        if (FAILED(hr)) {
+            if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
+                // TODO, WinRT: make sure display mode(s) are added when using Terminal Services / Windows Simulator
+            }
+            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode list size] failed", hr);
+            goto done;
+        }
+
+        dxgiModes = (DXGI_MODE_DESC *)SDL_calloc(numModes, sizeof(DXGI_MODE_DESC));
+        if ( ! dxgiModes) {
+            SDL_OutOfMemory();
+            goto done;
+        }
+
+        hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, dxgiModes);
+        if (FAILED(hr)) {
+            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode contents] failed", hr);
+            goto done;
+        }
+
+        for (UINT i = 0; i < numModes; ++i) {
+            SDL_DisplayMode sdlMode;
+            WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode);
+            SDL_AddDisplayMode(&display, &sdlMode);
+        }
+    }
+
+    if (SDL_AddVideoDisplay(&display, SDL_FALSE) < 0) {
+        goto done;
+    }
+
+    functionResult = 0;     /* 0 for Success! */
+done:
+    if (dxgiModes) {
+        SDL_free(dxgiModes);
+    }
+    if (dxgiOutput) {
+        dxgiOutput->Release();
+    }
+    if (displayName) {
+        SDL_free(displayName);
+    }
+    return functionResult;
+}
+
+static int
+WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex)
+{
+    HRESULT hr;
+    IDXGIAdapter1 * dxgiAdapter1;
+
+    hr = dxgiFactory2->EnumAdapters1(adapterIndex, &dxgiAdapter1);
+    if (FAILED(hr)) {
+        if (hr != DXGI_ERROR_NOT_FOUND) {
+            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory1::EnumAdapters1() failed", hr);
+        }
+        return -1;
+    }
+
+    for (int outputIndex = 0; ; ++outputIndex) {
+        if (WINRT_AddDisplaysForOutput(_this, dxgiAdapter1, outputIndex) < 0) {
+            /* HACK: The Windows App Certification Kit 10.0 can fail, when
+               running the Store Apps' test, "Direct3D Feature Test".  The
+               certification kit's error is:
+
+               "Application App was not running at the end of the test. It likely crashed or was terminated for having become unresponsive."
+
+               This was caused by SDL/WinRT's DXGI failing to report any
+               outputs.  Attempts to get the 1st display-output from the
+               1st display-adapter can fail, with IDXGIAdapter::EnumOutputs
+               returning DXGI_ERROR_NOT_FOUND.  This could be a bug in Windows,
+               the Windows App Certification Kit, or possibly in SDL/WinRT's
+               display detection code.  Either way, try to detect when this
+               happens, and use a hackish means to create a reasonable-as-possible
+               'display mode'.  -- DavidL
+            */
+            if (adapterIndex == 0 && outputIndex == 0) {
+                SDL_VideoDisplay display;
+                SDL_DisplayMode mode;
+#if SDL_WINRT_USE_APPLICATIONVIEW
+                ApplicationView ^ appView = ApplicationView::GetForCurrentView();
+#endif
+                CoreWindow ^ coreWin = CoreWindow::GetForCurrentThread();
+                SDL_zero(display);
+                SDL_zero(mode);
+                display.name = "DXGI Display-detection Workaround";
+
+                /* HACK: ApplicationView's VisibleBounds property, appeared, via testing, to
+                   give a better approximation of display-size, than did CoreWindow's
+                   Bounds property, insofar that ApplicationView::VisibleBounds seems like
+                   it will, at least some of the time, give the full display size (during the
+                   failing test), whereas CoreWindow might not.  -- DavidL
+                */
+
+#if (NTDDI_VERSION >= NTDDI_WIN10) || (SDL_WINRT_USE_APPLICATIONVIEW && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+                mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Width);
+                mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Height);
+#else
+                /* On platform(s) that do not support VisibleBounds, such as Windows 8.1,
+                   fall back to CoreWindow's Bounds property.
+                */
+                mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(coreWin->Bounds.Width);
+                mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(coreWin->Bounds.Height);
+#endif
+
+                mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
+                mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
+                display.desktop_mode = mode;
+                display.current_mode = mode;
+                if ((SDL_AddDisplayMode(&display, &mode) < 0) ||
+                    (SDL_AddVideoDisplay(&display, SDL_FALSE) < 0))
+                {
+                    return SDL_SetError("Failed to apply DXGI Display-detection workaround");
+                }
+            }
+
+            break;
+        }
+    }
+
+    dxgiAdapter1->Release();
+    return 0;
+}
+
+int
+WINRT_InitModes(_THIS)
+{
+    /* HACK: Initialize a single display, for whatever screen the app's
+         CoreApplicationView is on.
+       TODO, WinRT: Try initializing multiple displays, one for each monitor.
+         Appropriate WinRT APIs for this seem elusive, though.  -- DavidL
+    */
+
+    HRESULT hr;
+    IDXGIFactory2 * dxgiFactory2 = NULL;
+
+    hr = CreateDXGIFactory1(SDL_IID_IDXGIFactory2, (void **)&dxgiFactory2);
+    if (FAILED(hr)) {
+        return WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr);
+    }
+
+    for (int adapterIndex = 0; ; ++adapterIndex) {
+        if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) {
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int
+WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
+{
+    return 0;
+}
+
+void
+WINRT_VideoQuit(_THIS)
+{
+    SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata;
+    if (driverdata && driverdata->displayRequest) {
+        driverdata->displayRequest->Release();
+        driverdata->displayRequest = NULL;
+    }
+    WINRT_QuitGameBar(_this);
+    WINRT_QuitMouse(_this);
+}
+
+static const Uint32 WINRT_DetectableFlags =
+    SDL_WINDOW_MAXIMIZED |
+    SDL_WINDOW_FULLSCREEN_DESKTOP |
+    SDL_WINDOW_SHOWN |
+    SDL_WINDOW_HIDDEN |
+    SDL_WINDOW_MOUSE_FOCUS;
+
+extern "C" Uint32
+WINRT_DetectWindowFlags(SDL_Window * window)
+{
+    Uint32 latestFlags = 0;
+    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
+    bool is_fullscreen = false;
+
+#if SDL_WINRT_USE_APPLICATIONVIEW
+    if (data->appView) {
+        is_fullscreen = data->appView->IsFullScreenMode;
+    }
+#elif (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION == NTDDI_WIN8)
+    is_fullscreen = true;
+#endif
+
+    if (data->coreWindow.Get()) {
+        if (is_fullscreen) {
+            SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window);
+            int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
+            int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
+
+#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
+            // On all WinRT platforms, except for WinPhone 8.0, rotate the
+            // window size.  This is needed to properly calculate
+            // fullscreen vs. maximized.
+            const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
+            switch (currentOrientation) {
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+                case DisplayOrientations::Landscape:
+                case DisplayOrientations::LandscapeFlipped:
+#else
+                case DisplayOrientations::Portrait:
+                case DisplayOrientations::PortraitFlipped:
+#endif
+                {
+                    int tmp = w;
+                    w = h;
+                    h = tmp;
+                } break;
+            }
+#endif
+
+            if (display->desktop_mode.w != w || display->desktop_mode.h != h) {
+                latestFlags |= SDL_WINDOW_MAXIMIZED;
+            } else {
+                latestFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
+            }
+        }
+
+        if (data->coreWindow->Visible) {
+            latestFlags |= SDL_WINDOW_SHOWN;
+        } else {
+            latestFlags |= SDL_WINDOW_HIDDEN;
+        }
+
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION < NTDDI_WINBLUE)
+        // data->coreWindow->PointerPosition is not supported on WinPhone 8.0
+        latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
+#else
+        if (data->coreWindow->Visible && data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) {
+            latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
+        }
+#endif
+    }
+
+    return latestFlags;
+}
+
+// TODO, WinRT: consider removing WINRT_UpdateWindowFlags, and just calling WINRT_DetectWindowFlags as-appropriate (with appropriate calls to SDL_SendWindowEvent)
+void
+WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask)
+{
+    mask &= WINRT_DetectableFlags;
+    if (window) {
+        Uint32 apply = WINRT_DetectWindowFlags(window);
+        if ((apply & mask) & SDL_WINDOW_FULLSCREEN) {
+            window->last_fullscreen_flags = window->flags;  // seems necessary to programmatically un-fullscreen, via SDL APIs
+        }
+        window->flags = (window->flags & ~mask) | (apply & mask);
+    }
+}
+
+static bool
+WINRT_IsCoreWindowActive(CoreWindow ^ coreWindow)
+{
+    /* WinRT does not appear to offer API(s) to determine window-activation state,
+       at least not that I am aware of in Win8 - Win10.  As such, SDL tracks this
+       itself, via window-activation events.
+       
+       If there *is* an API to track this, it should probably get used instead
+       of the following hack (that uses "SDLHelperWindowActivationState").
+         -- DavidL.
+    */
+    if (coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) {
+        CoreWindowActivationState activationState = \
+            safe_cast<CoreWindowActivationState>(coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState"));
+        return (activationState != CoreWindowActivationState::Deactivated);
+    }
+
+    /* Assume that non-SDL tracked windows are active, although this should
+       probably be avoided, if possible.
+       
+       This might not even be possible, in normal SDL use, at least as of
+       this writing (Dec 22, 2015; via latest hg.libsdl.org/SDL clone)  -- DavidL
+    */
+    return true;
+}
+
+int
+WINRT_CreateWindow(_THIS, SDL_Window * window)
+{
+    // Make sure that only one window gets created, at least until multimonitor
+    // support is added.
+    if (WINRT_GlobalSDLWindow != NULL) {
+        return SDL_SetError("WinRT only supports one window");
+    }
+
+    SDL_WindowData *data = new SDL_WindowData;  /* use 'new' here as SDL_WindowData may use WinRT/C++ types */
+    if (!data) {
+        return SDL_OutOfMemory();
+    }
+    window->driverdata = data;
+    data->sdlWindow = window;
+
+    /* To note, when XAML support is enabled, access to the CoreWindow will not
+       be possible, at least not via the SDL/XAML thread.  Attempts to access it
+       from there will throw exceptions.  As such, the SDL_WindowData's
+       'coreWindow' field will only be set (to a non-null value) if XAML isn't
+       enabled.
+    */
+    if (!WINRT_XAMLWasEnabled) {
+        data->coreWindow = CoreWindow::GetForCurrentThread();
+#if SDL_WINRT_USE_APPLICATIONVIEW
+        data->appView = ApplicationView::GetForCurrentView();
+#endif
+    }
+
+    /* Make note of the requested window flags, before they start getting changed. */
+    const Uint32 requestedFlags = window->flags;
+
+#if SDL_VIDEO_OPENGL_EGL
+    /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
+    if (!(window->flags & SDL_WINDOW_OPENGL)) {
+        /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
+        data->egl_surface = EGL_NO_SURFACE;
+    } else {
+        /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
+        SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
+
+        /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
+         * rather than via SDL_EGL_CreateSurface, as older versions of
+         * ANGLE/WinRT may require that a C++ object, ComPtr<IUnknown>,
+         * be passed into eglCreateWindowSurface.
+         */
+        if (SDL_EGL_ChooseConfig(_this) != 0) {
+            /* SDL_EGL_ChooseConfig failed, SDL_GetError() should have info */
+            return -1; 
+        }
+
+        if (video_data->winrtEglWindow) {   /* ... is the 'old' version of ANGLE/WinRT being used? */
+            /* Attempt to create a window surface using older versions of
+             * ANGLE/WinRT:
+             */
+            Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
+            data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)(
+                _this->egl_data->egl_display,
+                _this->egl_data->egl_config,
+                cpp_winrtEglWindow, NULL);
+            if (data->egl_surface == NULL) {
+                return SDL_EGL_SetError("unable to create EGL native-window surface", "eglCreateWindowSurface");
+            }
+        } else if (data->coreWindow.Get() != nullptr) {
+            /* Attempt to create a window surface using newer versions of
+             * ANGLE/WinRT:
+             */
+            IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
+            data->egl_surface = _this->egl_data->eglCreateWindowSurface(
+                _this->egl_data->egl_display,
+                _this->egl_data->egl_config,
+                (NativeWindowType)coreWindowAsIInspectable,
+                NULL);
+            if (data->egl_surface == NULL) {
+                return SDL_EGL_SetError("unable to create EGL native-window surface", "eglCreateWindowSurface");
+            }
+        } else {
+            return SDL_SetError("No supported means to create an EGL window surface are available");
+        }
+    }
+#endif
+
+    /* Determine as many flags dynamically, as possible. */
+    window->flags =
+        SDL_WINDOW_BORDERLESS |
+        SDL_WINDOW_RESIZABLE;
+
+#if SDL_VIDEO_OPENGL_EGL
+    if (data->egl_surface) {
+        window->flags |= SDL_WINDOW_OPENGL;
+    }
+#endif
+
+    if (WINRT_XAMLWasEnabled) {
+        /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */
+        window->x = 0;
+        window->y = 0;
+        window->flags |= SDL_WINDOW_SHOWN;
+        SDL_SetMouseFocus(NULL);        // TODO: detect this
+        SDL_SetKeyboardFocus(NULL);     // TODO: detect this
+    } else {
+        /* WinRT 8.x apps seem to live in an environment where the OS controls the
+           app's window size, with some apps being fullscreen, depending on
+           user choice of various things.  For now, just adapt the SDL_Window to
+           whatever Windows set-up as the native-window's geometry.
+        */
+        window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
+        window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
+#if NTDDI_VERSION < NTDDI_WIN10
+        /* On WinRT 8.x / pre-Win10, just use the size we were given. */
+        window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
+        window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
+#else
+        /* On Windows 10, we occasionally get control over window size.  For windowed
+           mode apps, try this.
+        */
+        bool didSetSize = false;
+        if (!(requestedFlags & SDL_WINDOW_FULLSCREEN)) {
+            const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
+                                                 WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
+            didSetSize = data->appView->TryResizeView(size);
+        }
+        if (!didSetSize) {
+            /* We either weren't able to set the window size, or a request for
+               fullscreen was made.  Get window-size info from the OS.
+            */
+            window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
+            window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
+        }
+#endif
+
+        WINRT_UpdateWindowFlags(
+            window,
+            0xffffffff      /* Update any window flag(s) that WINRT_UpdateWindow can handle */
+        );
+
+        /* Try detecting if the window is active */
+        bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get());
+        if (isWindowActive) {
+            SDL_SetKeyboardFocus(window);
+        }
+    }
+ 
+    /* Make sure the WinRT app's IFramworkView can post events on
+       behalf of SDL:
+    */
+    WINRT_GlobalSDLWindow = window;
+
+    /* All done! */
+    return 0;
+}
+
+void
+WINRT_SetWindowSize(_THIS, SDL_Window * window)
+{
+#if NTDDI_VERSION >= NTDDI_WIN10
+    SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
+    const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
+                                         WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
+    data->appView->TryResizeView(size); // TODO, WinRT: return failure (to caller?) from TryResizeView()
+#endif
+}
+
+void
+WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
+{
+#if NTDDI_VERSION >= NTDDI_WIN10
+    SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
+    bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get());
+    if (isWindowActive) {
+        if (fullscreen) {
+            if (!data->appView->IsFullScreenMode) {
+                data->appView->TryEnterFullScreenMode();    // TODO, WinRT: return failure (to caller?) from TryEnterFullScreenMode()
+            }
+        } else {
+            if (data->appView->IsFullScreenMode) {
+                data->appView->ExitFullScreenMode();
+            }
+        }
+    }
+#endif
+}
+
+
+void
+WINRT_DestroyWindow(_THIS, SDL_Window * window)
+{
+    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
+
+    if (WINRT_GlobalSDLWindow == window) {
+        WINRT_GlobalSDLWindow = NULL;
+    }
+
+    if (data) {
+        // Delete the internal window data:
+        delete data;
+        data = NULL;
+        window->driverdata = NULL;
+    }
+}
+
+SDL_bool
+WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
+{
+    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
+
+    if (info->version.major <= SDL_MAJOR_VERSION) {
+        info->subsystem = SDL_SYSWM_WINRT;
+        info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
+        return SDL_TRUE;
+    } else {
+        SDL_SetError("Application not compiled with SDL %d",
+                     SDL_MAJOR_VERSION);
+        return SDL_FALSE;
+    }
+    return SDL_FALSE;
+}
+
+static ABI::Windows::System::Display::IDisplayRequest *
+WINRT_CreateDisplayRequest(_THIS)
+{
+    /* Setup a WinRT DisplayRequest object, usable for enabling/disabling screensaver requests */
+    wchar_t *wClassName = L"Windows.System.Display.DisplayRequest";
+    HSTRING hClassName;
+    IActivationFactory *pActivationFactory = NULL;
+    IInspectable * pDisplayRequestRaw = nullptr;
+    ABI::Windows::System::Display::IDisplayRequest * pDisplayRequest = nullptr;
+    HRESULT hr;
+
+    hr = ::WindowsCreateString(wClassName, (UINT32)SDL_wcslen(wClassName), &hClassName);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = Windows::Foundation::GetActivationFactory(hClassName, &pActivationFactory);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = pActivationFactory->ActivateInstance(&pDisplayRequestRaw);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = pDisplayRequestRaw->QueryInterface(SDL_IID_IDisplayRequest, (void **) &pDisplayRequest);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+done:
+    if (pDisplayRequestRaw) {
+        pDisplayRequestRaw->Release();
+    }
+    if (pActivationFactory) {
+        pActivationFactory->Release();
+    }
+    if (hClassName) {
+        ::WindowsDeleteString(hClassName);
+    }
+
+    return pDisplayRequest;
+}
+
+void
+WINRT_SuspendScreenSaver(_THIS)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata;
+    if (driverdata && driverdata->displayRequest) {
+        ABI::Windows::System::Display::IDisplayRequest * displayRequest = (ABI::Windows::System::Display::IDisplayRequest *) driverdata->displayRequest;
+        if (_this->suspend_screensaver) {
+            displayRequest->RequestActive();
+        } else {
+            displayRequest->RequestRelease();
+        }
+    }
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 106 - 0
src/video/winrt/SDL_winrtvideo_cpp.h

@@ -0,0 +1,106 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* Windows includes: */
+#include <windows.h>
+#ifdef __cplusplus_winrt
+#include <agile.h>
+#endif
+
+/* SDL includes: */
+#include "SDL_video.h"
+#include "SDL_events.h"
+
+#if NTDDI_VERSION >= NTDDI_WINBLUE  /* ApplicationView's functionality only becomes
+                                       useful for SDL in Win[Phone] 8.1 and up.
+                                       Plus, it is not available at all in WinPhone 8.0. */
+#define SDL_WINRT_USE_APPLICATIONVIEW 1
+#endif
+
+extern "C" {
+#include "../SDL_sysvideo.h"
+#include "../SDL_egl_c.h"
+}
+
+/* Private display data */
+typedef struct SDL_VideoData {
+    /* An object created by ANGLE/WinRT (OpenGL ES 2 for WinRT) that gets
+     * passed to eglGetDisplay and eglCreateWindowSurface:
+     */
+    IUnknown *winrtEglWindow;
+
+    /* Event token(s), for unregistering WinRT event handler(s).
+       These are just a struct with a 64-bit integer inside them
+    */
+    Windows::Foundation::EventRegistrationToken gameBarIsInputRedirectedToken;
+
+    /* A WinRT DisplayRequest, used for implementing SDL_*ScreenSaver() functions.
+     * This is really a pointer to a 'ABI::Windows::System::Display::IDisplayRequest *',
+     * It's casted to 'IUnknown *', to help with building SDL.
+    */
+    IUnknown *displayRequest;
+} SDL_VideoData;
+
+/* The global, WinRT, SDL Window.
+   For now, SDL/WinRT only supports one window (due to platform limitations of
+   WinRT.
+*/
+extern SDL_Window * WINRT_GlobalSDLWindow;
+
+/* Updates one or more SDL_Window flags, by querying the OS' native windowing APIs.
+   SDL_Window flags that can be updated should be specified in 'mask'.
+*/
+extern void WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask);
+extern "C" Uint32 WINRT_DetectWindowFlags(SDL_Window * window);  /* detects flags w/o applying them */
+
+/* Display mode internals */
+//typedef struct
+//{
+//    Windows::Graphics::Display::DisplayOrientations currentOrientation;
+//} SDL_DisplayModeData;
+
+#ifdef __cplusplus_winrt
+
+/* A convenience macro to get a WinRT display property */
+#if NTDDI_VERSION > NTDDI_WIN8
+#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayInformation::GetForCurrentView()->NAME)
+#else
+#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayProperties::NAME)
+#endif
+
+/* Converts DIPS to/from physical pixels */
+#define WINRT_DIPS_TO_PHYSICAL_PIXELS(DIPS)     ((int)(0.5f + (((float)(DIPS) * (float)WINRT_DISPLAY_PROPERTY(LogicalDpi)) / 96.f)))
+#define WINRT_PHYSICAL_PIXELS_TO_DIPS(PHYSPIX)  (((float)(PHYSPIX) * 96.f)/WINRT_DISPLAY_PROPERTY(LogicalDpi))
+
+/* Internal window data */
+struct SDL_WindowData
+{
+    SDL_Window *sdlWindow;
+    Platform::Agile<Windows::UI::Core::CoreWindow> coreWindow;
+#ifdef SDL_VIDEO_OPENGL_EGL
+    EGLSurface egl_surface;
+#endif
+#if SDL_WINRT_USE_APPLICATIONVIEW
+    Windows::UI::ViewManagement::ApplicationView ^ appView;
+#endif
+};
+
+#endif // ifdef __cplusplus_winrt