فهرست منبع

windows: vendor GameInput headers

Anonymous Maarten 1 ماه پیش
والد
کامیت
b048e8e6f8

+ 0 - 15
.github/workflows/create-test-plan.py

@@ -244,8 +244,6 @@ class JobDetails:
     msys2_packages: list[str] = dataclasses.field(default_factory=list)
     cygwin_packages: list[str] = dataclasses.field(default_factory=list)
     werror: bool = True
-    microsoft_gameinput: bool = False
-    microsoft_gameinput_arch: str = ""
     msvc_vcvars_arch: str = ""
     msvc_vcvars_sdk: str = ""
     msvc_project: str = ""
@@ -316,8 +314,6 @@ class JobDetails:
             "android-mk": self.android_mk,
             "werror": self.werror,
             "sudo": self.sudo,
-            "microsoft-gameinput": self.microsoft_gameinput,
-            "microsoft-gameinput-arch": self.microsoft_gameinput_arch,
             "msvc-vcvars-arch": self.msvc_vcvars_arch,
             "msvc-vcvars-sdk": self.msvc_vcvars_sdk,
             "msvc-project": self.msvc_project,
@@ -483,14 +479,6 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args
                         job.setup_libusb_arch = "x86"
                     case MsvcArch.X64:
                         job.setup_libusb_arch = "x64"
-                job.microsoft_gameinput = True
-                match spec.msvc_arch:
-                    case MsvcArch.X64:
-                        job.microsoft_gameinput_arch = "x64"
-                    case MsvcArch.Arm64:
-                        job.microsoft_gameinput_arch = "arm64"
-                job.cflags.append("-I$GAMEINPUT_INCLUDE")
-                job.cxxflags.append("-I$GAMEINPUT_INCLUDE")
         case SdlPlatform.Linux:
             if spec.name.startswith("Ubuntu"):
                 assert spec.os.value.startswith("ubuntu-")
@@ -827,9 +815,6 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args
                 job.msys2_packages.append(f"{msys2_env}-clang-tools-extra")
             if job.ccache:
                 job.msys2_packages.append(f"{msys2_env}-ccache")
-            job.microsoft_gameinput = True
-            job.cflags.append("-I$GAMEINPUT_INCLUDE")
-            job.cxxflags.append("-I$GAMEINPUT_INCLUDE")
         case SdlPlatform.Cygwin:
             job.ccache = False # Missing evict-older-than option
             job.clang_tidy = False # error finding files [clang-diagnostic-error] cause might be space in command path

+ 0 - 7
.github/workflows/generic.yml

@@ -176,13 +176,6 @@ jobs:
               echo '#error "System SDL headers must not be used by build system"' >"$dest"
             done
           done
-      - name: 'Set up Microsoft.GameInput headers'
-        if: ${{ !!matrix.platform.microsoft-gameinput }}
-        run: |
-          python build-scripts/download-gameinput-sdk.py -o $HOME/gameinput
-          echo "GAMEINPUT_INCLUDE=$(cygpath -w "$HOME/gameinput/include")" >>$GITHUB_ENV
-          echo "INCLUDE=$(cygpath -w "$HOME/gameinput/include");$INCLUDE" >>$GITHUB_ENV
-          ${{ (!!matrix.platform.microsoft-gameinput-arch && format('echo "LIB=$(cygpath -w "$HOME/gameinput/lib/{0}");$LIB" >>$GITHUB_ENV', matrix.platform.microsoft-gameinput-arch)) || '' }}
       - name: 'Calculate ccache key'
         if: ${{ matrix.platform.ccache }}
         id: prepare-restore-ccache

+ 21 - 46
CMakeLists.txt

@@ -512,14 +512,6 @@ if(SDL_SHARED)
   SDL_AddCommonCompilerFlags(SDL3-shared)
   target_compile_definitions(SDL3-shared PRIVATE "$<$<CONFIG:Debug>:DEBUG>")
   set_property(TARGET SDL3-shared PROPERTY UNITY_BUILD OFF)
-  if ("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
-    target_compile_features(SDL3-shared PRIVATE c_std_99)
-  else()
-    # tcc does support the subset of C99 used by SDL
-    if (NOT USE_TCC)
-      message(WARNING "target_compile_features does not know c_std_99 for C compiler")
-    endif()
-  endif()
 endif()
 
 if(SDL_STATIC)
@@ -528,12 +520,13 @@ if(SDL_STATIC)
   SDL_AddCommonCompilerFlags(SDL3-static)
   target_compile_definitions(SDL3-static PRIVATE "$<$<CONFIG:Debug>:DEBUG>")
   set_property(TARGET SDL3-static PROPERTY UNITY_BUILD OFF)
-  if ("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
-    target_compile_features(SDL3-static PRIVATE c_std_99)
-  else()
-    if (NOT USE_TCC)
-      message(WARNING "target_compile_features does not know c_std_99 for C compiler")
-    endif()
+endif()
+
+if("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
+  sdl_compile_features(c_std_99)
+else()
+  if(NOT USE_TCC)
+    message(WARNING "target_compile_features does not know c_std_99 for C compiler")
   endif()
 endif()
 
@@ -2353,40 +2346,22 @@ elseif(WINDOWS OR CYGWIN)
     int main(int argc, char **argv) { return 0; }" HAVE_WINDOWS_GAMING_INPUT_H
   )
 
-  check_cxx_source_compiles("
-    #include <gameinput.h>
-    int main(int argc, char **argv) { return 0; }" HAVE_GAMEINPUT_H
-  )
-  if(HAVE_GAMEINPUT_H)
-    set(SDL_GAMEINPUT_DYNAMIC 1)
-    find_library(GAMEINPUT_LIB NAMES "gameinput.lib")
-    if(GAMEINPUT_LIB)
-      cmake_push_check_state()
-      list(APPEND CMAKE_REQUIRED_LIBRARIES "${GAMEINPUT_LIB}")
-      check_cxx_source_compiles("
-        #include <windows.h>
-        #include <gameinput.h>
-        #if defined(GAMEINPUT_API_VERSION) && GAMEINPUT_API_VERSION > 0
-        #define STR_JOIN2(A, B) A##B
-        #define STR_JOIN(A, B) STR_JOIN2(A, B)
-        using namespace GameInput::STR_JOIN(v, GAMEINPUT_API_VERSION);
-        #endif
-        int main(int argc, char **argv) {
-         IGameInput *gameInput;
-         HRESULT hr = GameInputCreate(&gameInput);
-         if (SUCCEEDED(hr)) {
-          gameInput->Release();
-         }
-         (void) argc; (void) argv;
-         return 0;
-        }" HAVE_GAMEINPUT_LIB
-      )
-      cmake_pop_check_state()
-      if(HAVE_GAMEINPUT_LIB)
-        sdl_link_dependency(gameinput LIBS gameinput.lib PKG_CONFIG_LINK_OPTIONS -lgameinput)
-        set(SDL_GAMEINPUT_DYNAMIC 0)
+  set(HAVE_GAMEINPUT_H 1)
+  sdl_include_directories(PRIVATE SYSTEM "${SDL3_SOURCE_DIR}/src/core/windows/gameinput")
+  if("cxx_std_11" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
+    sdl_sources("${SDL3_SOURCE_DIR}/src/core/windows/gameinput/gameinput.cpp")
+    sdl_compile_features(cxx_std_11)
+    if(USE_GCC OR USE_CLANG)
+      # Avoid a dependency on libstdc++-X.dll for `__gxx_personality_seh0`
+      check_c_compiler_flag(-fno-exceptions COMPILER_SUPPORTS_FNO_EXCEPTIONS)
+      if(COMPILER_SUPPORTS_FNO_EXCEPTIONS)
+        set_property(SOURCE "${SDL3_SOURCE_DIR}/src/core/windows/gameinput/gameinput.cpp" APPEND PROPERTY COMPILE_OPTIONS "-fno-exceptions")
+        set_property(SOURCE "${SDL3_SOURCE_DIR}/src/core/windows/gameinput/gameinput.cpp" PROPERTY SKIP_PRECOMPILE_HEADERS 1)
       endif()
     endif()
+    set(SDL_GAMEINPUT_DYNAMIC 0)
+  else()
+    set(SDL_GAMEINPUT_DYNAMIC 1)
   endif()
 
   check_include_file(dxgi1_5.h HAVE_DXGI1_5_H)

+ 11 - 12
VisualC/SDL/SDL.vcxproj

@@ -114,22 +114,22 @@
     <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath)</LibraryPath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(ProjectDir)/../../src/core/windows/gameinput;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(ProjectDir)/../../src/core/windows/gameinput;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(ProjectDir)/../../src/core/windows/gameinput;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
-    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(ProjectDir)/../../src/core/windows/gameinput;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(ProjectDir)/../../src/core/windows/gameinput;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
-    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(IncludePath)</IncludePath>
+    <IncludePath>$(ProjectDir)/../../src;$(ProjectDir)/../../src/core/windows;$(ProjectDir)/../../src/core/windows/gameinput;$(IncludePath)</IncludePath>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <PreBuildEvent>
@@ -435,6 +435,7 @@
     <ClInclude Include="..\..\src\camera\SDL_camera_c.h" />
     <ClInclude Include="..\..\src\camera\SDL_syscamera.h" />
     <ClInclude Include="..\..\src\core\SDL_core_unsupported.h" />
+    <ClInclude Include="..\..\src\core\windows\gameinput\gameinput.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_directx.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_gameinput.h" />
     <ClInclude Include="..\..\src\core\windows\SDL_hid.h" />
@@ -773,13 +774,11 @@
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
+    <ClCompile Include="..\..\src\core\windows\gameinput\gameinput.cpp">
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\windows\SDL_gameinput.cpp">
-      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
-      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
-      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
-      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
-      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
-      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
     </ClCompile>
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />

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

@@ -543,6 +543,9 @@
     <ClInclude Include="..\..\src\core\windows\SDL_directx.h">
       <Filter>core\windows</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\windows\gameinput\gameinput.h">
+      <Filter>core\windows\gameinput</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\windows\SDL_gameinput.h">
       <Filter>core\windows</Filter>
     </ClInclude>
@@ -1447,6 +1450,9 @@
     <ClCompile Include="..\..\src\core\SDL_core_unsupported.c">
       <Filter>core</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\windows\gameinput\gameinput.cpp">
+      <Filter>core\windows\gameinput</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\windows\SDL_gameinput.cpp">
       <Filter>core\windows</Filter>
     </ClCompile>

+ 1 - 1
build-scripts/build-release.py

@@ -1200,7 +1200,7 @@ class Releaser:
             shutil.rmtree(deps_path, ignore_errors=True)
             dep_roots = []
             dep_includes = []
-            for dep in self.release_info.get("dependencies"):
+            for dep in self.release_info.get("dependencies", []):
                 if "command" in self.release_info["dependencies"][dep]:
                     dep_includes.append(self.deps_path / dep / "include")
                     continue

+ 0 - 47
build-scripts/download-gameinput-sdk.py

@@ -1,47 +0,0 @@
-#!/usr/bin/env python3
-
-import argparse
-import logging
-from pathlib import Path
-import urllib.request
-
-logger = logging.getLogger(__name__)
-
-DEFAULT_GAMEINPUT_VERSION = "v3.3.195.0"
-
-def download_sdk(tag: str, lowercase: bool, output: Path):
-    base_url = f"https://raw.githubusercontent.com/microsoftconnect/GameInput/refs/tags/{tag}/"
-    url_relpaths = (
-        "include/GameInput.h",
-        "include/v0/GameInput.h",
-        "include/v1/GameInput.h",
-        "include/v2/GameInput.h",
-        "lib/arm64/GameInput.lib",
-        "lib/x64/GameInput.lib",
-    )
-    for url_relpath in url_relpaths:
-        url = base_url + url_relpath
-        local_relpath = url_relpath
-        if lowercase:
-            local_relpath = local_relpath.lower()
-        local_path = output / local_relpath
-
-        local_dirpath = local_path.parent
-        local_dirpath.mkdir(parents=True, exist_ok=True)
-
-        logger.info("Downloading %s to %s...", url, local_path)
-        urllib.request.urlretrieve(url, local_path)
-        logger.info("... done")
-
-def main():
-    logging.basicConfig(level=logging.INFO)
-
-    parser = argparse.ArgumentParser(description="Download Microsoft.GameInput SDK", allow_abbrev=False)
-    parser.add_argument("--version", help="GameInput release tag (see https://github.com/microsoftconnect/GameInput/tags)", default=DEFAULT_GAMEINPUT_VERSION)
-    parser.add_argument("--no-lowercase", action="store_false", dest="lowercase", help="Don't lowercase downloaded files")
-    parser.add_argument("-o", "--output", type=Path, default=Path.cwd(), help="SDK will be stored here (in include and lib subdirectories)")
-    args = parser.parse_args()
-    download_sdk(tag=args.version, lowercase=args.lowercase, output=args.output)
-
-if __name__ == "__main__":
-    raise SystemExit(main())

+ 0 - 12
build-scripts/release-info.json

@@ -1,12 +1,6 @@
 {
   "name": "SDL3",
   "remote": "libsdl-org/SDL",
-  "dependencies": {
-    "gameinput": {
-      "command": "build-scripts/download-gameinput-sdk.py -o @<@DEPS_PATH@>@",
-      "artifact": "gameinput/include/gameinput.h"
-    }
-  },
   "version": {
     "file": "include/SDL3/SDL_version.h",
     "re_major": "^#define SDL_MAJOR_VERSION\\s+([0-9]+)$",
@@ -60,9 +54,6 @@
         "build-scripts/pkg-support/mingw/cmake/SDL3Config.cmake",
         "build-scripts/pkg-support/mingw/cmake/SDL3ConfigVersion.cmake"
       ]
-    },
-    "dependencies": {
-      "gameinput": {}
     }
   },
   "msvc": {
@@ -138,9 +129,6 @@
       "include/SDL3": [
         "include/SDL3/*.h"
       ]
-    },
-    "dependencies": {
-      "gameinput": {}
     }
   },
   "android": {

+ 9 - 0
cmake/sdlcommands.cmake

@@ -104,6 +104,15 @@ function(sdl_test_link_dependency )
   sdl_generic_link_dependency(${ARGN} COLLECTOR SDL3_test-collector STATIC_TARGETS SDL3_test)
 endfunction()
 
+function(sdl_compile_features)
+  if(TARGET SDL3-shared)
+    target_compile_features(SDL3-shared PRIVATE ${ARGN})
+  endif()
+  if(TARGET SDL3-static)
+    target_compile_features(SDL3-static PRIVATE ${ARGN})
+  endif()
+endfunction()
+
 macro(_get_ARGS_visibility)
   set(_conflict FALSE)
   set(visibility)

+ 0 - 4
include/build_config/SDL_build_config_windows.h

@@ -100,9 +100,7 @@ typedef unsigned int uintptr_t;
 #define HAVE_AUDIOCLIENT_H 1
 #define HAVE_TPCSHRD_H 1
 #define HAVE_SENSORSAPI_H 1
-#if defined(__has_include) && __has_include(<gameinput.h>)
 #define HAVE_GAMEINPUT_H 1
-#endif
 #if (defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64)) && (defined(_MSC_VER) && _MSC_VER >= 1600)
 #elif defined(__has_include) && (defined(__i386__) || defined(__x86_64))
 # if !__has_include(<immintrin.h>)
@@ -225,9 +223,7 @@ typedef unsigned int uintptr_t;
 
 /* Enable various input drivers */
 #define SDL_JOYSTICK_DINPUT 1
-#ifdef HAVE_GAMEINPUT_H
 #define SDL_JOYSTICK_GAMEINPUT 1
-#endif
 #define SDL_JOYSTICK_HIDAPI 1
 #define SDL_JOYSTICK_RAWINPUT 1
 #define SDL_JOYSTICK_VIRTUAL 1

+ 3 - 41
src/core/windows/SDL_gameinput.cpp

@@ -25,12 +25,12 @@
 
 #ifdef HAVE_GAMEINPUT_H
 
-#ifndef SDL_GAMEINPUT_DYNAMIC
-#define USE_GAMEINPUT_LIB
+#define USE_GAMEINPUTCREATE
+#if defined(SDL_PLATFORM_GDK)
 #ifdef _MSC_VER
 #pragma comment(lib, "gameinput.lib")
 #endif
-#endif // !SDL_GAMEINPUT_DYNAMIC
+#endif
 
 static SDL_SharedObject *g_hGameInputDLL;
 static IGameInput *g_pGameInput;
@@ -40,50 +40,12 @@ static int g_nGameInputRefCount;
 bool SDL_InitGameInput(IGameInput **ppGameInput)
 {
     if (g_nGameInputRefCount == 0) {
-#ifdef USE_GAMEINPUT_LIB
         // This is recommended, as Microsoft's GameInputCreate() is robust
         // and better handles various GameInput installations
         HRESULT hr = GameInputCreate(&g_pGameInput);
         if (FAILED(hr)) {
             return WIN_SetErrorFromHRESULT("GameInputCreate failed", hr);
         }
-#elif GAMEINPUT_API_VERSION > 0
-        g_hGameInputDLL = SDL_LoadObject("gameinputredist.dll");
-        if (!g_hGameInputDLL) {
-            return false;
-        }
-
-        typedef HRESULT (WINAPI *pfnGameInputInitialize)(REFIID riid, void **ppvObject);
-        pfnGameInputInitialize pGameInputInitialize = (pfnGameInputInitialize)SDL_LoadFunction(g_hGameInputDLL, "GameInputInitialize");
-        if (!pGameInputInitialize) {
-            SDL_UnloadObject(g_hGameInputDLL);
-            return false;
-        }
-
-        HRESULT hr = pGameInputInitialize(IID_IGameInput, (void **)&g_pGameInput);
-        if (FAILED(hr)) {
-            SDL_UnloadObject(g_hGameInputDLL);
-            return WIN_SetErrorFromHRESULT("GameInputInitialize failed", hr);
-        }
-#else
-        g_hGameInputDLL = SDL_LoadObject("gameinput.dll");
-        if (!g_hGameInputDLL) {
-            return false;
-        }
-
-        typedef HRESULT (WINAPI *pfnGameInputCreate)(IGameInput **gameInput);
-        pfnGameInputCreate pGameInputCreate = (pfnGameInputCreate)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate");
-        if (!pGameInputCreate) {
-            SDL_UnloadObject(g_hGameInputDLL);
-            return false;
-        }
-
-        HRESULT hr = pGameInputCreate(&g_pGameInput);
-        if (FAILED(hr)) {
-            SDL_UnloadObject(g_hGameInputDLL);
-            return WIN_SetErrorFromHRESULT("GameInputCreate failed", hr);
-        }
-#endif // USE_GAMEINPUT_LIB
     }
     ++g_nGameInputRefCount;
 

+ 1 - 1
src/core/windows/SDL_gameinput.h

@@ -30,7 +30,7 @@
 #pragma GCC diagnostic ignored "-Wundef"
 #endif
 
-#include <gameinput.h>
+#include "gameinput.h"
 
 #ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
 #pragma GCC diagnostic pop

+ 637 - 0
src/core/windows/gameinput/gameinput.cpp

@@ -0,0 +1,637 @@
+// Copyright (c) Microsoft Corporation.
+//
+// This file is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+// Start SDL modifications
+#include "SDL_internal.h"
+
+#ifdef HAVE_GAMEINPUT_H
+
+#ifdef _MBCS
+#undef _MBCS
+#endif
+#define _UNICODE
+#define UNICODE
+// End SDL modifications
+
+#include <windows.h>
+#include <unknwn.h>
+#include <stdint.h>
+
+// Start SDL modifications
+#ifndef RRF_SUBKEY_WOW6432KEY
+#define RRF_SUBKEY_WOW6432KEY 0x00020000
+#endif
+
+#define memcpy_s(DST, DST_SIZE, SRC, SRC_SIZE) SDL_memcpy(DST, SRC, SDL_min(DST_SIZE, SRC_SIZE))
+#define wcscpy_s(DST, DST_SIZE, SRC) SDL_wcslcpy(DST, SRC, DST_SIZE)
+#define wcscat_s(DST, DST_SIZE, SRC) SDL_wcslcat(DST, SRC, DST_SIZE)
+
+// Additional changes:
+// - Removed unused `static uint32_t g_productType = PRODUCT_UNDEFINED;`
+// - Removed unused `static HMODULE g_ntdllDll = nullptr;`
+// End SDL modifications
+
+namespace GameInput {
+
+
+//
+//  Constants
+//
+
+static const IID IID_IGameInput_v0 = {0x11be2a7e, 0x4254, 0x445a, {0x9c, 0x09, 0xff, 0xc4, 0x0f, 0x00, 0x69, 0x18}};
+
+
+//
+//  Globals
+//
+
+static HMODULE g_gameInputDll = nullptr;
+static HMODULE g_advapi32Dll = nullptr;
+static HMODULE g_versionDll = nullptr;
+
+
+//
+//  Macros
+//
+
+#define RETURN_HR_IF(hr, condition) { bool _condition = (condition); if(_condition) { return (hr); } }
+#define RETURN_HR_IF_NULL(hr, ptr) RETURN_HR_IF(hr, ((ptr) == nullptr))
+#define RETURN_IF_FAILED(x) { HRESULT _hr = (x); if (FAILED(_hr)) { return _hr; } }
+#define RETURN_IF_NULL_ALLOC(ptr) RETURN_HR_IF_NULL(E_OUTOFMEMORY, ptr)
+
+#define RETURN_WIN32(error) { return HRESULT_FROM_WIN32(error); }
+#define RETURN_IF_WIN32_ERROR(error) { if (error != ERROR_SUCCESS) { RETURN_WIN32(error); } }
+#define RETURN_IF_WIN32_BOOL_FALSE(condition) { if (condition == FALSE) { RETURN_WIN32(GetLastError()); } }
+#define RETURN_LAST_ERROR_IF(condition) { bool _condition = (condition); if(_condition) { RETURN_WIN32(GetLastError()); } }
+#define RETURN_LAST_ERROR_IF_NULL(ptr) RETURN_LAST_ERROR_IF((ptr) == NULL)
+
+#define RETURN_NTSTATUS(status) { NTSTATUS _value = (status); return NT_SUCCESS(_value) ? S_OK : (HRESULT)((_value) | FACILITY_NT_BIT); }
+#define RETURN_IF_NTSTATUS_FAILED(status) { NTSTATUS _status = (status); if (!NT_SUCCESS(_status)) { RETURN_NTSTATUS(_status); } }
+
+#define FAIL_FAST_HR(hr) { __fastfail(hr); }
+#define FAIL_FAST() FAIL_FAST_HR(E_UNEXPECTED)
+#define FAIL_FAST_IF(condition) { if (condition) { FAIL_FAST_HR(E_UNEXPECTED); } }
+#define FAIL_FAST_IF_FAILED(x) { HRESULT _hr = (x); if (FAILED(_hr)) { FAIL_FAST_HR(_hr); } }
+#define FAIL_FAST_IF_WIN32_BOOL_FALSE(condition) { if (condition == FALSE) { FAIL_FAST_HR(HRESULT_FROM_WIN32(GetLastError())); } }
+
+
+//
+//  Containers
+//
+
+template <typename T>
+class Vector
+{
+public:
+    ~Vector()
+    {
+        if (m_data != nullptr)
+        {
+            LocalFree(m_data);
+        }
+    }
+
+    HRESULT Resize(
+        size_t count) noexcept
+    {
+        if (count > m_capacity)
+        {
+            const size_t capacity = (m_capacity + count) * 2;
+
+            T* const data = static_cast<T*>(LocalAlloc(LPTR, capacity * sizeof(T)));
+            RETURN_IF_NULL_ALLOC(data);
+
+            if (m_data != nullptr)
+            {
+                memcpy_s(data, count * sizeof(T), m_data, m_count * sizeof(T));
+                LocalFree(m_data);
+            }
+
+            m_data = data;
+            m_capacity = capacity;
+        }
+
+        m_count = count;
+
+        return S_OK;
+    }
+
+    size_t GetCount() const noexcept
+    {
+        return m_count;
+    }
+
+    T& operator[](
+        size_t index) noexcept
+    {
+        return m_data[index];
+    }
+
+    const T& operator[](
+        size_t index) const noexcept
+    {
+        return m_data[index];
+    }
+
+    operator const T*() const noexcept
+    {
+        return m_data;
+    }
+
+    operator T*() noexcept
+    {
+        return m_data;
+    }
+
+private:
+    T*     m_data = nullptr;
+    size_t m_count = 0;
+    size_t m_capacity = 0;
+};
+
+template <typename T>
+class String
+{
+public:
+    HRESULT Assign(
+        _In_z_ const wchar_t* string)
+    {
+        RETURN_IF_FAILED(Resize(wcslen(string)));
+        wcscpy_s(m_string, m_string.GetCount(), string);
+
+        return S_OK;
+    }
+
+    HRESULT Append(
+        _In_z_ const T* part) noexcept
+    {
+        const size_t stringLength = GetLength();
+        const size_t partLength = wcslen(part);
+        const size_t totalLength = stringLength + partLength;
+
+        if (totalLength >= m_string.GetCount())
+        {
+            RETURN_IF_FAILED(Resize(totalLength));
+        }
+
+        wcscat_s(m_string, m_string.GetCount(), part);
+
+        return S_OK;
+    }
+
+    HRESULT Resize(
+        size_t length) noexcept
+    {
+        if (length >= m_string.GetCount())
+        {
+            RETURN_IF_FAILED(m_string.Resize(length + 1));
+        }
+
+        if (m_string.GetCount() > 0)
+        {
+            m_string[m_string.GetCount() - 1] = 0;
+        }
+
+        return S_OK;
+    }
+
+    size_t GetLength() const noexcept
+    {
+        const size_t count = m_string.GetCount();
+        return count == 0 ? count : count - 1;
+    }
+
+    operator const T*() const noexcept
+    {
+        return m_string;
+    }
+
+    operator T*() noexcept
+    {
+        return m_string;
+    }
+
+    const T& GetFront() const noexcept
+    {
+        return m_string[0];
+    }
+
+    const T& GetBack() const noexcept
+    {
+        return m_string[m_string.GetCount() - 1];
+    }
+
+private:
+    Vector<T> m_string;
+};
+
+using WString = String<wchar_t>;
+using AString = String<char>;
+
+
+//
+//  Helpers
+//
+
+template <typename T>
+static HRESULT GetModuleProc(
+    _In_ HMODULE module,
+    _In_z_ const char* name,
+    _Out_ T* proc) noexcept
+{
+    *proc = reinterpret_cast<T>(reinterpret_cast<uintptr_t>(GetProcAddress(module, name)));
+    RETURN_LAST_ERROR_IF_NULL(*proc);
+
+    return S_OK;
+}
+
+template <typename T>
+static HRESULT LoadSystemModuleProc(
+    _In_ HMODULE* module,
+    _In_z_ const wchar_t* path,
+    _In_z_ const char* name,
+    _Out_ T* proc) noexcept
+{
+    *proc = nullptr;
+
+    if (*module == nullptr)
+    {
+        *module = LoadLibraryEx(path, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+        RETURN_LAST_ERROR_IF_NULL(*module);
+    }
+
+    RETURN_IF_FAILED(GetModuleProc(*module, name, proc));
+
+    return S_OK;
+}
+
+static HRESULT GetSystemDirectory(
+    _Inout_ WString* systemDir) noexcept
+{
+    uint32_t length = ::GetSystemDirectory(nullptr, 0);
+    RETURN_LAST_ERROR_IF(length == 0);
+    RETURN_IF_FAILED(systemDir->Resize(length));
+
+    length = ::GetSystemDirectory(*systemDir, length) + 1;
+    RETURN_LAST_ERROR_IF(length == 0);
+    RETURN_IF_FAILED(systemDir->Resize(length));
+
+    return S_OK;
+}
+
+static HRESULT GetApplicationDirectory(
+    _Inout_ WString* appDir) noexcept
+{
+    // GetModuleFileName does not report the required buffer size; grow until the
+    // full module path fits, capping retries to avoid unbounded allocation.
+
+    DWORD capacity = MAX_PATH;
+    DWORD length = 0;
+
+    for (;;)
+    {
+        RETURN_IF_FAILED(appDir->Resize(capacity));
+
+        SetLastError(ERROR_SUCCESS);
+        length = ::GetModuleFileName(nullptr, *appDir, capacity + 1);
+        RETURN_LAST_ERROR_IF(length == 0);
+
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            break;
+        }
+
+        if (capacity >= 0x8000)
+        {
+            return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+        }
+
+        capacity *= 2;
+    }
+
+    // Trim the executable filename, leaving only the directory path.
+
+    wchar_t* const path = *appDir;
+    while (length > 0 && path[length - 1] != L'\\' && path[length - 1] != L'/')
+    {
+        length--;
+    }
+
+    path[length] = L'\0';
+
+    return S_OK;
+}
+
+static HRESULT GetRedistDirectory(
+    _Inout_ WString* redistDir) noexcept
+{
+    constexpr const wchar_t* RedistDirRegPath = L"SOFTWARE\\Microsoft\\GameInput";
+    constexpr const wchar_t* RedistDirValueName = L"RedistDir";
+
+    decltype(RegGetValueW)* regGetValue = nullptr;
+    RETURN_IF_FAILED(LoadSystemModuleProc(
+        &g_advapi32Dll,
+        L"advapi32.dll",
+        "RegGetValueW",
+        &regGetValue));
+
+    DWORD cbSize = 0;
+    RETURN_IF_WIN32_ERROR(static_cast<DWORD>(regGetValue(
+        HKEY_LOCAL_MACHINE,
+        RedistDirRegPath,
+        RedistDirValueName,
+        RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY,
+        nullptr,
+        nullptr,
+        &cbSize)));
+
+    redistDir->Resize(cbSize / sizeof(wchar_t));
+
+    RETURN_IF_WIN32_ERROR(static_cast<DWORD>(regGetValue(
+        HKEY_LOCAL_MACHINE,
+        RedistDirRegPath,
+        RedistDirValueName,
+        RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY,
+        nullptr,
+        *redistDir,
+        &cbSize)));
+
+    redistDir->Resize(cbSize / sizeof(wchar_t));
+
+    return S_OK;
+}
+
+static HRESULT GetFileVersion(
+    _In_z_ const wchar_t* path,
+    _Out_ uint64_t* version) noexcept
+{
+    *version = 0;
+
+    decltype(GetFileVersionInfoSizeW)* getFileVersionInfoSize = nullptr;
+    RETURN_IF_FAILED(LoadSystemModuleProc(
+        &g_versionDll,
+        L"version.dll",
+        "GetFileVersionInfoSizeW",
+        &getFileVersionInfoSize));
+
+    decltype(GetFileVersionInfoW)* getFileVersionInfo = nullptr;
+    RETURN_IF_FAILED(LoadSystemModuleProc(
+        &g_versionDll,
+        L"version.dll",
+        "GetFileVersionInfoW",
+        &getFileVersionInfo));
+
+    decltype(VerQueryValueW)* verQueryValue = nullptr;
+    RETURN_IF_FAILED(LoadSystemModuleProc(
+        &g_versionDll,
+        L"version.dll",
+        "VerQueryValueW",
+        &verQueryValue));
+
+    DWORD unused = 0;
+    const DWORD bufferSize = getFileVersionInfoSize(path, &unused);
+    RETURN_LAST_ERROR_IF(bufferSize == 0);
+
+    Vector<uint8_t> buffer;
+    RETURN_IF_FAILED(buffer.Resize(bufferSize));
+    RETURN_IF_WIN32_BOOL_FALSE(getFileVersionInfo(
+        path,
+        0,
+        static_cast<DWORD>(buffer.GetCount()),
+        buffer));
+
+    UINT verLength = 0;
+    VS_FIXEDFILEINFO* verInfo = nullptr;
+    RETURN_IF_WIN32_BOOL_FALSE(verQueryValue(
+        buffer,
+        L"\\",
+        reinterpret_cast<LPVOID*>(&verInfo),
+        &verLength));
+
+    ULARGE_INTEGER li = {};
+    li.HighPart = verInfo->dwFileVersionMS;
+    li.LowPart = verInfo->dwFileVersionLS;
+
+    *version = li.QuadPart;
+
+    return S_OK;
+}
+
+static bool FileExists(
+    _In_z_ const wchar_t* path) noexcept
+{
+    const DWORD attributes = GetFileAttributesW(path);
+    if (attributes == INVALID_FILE_ATTRIBUTES || attributes & FILE_ATTRIBUTE_DIRECTORY)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+static bool GetFileInfo(
+    _In_z_ const wchar_t* path,
+    _Out_ uint64_t* version) noexcept
+{
+    *version = 0;
+
+    if (FileExists(path))
+    {
+        // Best effort attempt to get DLL verison; will return zero
+        // on platforms which do not support this query.
+
+        (void)GetFileVersion(path, version);
+        return true;
+    }
+
+    return false;
+}
+
+static HRESULT PathJoin(
+    _In_z_ const wchar_t* path1,
+    _In_z_ const wchar_t* path2,
+    _Inout_ WString* result) noexcept
+{
+    if (*path1 == 0)
+    {
+        return result->Assign(path2);
+    }
+
+    if (*path2 == 0)
+    {
+        return result->Assign(path1);
+    }
+
+    RETURN_IF_FAILED(result->Assign(path1));
+
+    if (result->GetBack() != L'\\' && result->GetBack() != L'/')
+    {
+        RETURN_IF_FAILED(result->Append(L"\\"));
+    }
+
+    if (path2[0] == L'\\' || path2[0] == L'/')
+    {
+        RETURN_IF_FAILED(result->Append(path2 + 1));
+    }
+    else
+    {
+        RETURN_IF_FAILED(result->Append(path2));
+    }
+
+    return S_OK;
+}
+
+
+//
+//  Loader
+//
+
+static HRESULT LoadGameInputDll(
+    _Out_ HMODULE* module) noexcept
+{
+    *module = nullptr;
+
+    WString systemDir;
+    RETURN_IF_FAILED(GetSystemDirectory(&systemDir));
+
+    WString inboxPath;
+    uint64_t inboxVersion = 0;
+    const bool validInbox =
+        SUCCEEDED(PathJoin(systemDir, L"GameInput.dll", &inboxPath)) &&
+        GetFileInfo(inboxPath, &inboxVersion);
+
+    WString redistPath;
+    uint64_t redistVersion = 0;
+    bool validRedist =
+        SUCCEEDED(PathJoin(systemDir, L"GameInputRedist.dll", &redistPath)) &&
+        GetFileInfo(redistPath, &redistVersion);
+
+    if (!validRedist)
+    {
+        // GameInputRedist.dll can be found in System32 and Program Files;
+        // check both locations for improved compatibility.
+
+        WString redistDir;
+        validRedist =
+            SUCCEEDED(GetRedistDirectory(&redistDir)) &&
+            SUCCEEDED(PathJoin(redistDir, L"GameInputRedist.dll", &redistPath)) &&
+            GetFileInfo(redistPath, &redistVersion);
+    }
+
+    WString appDir;
+    WString sideloadedPath;
+    uint64_t sideloadedVersion = 0;
+    const bool validSideloaded =
+        SUCCEEDED(GetApplicationDirectory(&appDir)) &&
+        SUCCEEDED(PathJoin(appDir, L"GameInputRedist.dll", &sideloadedPath)) &&
+        GetFileInfo(sideloadedPath, &sideloadedVersion);
+
+    // Select the candidate with the highest version. Ties prefer redist over inbox
+    // and sideloaded over both, matching the order in which candidates are evaluated.
+
+    const wchar_t* path = nullptr;
+    uint64_t version = 0;
+
+    if (validInbox)
+    {
+        path = inboxPath;
+        version = inboxVersion;
+    }
+    if (validRedist && (path == nullptr || redistVersion >= version))
+    {
+        path = redistPath;
+        version = redistVersion;
+    }
+    if (validSideloaded && (path == nullptr || sideloadedVersion >= version))
+    {
+        path = sideloadedPath;
+        version = sideloadedVersion;
+    }
+
+    RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), path);
+
+    *module = LoadLibrary(path);
+    RETURN_LAST_ERROR_IF_NULL(*module);
+
+    return S_OK;
+}
+
+static HRESULT GameInputCreateWithVersion(
+    _In_ REFIID riid,
+    _COM_Outptr_ LPVOID* ppv) noexcept
+{
+    *ppv = nullptr;
+
+    if (g_gameInputDll == nullptr)
+    {
+        RETURN_IF_FAILED(LoadGameInputDll(&g_gameInputDll));
+    }
+
+    using GameInputInitializeFn = HRESULT (*)(
+        _In_ REFIID riid,
+        _COM_Outptr_ LPVOID* ppv);
+
+    GameInputInitializeFn gameInputInitialize = nullptr;
+    if (SUCCEEDED(GetModuleProc(g_gameInputDll, "GameInputInitialize", &gameInputInitialize)))
+    {
+        return gameInputInitialize(riid, ppv);
+    }
+
+    if (riid == IID_IGameInput_v0)
+    {
+        // All recent versions of GameInput support the GameInputInitialize export. As we
+        // did not find it via above query, we must be running an old version of GameInput
+        // which only supports the v0 API. Don't attempt to use it for newer API versions.
+
+        using GameInputCreateFn = HRESULT (*)(
+            _COM_Outptr_ LPVOID* ppv);
+
+        GameInputCreateFn gameInputCreate = nullptr;
+        if (SUCCEEDED(GetModuleProc(g_gameInputDll, "GameInputCreate", &gameInputCreate)))
+        {
+            return gameInputCreate(ppv);
+        }
+
+        return HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
+    }
+
+    return E_NOINTERFACE;
+}
+
+
+} // namespace GameInput
+
+
+//
+//  Exports
+//
+
+STDAPI GameInputInitialize(
+    _In_ REFIID riid,
+    _COM_Outptr_ LPVOID* ppv) noexcept
+{
+    return GameInput::GameInputCreateWithVersion(riid, ppv);
+}
+
+// Start SDL modifications
+#endif // HAVE_GAMEINPUT_H
+// End SDL modifications

+ 1332 - 0
src/core/windows/gameinput/gameinput.h

@@ -0,0 +1,1332 @@
+// Copyright (c) Microsoft Corporation.
+//
+// This file is licensed under the MIT License.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#pragma once
+
+#ifndef __cplusplus
+#error GameInput requires C++
+#endif
+
+#include <stdint.h>
+#include <unknwn.h>
+
+#pragma region Application Family or OneCore Family or Games Family
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
+
+#define GAMEINPUT_API_VERSION 3
+
+namespace GameInput { namespace v3 {
+
+enum GameInputKind
+{
+    GameInputKindUnknown          = 0x00000000,
+    GameInputKindRawDeviceReport  = 0x00000001,
+    GameInputKindControllerAxis   = 0x00000002,
+    GameInputKindControllerButton = 0x00000004,
+    GameInputKindControllerSwitch = 0x00000008,
+    GameInputKindController       = 0x0000000E,
+    GameInputKindKeyboard         = 0x00000010,
+    GameInputKindMouse            = 0x00000020,
+    GameInputKindSensors          = 0x00000040,
+    GameInputKindArcadeStick      = 0x00010000,
+    GameInputKindFlightStick      = 0x00020000,
+    GameInputKindGamepad          = 0x00040000,
+    GameInputKindRacingWheel      = 0x00080000,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputKind)
+
+enum GameInputEnumerationKind
+{
+    GameInputNoEnumeration       = 0,
+    GameInputAsyncEnumeration    = 1,
+    GameInputBlockingEnumeration = 2
+};
+
+enum GameInputFocusPolicy
+{
+    GameInputDefaultFocusPolicy             = 0x00000000,
+    GameInputExclusiveForegroundInput       = 0x00000002,
+    GameInputExclusiveForegroundGuideButton = 0x00000008,
+    GameInputExclusiveForegroundShareButton = 0x00000020,
+    GameInputEnableBackgroundInput          = 0x00000040,
+    GameInputEnableBackgroundGuideButton    = 0x00000080,
+    GameInputEnableBackgroundShareButton    = 0x00000100
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputFocusPolicy)
+
+enum GameInputSwitchKind
+{
+    GameInputUnknownSwitchKind = -1,
+    GameInput2WaySwitch        =  0,
+    GameInput4WaySwitch        =  1,
+    GameInput8WaySwitch        =  2
+};
+
+enum GameInputSwitchPosition
+{
+    GameInputSwitchCenter    = 0,
+    GameInputSwitchUp        = 1,
+    GameInputSwitchUpRight   = 2,
+    GameInputSwitchRight     = 3,
+    GameInputSwitchDownRight = 4,
+    GameInputSwitchDown      = 5,
+    GameInputSwitchDownLeft  = 6,
+    GameInputSwitchLeft      = 7,
+    GameInputSwitchUpLeft    = 8
+};
+
+enum GameInputKeyboardKind
+{
+    GameInputUnknownKeyboard = -1,
+    GameInputAnsiKeyboard    =  0,
+    GameInputIsoKeyboard     =  1,
+    GameInputKsKeyboard      =  2,
+    GameInputAbntKeyboard    =  3,
+    GameInputJisKeyboard     =  4
+};
+
+enum GameInputMouseButtons
+{
+    GameInputMouseNone           = 0x00000000,
+    GameInputMouseLeftButton     = 0x00000001,
+    GameInputMouseRightButton    = 0x00000002,
+    GameInputMouseMiddleButton   = 0x00000004,
+    GameInputMouseButton4        = 0x00000008,
+    GameInputMouseButton5        = 0x00000010,
+    GameInputMouseWheelTiltLeft  = 0x00000020,
+    GameInputMouseWheelTiltRight = 0x00000040
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputMouseButtons)
+
+enum GameInputMousePositions
+{
+    GameInputMouseNoPosition       = 0x00000000,
+    GameInputMouseAbsolutePosition = 0x00000001,
+    GameInputMouseRelativePosition = 0x00000002
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputMousePositions)
+
+enum GameInputSensorsKind
+{
+    GameInputSensorsNone            = 0x00000000,
+    GameInputSensorsAccelerometer   = 0x00000001,
+    GameInputSensorsGyrometer       = 0x00000002,
+    GameInputSensorsCompass         = 0x00000004,
+    GameInputSensorsOrientation     = 0x00000008
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputSensorsKind)
+
+enum GameInputSensorAccuracy
+{
+    GameInputSensorAccuracyUnknown      = 0x00000000,
+    GameInputSensorAccuracyUnreliable   = 0x00000001,
+    GameInputSensorAccuracyApproximate  = 0x00000002,
+    GameInputSensorAccuracyHigh         = 0x00000003
+};
+
+enum GameInputArcadeStickButtons
+{
+    GameInputArcadeStickNone     = 0x00000000,
+    GameInputArcadeStickMenu     = 0x00000001,
+    GameInputArcadeStickView     = 0x00000002,
+    GameInputArcadeStickUp       = 0x00000004,
+    GameInputArcadeStickDown     = 0x00000008,
+    GameInputArcadeStickLeft     = 0x00000010,
+    GameInputArcadeStickRight    = 0x00000020,
+    GameInputArcadeStickAction1  = 0x00000040,
+    GameInputArcadeStickAction2  = 0x00000080,
+    GameInputArcadeStickAction3  = 0x00000100,
+    GameInputArcadeStickAction4  = 0x00000200,
+    GameInputArcadeStickAction5  = 0x00000400,
+    GameInputArcadeStickAction6  = 0x00000800,
+    GameInputArcadeStickSpecial1 = 0x00001000,
+    GameInputArcadeStickSpecial2 = 0x00002000
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputArcadeStickButtons)
+
+enum GameInputFlightStickButtons
+{
+    GameInputFlightStickNone           = 0x00000000,
+    GameInputFlightStickMenu           = 0x00000001,
+    GameInputFlightStickView           = 0x00000002,
+    GameInputFlightStickFirePrimary    = 0x00000004,
+    GameInputFlightStickFireSecondary  = 0x00000008,
+    GameInputFlightStickHatSwitchUp    = 0x00000010,
+    GameInputFlightStickHatSwitchDown  = 0x00000020,
+    GameInputFlightStickHatSwitchLeft  = 0x00000040,
+    GameInputFlightStickHatSwitchRight = 0x00000080,
+    GameInputFlightStickA              = 0x00000100,
+    GameInputFlightStickB              = 0x00000200,
+    GameInputFlightStickX              = 0x00000400,
+    GameInputFlightStickY              = 0x00000800,
+    GameInputFlightStickLeftShoulder   = 0x00001000,
+    GameInputFlightStickRightShoulder  = 0x00002000,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputFlightStickButtons)
+
+enum GameInputGamepadButtons
+{
+    GameInputGamepadNone                 = 0x00000000,
+    GameInputGamepadMenu                 = 0x00000001,
+    GameInputGamepadView                 = 0x00000002,
+    GameInputGamepadA                    = 0x00000004,
+    GameInputGamepadB                    = 0x00000008,
+    GameInputGamepadC                    = 0x00004000,
+    GameInputGamepadX                    = 0x00000010,
+    GameInputGamepadY                    = 0x00000020,
+    GameInputGamepadZ                    = 0x00008000,
+    GameInputGamepadDPadUp               = 0x00000040,
+    GameInputGamepadDPadDown             = 0x00000080,
+    GameInputGamepadDPadLeft             = 0x00000100,
+    GameInputGamepadDPadRight            = 0x00000200,
+    GameInputGamepadLeftShoulder         = 0x00000400,
+    GameInputGamepadRightShoulder        = 0x00000800,
+    GameInputGamepadLeftTriggerButton    = 0x00010000,
+    GameInputGamepadRightTriggerButton   = 0x00020000,
+    GameInputGamepadLeftThumbstick       = 0x00001000,
+    GameInputGamepadLeftThumbstickUp     = 0x00040000,
+    GameInputGamepadLeftThumbstickDown   = 0x00080000,
+    GameInputGamepadLeftThumbstickLeft   = 0x00100000,
+    GameInputGamepadLeftThumbstickRight  = 0x00200000,
+    GameInputGamepadRightThumbstick      = 0x00002000,
+    GameInputGamepadRightThumbstickUp    = 0x00400000,
+    GameInputGamepadRightThumbstickDown  = 0x00800000,
+    GameInputGamepadRightThumbstickLeft  = 0x01000000,
+    GameInputGamepadRightThumbstickRight = 0x02000000,
+    GameInputGamepadPaddleLeft1          = 0x04000000,
+    GameInputGamepadPaddleLeft2          = 0x08000000,
+    GameInputGamepadPaddleRight1         = 0x10000000,
+    GameInputGamepadPaddleRight2         = 0x20000000,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputGamepadButtons)
+
+enum GameInputRawDeviceReportKind
+{
+    GameInputRawInputReport   = 0,
+    GameInputRawOutputReport  = 1,
+};
+
+// Gamepad modules (Groupings of gamepad elements commonly found together)
+const GameInputGamepadButtons GameInputGamepadModuleSystemDuo =
+    GameInputGamepadMenu |
+    GameInputGamepadView;
+
+const GameInputGamepadButtons GameInputGamepadModuleDpad =
+    GameInputGamepadDPadUp |
+    GameInputGamepadDPadDown |
+    GameInputGamepadDPadLeft |
+    GameInputGamepadDPadRight;
+
+const GameInputGamepadButtons GameInputGamepadModuleShoulders =
+    GameInputGamepadLeftShoulder |
+    GameInputGamepadRightShoulder;
+
+const GameInputGamepadButtons GameInputGamepadModuleTriggers =
+    GameInputGamepadLeftTriggerButton |
+    GameInputGamepadRightTriggerButton;
+
+const GameInputGamepadButtons GameInputGamepadModuleThumbsticks =
+    GameInputGamepadLeftThumbstickUp |
+    GameInputGamepadLeftThumbstickDown |
+    GameInputGamepadLeftThumbstickLeft |
+    GameInputGamepadLeftThumbstickRight |
+    GameInputGamepadRightThumbstickUp |
+    GameInputGamepadRightThumbstickDown |
+    GameInputGamepadRightThumbstickLeft |
+    GameInputGamepadRightThumbstickRight;
+
+const GameInputGamepadButtons GameInputGamepadModulePaddles2 =
+    GameInputGamepadPaddleLeft1 |
+    GameInputGamepadPaddleRight1;
+
+const GameInputGamepadButtons GameInputGamepadModulePaddles4 =
+    GameInputGamepadPaddleLeft1 |
+    GameInputGamepadPaddleLeft2 |
+    GameInputGamepadPaddleRight1 |
+    GameInputGamepadPaddleRight2;
+
+// Commonly found gamepad layouts. Custom layouts are possible and encouraged.
+const GameInputGamepadButtons GameInputGamepadLayoutBasic =
+    GameInputGamepadModuleSystemDuo |
+    GameInputGamepadModuleDpad |
+    GameInputGamepadA |
+    GameInputGamepadB;
+
+const GameInputGamepadButtons GameInputGamepadLayoutButtons =
+    GameInputGamepadLayoutBasic |
+    GameInputGamepadX |
+    GameInputGamepadY |
+    GameInputGamepadModuleShoulders;
+
+const GameInputGamepadButtons GameInputGamepadLayoutStandard =
+    GameInputGamepadLayoutButtons |
+    GameInputGamepadModuleTriggers |
+    GameInputGamepadModuleThumbsticks |
+    GameInputGamepadLeftThumbstick |
+    GameInputGamepadRightThumbstick;
+
+const GameInputGamepadButtons GameInputGamepadLayoutElite =
+    GameInputGamepadLayoutStandard |
+    GameInputGamepadModulePaddles4;
+
+enum GameInputRacingWheelButtons
+{
+    GameInputRacingWheelNone            = 0x00000000,
+    GameInputRacingWheelMenu            = 0x00000001,
+    GameInputRacingWheelView            = 0x00000002,
+    GameInputRacingWheelPreviousGear    = 0x00000004,
+    GameInputRacingWheelNextGear        = 0x00000008,
+    GameInputRacingWheelA               = 0x00000100,
+    GameInputRacingWheelB               = 0x00000200,
+    GameInputRacingWheelX               = 0x00000400,
+    GameInputRacingWheelY               = 0x00000800,
+    GameInputRacingWheelDpadUp          = 0x00000010,
+    GameInputRacingWheelDpadDown        = 0x00000020,
+    GameInputRacingWheelDpadLeft        = 0x00000040,
+    GameInputRacingWheelDpadRight       = 0x00000080,
+    GameInputRacingWheelLeftThumbstick  = 0x00001000,
+    GameInputRacingWheelRightThumbstick = 0x00002000,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputRacingWheelButtons)
+
+enum GameInputSystemButtons
+{
+    GameInputSystemButtonNone  = 0x00000000,
+    GameInputSystemButtonGuide = 0x00000001,
+    GameInputSystemButtonShare = 0x00000002
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputSystemButtons)
+
+enum GameInputFlightStickAxes
+{
+    GameInputFlightStickAxesNone = 0x00000000,
+    GameInputFlightStickRoll     = 0x00000010,
+    GameInputFlightStickPitch    = 0x00000020,
+    GameInputFlightStickYaw      = 0x00000040,
+    GameInputFlightStickThrottle = 0x00000080,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputFlightStickAxes)
+
+enum GameInputGamepadAxes
+{
+    GameInputGamepadAxesNone         = 0x00000000,
+    GameInputGamepadLeftTrigger      = 0x00000001,
+    GameInputGamepadRightTrigger     = 0x00000002,
+    GameInputGamepadLeftThumbstickX  = 0x00000004,
+    GameInputGamepadLeftThumbstickY  = 0x00000008,
+    GameInputGamepadRightThumbstickX = 0x00000010,
+    GameInputGamepadRightThumbstickY = 0x00000020,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputGamepadAxes)
+
+enum GameInputRacingWheelAxes
+{
+    GameInputRacingWheelAxesNone       = 0x00000000,
+    GameInputRacingWheelSteering       = 0x00000100,
+    GameInputRacingWheelThrottle       = 0x00000200,
+    GameInputRacingWheelBrake          = 0x00000400,
+    GameInputRacingWheelClutch         = 0x00000800,
+    GameInputRacingWheelHandbrake      = 0x00001000,
+    GameInputRacingWheelPatternShifter = 0x00002000,
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputRacingWheelAxes)
+
+enum GameInputDeviceStatus
+{
+    GameInputDeviceNoStatus        = 0x00000000,
+    GameInputDeviceConnected       = 0x00000001,
+    GameInputDeviceHapticInfoReady = 0x00200000,
+    GameInputDeviceAnyStatus       = 0xFFFFFFFF
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputDeviceStatus)
+
+enum GameInputDeviceFamily
+{
+    GameInputFamilyVirtual   = -1,
+    GameInputFamilyUnknown   =  0,
+    GameInputFamilyXboxOne   =  1,
+    GameInputFamilyXbox360   =  2,
+    GameInputFamilyHid       =  3,
+    GameInputFamilyI8042     =  4,
+    GameInputFamilyAggregate =  5,
+};
+
+enum GameInputLabel
+{
+    GameInputLabelUnknown                  =  -1,
+    GameInputLabelNone                     =   0,
+    GameInputLabelXboxGuide                =   1,
+    GameInputLabelXboxBack                 =   2,
+    GameInputLabelXboxStart                =   3,
+    GameInputLabelXboxMenu                 =   4,
+    GameInputLabelXboxView                 =   5,
+    GameInputLabelXboxA                    =   7,
+    GameInputLabelXboxB                    =   8,
+    GameInputLabelXboxX                    =   9,
+    GameInputLabelXboxY                    =  10,
+    GameInputLabelXboxDPadUp               =  11,
+    GameInputLabelXboxDPadDown             =  12,
+    GameInputLabelXboxDPadLeft             =  13,
+    GameInputLabelXboxDPadRight            =  14,
+    GameInputLabelXboxLeftShoulder         =  15,
+    GameInputLabelXboxLeftTrigger          =  16,
+    GameInputLabelXboxLeftStickButton      =  17,
+    GameInputLabelXboxRightShoulder        =  18,
+    GameInputLabelXboxRightTrigger         =  19,
+    GameInputLabelXboxRightStickButton     =  20,
+    GameInputLabelXboxPaddle1              =  21,
+    GameInputLabelXboxPaddle2              =  22,
+    GameInputLabelXboxPaddle3              =  23,
+    GameInputLabelXboxPaddle4              =  24,
+    GameInputLabelLetterA                  =  25,
+    GameInputLabelLetterB                  =  26,
+    GameInputLabelLetterC                  =  27,
+    GameInputLabelLetterD                  =  28,
+    GameInputLabelLetterE                  =  29,
+    GameInputLabelLetterF                  =  30,
+    GameInputLabelLetterG                  =  31,
+    GameInputLabelLetterH                  =  32,
+    GameInputLabelLetterI                  =  33,
+    GameInputLabelLetterJ                  =  34,
+    GameInputLabelLetterK                  =  35,
+    GameInputLabelLetterL                  =  36,
+    GameInputLabelLetterM                  =  37,
+    GameInputLabelLetterN                  =  38,
+    GameInputLabelLetterO                  =  39,
+    GameInputLabelLetterP                  =  40,
+    GameInputLabelLetterQ                  =  41,
+    GameInputLabelLetterR                  =  42,
+    GameInputLabelLetterS                  =  43,
+    GameInputLabelLetterT                  =  44,
+    GameInputLabelLetterU                  =  45,
+    GameInputLabelLetterV                  =  46,
+    GameInputLabelLetterW                  =  47,
+    GameInputLabelLetterX                  =  48,
+    GameInputLabelLetterY                  =  49,
+    GameInputLabelLetterZ                  =  50,
+    GameInputLabelNumber0                  =  51,
+    GameInputLabelNumber1                  =  52,
+    GameInputLabelNumber2                  =  53,
+    GameInputLabelNumber3                  =  54,
+    GameInputLabelNumber4                  =  55,
+    GameInputLabelNumber5                  =  56,
+    GameInputLabelNumber6                  =  57,
+    GameInputLabelNumber7                  =  58,
+    GameInputLabelNumber8                  =  59,
+    GameInputLabelNumber9                  =  60,
+    GameInputLabelArrowUp                  =  61,
+    GameInputLabelArrowUpRight             =  62,
+    GameInputLabelArrowRight               =  63,
+    GameInputLabelArrowDownRight           =  64,
+    GameInputLabelArrowDown                =  65,
+    GameInputLabelArrowDownLLeft           =  66,
+    GameInputLabelArrowLeft                =  67,
+    GameInputLabelArrowUpLeft              =  68,
+    GameInputLabelArrowUpDown              =  69,
+    GameInputLabelArrowLeftRight           =  70,
+    GameInputLabelArrowUpDownLeftRight     =  71,
+    GameInputLabelArrowClockwise           =  72,
+    GameInputLabelArrowCounterClockwise    =  73,
+    GameInputLabelArrowReturn              =  74,
+    GameInputLabelIconBranding             =  75,
+    GameInputLabelIconHome                 =  76,
+    GameInputLabelIconMenu                 =  77,
+    GameInputLabelIconCross                =  78,
+    GameInputLabelIconCircle               =  79,
+    GameInputLabelIconSquare               =  80,
+    GameInputLabelIconTriangle             =  81,
+    GameInputLabelIconStar                 =  82,
+    GameInputLabelIconDPadUp               =  83,
+    GameInputLabelIconDPadDown             =  84,
+    GameInputLabelIconDPadLeft             =  85,
+    GameInputLabelIconDPadRight            =  86,
+    GameInputLabelIconDialClockwise        =  87,
+    GameInputLabelIconDialCounterClockwise =  88,
+    GameInputLabelIconSliderLeftRight      =  89,
+    GameInputLabelIconSliderUpDown         =  90,
+    GameInputLabelIconWheelUpDown          =  91,
+    GameInputLabelIconPlus                 =  92,
+    GameInputLabelIconMinus                =  93,
+    GameInputLabelIconSuspension           =  94,
+    GameInputLabelHome                     =  95,
+    GameInputLabelGuide                    =  96,
+    GameInputLabelMode                     =  97,
+    GameInputLabelSelect                   =  98,
+    GameInputLabelMenu                     =  99,
+    GameInputLabelView                     = 100,
+    GameInputLabelBack                     = 101,
+    GameInputLabelStart                    = 102,
+    GameInputLabelOptions                  = 103,
+    GameInputLabelShare                    = 104,
+    GameInputLabelUp                       = 105,
+    GameInputLabelDown                     = 106,
+    GameInputLabelLeft                     = 107,
+    GameInputLabelRight                    = 108,
+    GameInputLabelLB                       = 109,
+    GameInputLabelLT                       = 110,
+    GameInputLabelLSB                      = 111,
+    GameInputLabelL1                       = 112,
+    GameInputLabelL2                       = 113,
+    GameInputLabelL3                       = 114,
+    GameInputLabelRB                       = 115,
+    GameInputLabelRT                       = 116,
+    GameInputLabelRSB                      = 117,
+    GameInputLabelR1                       = 118,
+    GameInputLabelR2                       = 119,
+    GameInputLabelR3                       = 120,
+    GameInputLabelPaddleLeft1              = 121,
+    GameInputLabelPaddleLeft2              = 122,
+    GameInputLabelPaddleRight1             = 123,
+    GameInputLabelPaddleRight2             = 124,
+};
+
+enum GameInputFeedbackAxes
+{
+    GameInputFeedbackAxisNone     = 0x00000000,
+    GameInputFeedbackAxisLinearX  = 0x00000001,
+    GameInputFeedbackAxisLinearY  = 0x00000002,
+    GameInputFeedbackAxisLinearZ  = 0x00000004,
+    GameInputFeedbackAxisAngularX = 0x00000008,
+    GameInputFeedbackAxisAngularY = 0x00000010,
+    GameInputFeedbackAxisAngularZ = 0x00000020,
+    GameInputFeedbackAxisNormal   = 0x00000040
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputFeedbackAxes)
+
+enum GameInputFeedbackEffectState
+{
+    GameInputFeedbackStopped = 0,
+    GameInputFeedbackRunning = 1,
+    GameInputFeedbackPaused  = 2
+};
+
+enum GameInputForceFeedbackEffectKind
+{
+    GameInputForceFeedbackConstant         = 0,
+    GameInputForceFeedbackRamp             = 1,
+    GameInputForceFeedbackSineWave         = 2,
+    GameInputForceFeedbackSquareWave       = 3,
+    GameInputForceFeedbackTriangleWave     = 4,
+    GameInputForceFeedbackSawtoothUpWave   = 5,
+    GameInputForceFeedbackSawtoothDownWave = 6,
+    GameInputForceFeedbackSpring           = 7,
+    GameInputForceFeedbackFriction         = 8,
+    GameInputForceFeedbackDamper           = 9,
+    GameInputForceFeedbackInertia          = 10
+};
+
+enum GameInputRumbleMotors
+{
+    GameInputRumbleNone          = 0x00000000,
+    GameInputRumbleLowFrequency  = 0x00000001,
+    GameInputRumbleHighFrequency = 0x00000002,
+    GameInputRumbleLeftTrigger   = 0x00000004,
+    GameInputRumbleRightTrigger  = 0x00000008
+};
+
+DEFINE_ENUM_FLAG_OPERATORS(GameInputRumbleMotors)
+
+interface IGameInput;
+interface IGameInputReading;
+interface IGameInputDevice;
+interface IGameInputDispatcher;
+interface IGameInputForceFeedbackEffect;
+interface IGameInputMapper;
+
+typedef uint64_t GameInputCallbackToken;
+
+constexpr GUID GAMEINPUT_HAPTIC_LOCATION_NONE          = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
+constexpr GUID GAMEINPUT_HAPTIC_LOCATION_GRIP_LEFT     = { 0x08c707c2, 0x66bb, 0x406c, { 0xa8, 0x4a, 0xdf, 0xe0, 0x85, 0x12, 0x0a, 0x92 } };
+constexpr GUID GAMEINPUT_HAPTIC_LOCATION_GRIP_RIGHT    = { 0x155a0b77, 0x8bb2, 0x40db, { 0x86, 0x90, 0xb6, 0xd4, 0x11, 0x26, 0xdf, 0xc1 } };
+constexpr GUID GAMEINPUT_HAPTIC_LOCATION_TRIGGER_LEFT  = { 0x8de4d896, 0x5559, 0x4081, { 0x86, 0xe5, 0x17, 0x24, 0xcc, 0x07, 0xc6, 0xbc } };
+constexpr GUID GAMEINPUT_HAPTIC_LOCATION_TRIGGER_RIGHT = { 0xff0cb557, 0x3af5, 0x406b, { 0x8b, 0x0f, 0x55, 0x5a, 0x2d, 0x92, 0xa2, 0x20 } };
+
+const uint32_t GAMEINPUT_HAPTIC_MAX_LOCATIONS              = 8;
+const uint32_t GAMEINPUT_HAPTIC_MAX_AUDIO_ENDPOINT_ID_SIZE = 256;
+
+typedef void (CALLBACK* GameInputReadingCallback)(
+    _In_ GameInputCallbackToken callbackToken,
+    _In_ void* context,
+    _In_ IGameInputReading* reading);
+
+typedef void (CALLBACK* GameInputDeviceCallback)(
+    _In_ GameInputCallbackToken callbackToken,
+    _In_ void* context,
+    _In_ IGameInputDevice* device,
+    _In_ uint64_t timestamp,
+    _In_ GameInputDeviceStatus currentStatus,
+    _In_ GameInputDeviceStatus previousStatus);
+
+typedef void (CALLBACK* GameInputSystemButtonCallback)(
+    _In_ GameInputCallbackToken callbackToken,
+    _In_ void* context,
+    _In_ IGameInputDevice* device,
+    _In_ uint64_t timestamp,
+    _In_ GameInputSystemButtons currentButtons,
+    _In_ GameInputSystemButtons previousButtons);
+
+typedef void (CALLBACK* GameInputKeyboardLayoutCallback)(
+    _In_ GameInputCallbackToken callbackToken,
+    _In_ void* context,
+    _In_ IGameInputDevice* device,
+    _In_ uint64_t timestamp,
+    _In_ uint32_t currentLayout,
+    _In_ uint32_t previousLayout);
+
+struct GameInputKeyState
+{
+    uint32_t scanCode;
+    uint32_t codePoint;
+    uint8_t  virtualKey;
+    bool     isDeadKey;
+};
+
+struct GameInputMouseState
+{
+    GameInputMouseButtons   buttons;
+    GameInputMousePositions positions;
+    int64_t                 positionX;
+    int64_t                 positionY;
+    int64_t                 absolutePositionX;
+    int64_t                 absolutePositionY;
+    int64_t                 wheelX;
+    int64_t                 wheelY;
+};
+
+struct GameInputVersion
+{
+    uint16_t major;
+    uint16_t minor;
+    uint16_t build;
+    uint16_t revision;
+};
+
+struct GameInputSensorsState
+{
+    // GameInputSensorsAccelerometer
+    float accelerationInGX;
+    float accelerationInGY;
+    float accelerationInGZ;
+
+    // GameInputSensorsGyrometer
+    float angularVelocityInRadPerSecX;
+    float angularVelocityInRadPerSecY;
+    float angularVelocityInRadPerSecZ;
+
+    // GameInputSensorsCompass
+    float headingInDegreesFromMagneticNorth;
+    GameInputSensorAccuracy headingAccuracy;
+
+    // GameInputSensorsOrientation
+    float orientationW;
+    float orientationX;
+    float orientationY;
+    float orientationZ;
+};
+
+struct GameInputArcadeStickState
+{
+    GameInputArcadeStickButtons buttons;
+};
+
+struct GameInputFlightStickState
+{
+    GameInputFlightStickButtons buttons;
+    GameInputSwitchPosition     hatSwitch;
+    float                       roll;
+    float                       pitch;
+    float                       yaw;
+    float                       throttle;
+};
+
+struct GameInputGamepadState
+{
+    GameInputGamepadButtons buttons;
+    float                   leftTrigger;
+    float                   rightTrigger;
+    float                   leftThumbstickX;
+    float                   leftThumbstickY;
+    float                   rightThumbstickX;
+    float                   rightThumbstickY;
+};
+
+struct GameInputRacingWheelState
+{
+    GameInputRacingWheelButtons buttons;
+    int32_t                     patternShifterGear;
+    float                       wheel;
+    float                       throttle;
+    float                       brake;
+    float                       clutch;
+    float                       handbrake;
+};
+
+struct GameInputUsage
+{
+    uint16_t page;
+    uint16_t id;
+};
+
+const uint32_t GAMEINPUT_MAX_SWITCH_STATES = 8;
+
+struct GameInputControllerSwitchInfo
+{
+    GameInputLabel      labels[GAMEINPUT_MAX_SWITCH_STATES];
+    GameInputSwitchKind kind;
+};
+
+struct GameInputControllerInfo
+{
+    uint32_t                                                                      controllerAxisCount;
+    _Field_size_full_(controllerAxisCount) const GameInputLabel*                  controllerAxisLabels;
+    uint32_t                                                                      controllerButtonCount;
+    _Field_size_full_(controllerButtonCount) const GameInputLabel*                controllerButtonLabels;
+    uint32_t                                                                      controllerSwitchCount;
+    _Field_size_full_(controllerSwitchCount) const GameInputControllerSwitchInfo* controllerSwitchInfo;
+};
+
+struct GameInputKeyboardInfo
+{
+    GameInputKeyboardKind kind;
+    uint32_t              layout;
+    uint32_t              keyCount;
+    uint32_t              functionKeyCount;
+    uint32_t              maxSimultaneousKeys;
+    uint32_t              platformType;
+    uint32_t              platformSubtype;
+};
+
+struct GameInputMouseInfo
+{
+    GameInputMouseButtons supportedButtons;
+    uint32_t              sampleRate;
+    bool                  hasWheelX;
+    bool                  hasWheelY;
+};
+
+struct GameInputSensorsInfo
+{
+    GameInputSensorsKind supportedSensors;
+};
+
+struct GameInputArcadeStickInfo
+{
+    GameInputLabel menuButtonLabel;
+    GameInputLabel viewButtonLabel;
+    GameInputLabel stickUpLabel;
+    GameInputLabel stickDownLabel;
+    GameInputLabel stickLeftLabel;
+    GameInputLabel stickRightLabel;
+    GameInputLabel actionButton1Label;
+    GameInputLabel actionButton2Label;
+    GameInputLabel actionButton3Label;
+    GameInputLabel actionButton4Label;
+    GameInputLabel actionButton5Label;
+    GameInputLabel actionButton6Label;
+    GameInputLabel specialButton1Label;
+    GameInputLabel specialButton2Label;
+    uint32_t       extraButtonCount;
+    uint32_t       extraAxisCount;
+};
+
+struct GameInputFlightStickInfo
+{
+    GameInputLabel menuButtonLabel;
+    GameInputLabel viewButtonLabel;
+    GameInputLabel firePrimaryButtonLabel;
+    GameInputLabel fireSecondaryButtonLabel;
+    GameInputLabel hatSwitchUpLabel;
+    GameInputLabel hatSwitchDownLabel;
+    GameInputLabel hatSwitchLeftLabel;
+    GameInputLabel hatSwitchRightLabel;
+    GameInputLabel aButtonLabel;
+    GameInputLabel bButtonLabel;
+    GameInputLabel xButtonLabel;
+    GameInputLabel yButtonLabel;
+    GameInputLabel leftShoulderButtonLabel;
+    GameInputLabel rightShoulderButtonLabel;
+    uint32_t       extraButtonCount;
+    uint32_t       extraAxisCount;
+};
+
+struct GameInputGamepadInfo
+{
+    GameInputGamepadButtons supportedLayout;
+    GameInputLabel          menuButtonLabel;
+    GameInputLabel          viewButtonLabel;
+    GameInputLabel          aButtonLabel;
+    GameInputLabel          bButtonLabel;
+    GameInputLabel          cButtonLabel;
+    GameInputLabel          xButtonLabel;
+    GameInputLabel          yButtonLabel;
+    GameInputLabel          zButtonLabel;
+    GameInputLabel          dpadUpLabel;
+    GameInputLabel          dpadDownLabel;
+    GameInputLabel          dpadLeftLabel;
+    GameInputLabel          dpadRightLabel;
+    GameInputLabel          leftShoulderButtonLabel;
+    GameInputLabel          rightShoulderButtonLabel;
+    GameInputLabel          leftThumbstickButtonLabel;
+    GameInputLabel          rightThumbstickButtonLabel;
+    uint32_t                extraButtonCount;
+    uint32_t                extraAxisCount;
+};
+
+struct GameInputRacingWheelInfo
+{
+    GameInputLabel menuButtonLabel;
+    GameInputLabel viewButtonLabel;
+    GameInputLabel previousGearButtonLabel;
+    GameInputLabel nextGearButtonLabel;
+    GameInputLabel dpadUpLabel;
+    GameInputLabel dpadDownLabel;
+    GameInputLabel dpadLeftLabel;
+    GameInputLabel dpadRightLabel;
+    GameInputLabel aButtonLabel;
+    GameInputLabel bButtonLabel;
+    GameInputLabel xButtonLabel;
+    GameInputLabel yButtonLabel;
+    GameInputLabel leftThumbstickButtonLabel;
+    GameInputLabel rightThumbstickButtonLabel;
+    bool           hasClutch;
+    bool           hasHandbrake;
+    bool           hasPatternShifter;
+    int32_t        minPatternShifterGear;
+    int32_t        maxPatternShifterGear;
+    float          maxWheelAngle;
+    uint32_t       extraButtonCount;
+    uint32_t       extraAxisCount;
+};
+
+struct GameInputForceFeedbackMotorInfo
+{
+    GameInputFeedbackAxes supportedAxes;
+    bool                  isConstantEffectSupported;
+    bool                  isRampEffectSupported;
+    bool                  isSineWaveEffectSupported;
+    bool                  isSquareWaveEffectSupported;
+    bool                  isTriangleWaveEffectSupported;
+    bool                  isSawtoothUpWaveEffectSupported;
+    bool                  isSawtoothDownWaveEffectSupported;
+    bool                  isSpringEffectSupported;
+    bool                  isFrictionEffectSupported;
+    bool                  isDamperEffectSupported;
+    bool                  isInertiaEffectSupported;
+};
+
+struct GameInputRawDeviceReportInfo
+{
+    GameInputRawDeviceReportKind kind;
+    uint32_t                     id;
+    uint32_t                     size;
+};
+
+struct GameInputDeviceInfo
+{
+    uint16_t               vendorId;
+    uint16_t               productId;
+    uint16_t               revisionNumber;
+    GameInputUsage         usage;
+    GameInputVersion       hardwareVersion;
+    GameInputVersion       firmwareVersion;
+    APP_LOCAL_DEVICE_ID    deviceId;
+    APP_LOCAL_DEVICE_ID    deviceRootId;
+    GameInputDeviceFamily  deviceFamily;
+    GameInputKind          supportedInput;
+    GameInputRumbleMotors  supportedRumbleMotors;
+    GameInputSystemButtons supportedSystemButtons;
+    GUID                   containerId;
+    const char*            displayName;
+    const char*            pnpPath;
+
+    _Field_size_full_opt_(1) const GameInputKeyboardInfo*    keyboardInfo;
+    _Field_size_full_opt_(1) const GameInputMouseInfo*       mouseInfo;
+    _Field_size_full_opt_(1) const GameInputSensorsInfo*     sensorsInfo;
+    _Field_size_full_opt_(1) const GameInputControllerInfo*  controllerInfo;
+    _Field_size_full_opt_(1) const GameInputArcadeStickInfo* arcadeStickInfo;
+    _Field_size_full_opt_(1) const GameInputFlightStickInfo* flightStickInfo;
+    _Field_size_full_opt_(1) const GameInputGamepadInfo*     gamepadInfo;
+    _Field_size_full_opt_(1) const GameInputRacingWheelInfo* racingWheelInfo;
+
+    uint32_t forceFeedbackMotorCount;
+    _Field_size_full_(forceFeedbackMotorCount) const GameInputForceFeedbackMotorInfo* forceFeedbackMotorInfo;
+
+    uint32_t inputReportCount;
+    _Field_size_full_opt_(inputReportCount) const GameInputRawDeviceReportInfo* inputReportInfo;
+
+    uint32_t outputReportCount;
+    _Field_size_full_opt_(outputReportCount) const GameInputRawDeviceReportInfo* outputReportInfo;
+};
+
+struct GameInputHapticInfo
+{
+    _Field_z_ wchar_t                                         audioEndpointId[GAMEINPUT_HAPTIC_MAX_AUDIO_ENDPOINT_ID_SIZE];
+    _Field_range_(1, GAMEINPUT_HAPTIC_MAX_LOCATIONS) uint32_t locationCount;
+    _Field_size_full_(locationCount) GUID                     locations[GAMEINPUT_HAPTIC_MAX_LOCATIONS];
+};
+
+struct GameInputForceFeedbackEnvelope
+{
+    uint64_t attackDuration;
+    uint64_t sustainDuration;
+    uint64_t releaseDuration;
+    float    attackGain;
+    float    sustainGain;
+    float    releaseGain;
+    uint32_t playCount;
+    uint64_t repeatDelay;
+};
+
+struct GameInputForceFeedbackMagnitude
+{
+    float linearX;
+    float linearY;
+    float linearZ;
+    float angularX;
+    float angularY;
+    float angularZ;
+    float normal;
+};
+
+struct GameInputForceFeedbackConditionParams
+{
+    GameInputForceFeedbackMagnitude magnitude;
+    float                           positiveCoefficient;
+    float                           negativeCoefficient;
+    float                           maxPositiveMagnitude;
+    float                           maxNegativeMagnitude;
+    float                           deadZone;
+    float                           bias;
+};
+
+struct GameInputForceFeedbackConstantParams
+{
+    GameInputForceFeedbackEnvelope  envelope;
+    GameInputForceFeedbackMagnitude magnitude;
+};
+
+struct GameInputForceFeedbackPeriodicParams
+{
+    GameInputForceFeedbackEnvelope  envelope;
+    GameInputForceFeedbackMagnitude magnitude;
+    float                           frequency;
+    float                           phase;
+    float                           bias;
+};
+
+struct GameInputForceFeedbackRampParams
+{
+    GameInputForceFeedbackEnvelope  envelope;
+    GameInputForceFeedbackMagnitude startMagnitude;
+    GameInputForceFeedbackMagnitude endMagnitude;
+};
+
+struct GameInputForceFeedbackParams
+{
+    GameInputForceFeedbackEffectKind kind;
+    union
+    {
+        GameInputForceFeedbackConstantParams  constant;
+        GameInputForceFeedbackRampParams      ramp;
+        GameInputForceFeedbackPeriodicParams  sineWave;
+        GameInputForceFeedbackPeriodicParams  squareWave;
+        GameInputForceFeedbackPeriodicParams  triangleWave;
+        GameInputForceFeedbackPeriodicParams  sawtoothUpWave;
+        GameInputForceFeedbackPeriodicParams  sawtoothDownWave;
+        GameInputForceFeedbackConditionParams spring;
+        GameInputForceFeedbackConditionParams friction;
+        GameInputForceFeedbackConditionParams damper;
+        GameInputForceFeedbackConditionParams inertia;
+    } data;
+};
+
+struct GameInputRumbleParams
+{
+    float lowFrequency;
+    float highFrequency;
+    float leftTrigger;
+    float rightTrigger;
+};
+
+enum GameInputElementKind
+{
+    GameInputElementKindNone   = 0,
+    GameInputElementKindAxis   = 1,
+    GameInputElementKindButton = 2,
+    GameInputElementKindSwitch = 3
+};
+
+struct GameInputAxisMapping
+{
+    GameInputElementKind controllerElementKind;
+    uint32_t             controllerIndex;
+
+    // When axis is mapped from a axis
+    bool isInverted;
+
+    // When the axis is mapped from a button
+    bool     fromTwoButtons;
+    uint32_t buttonMinIndexValue;
+
+    // When the axis is mapped from a switch
+    GameInputSwitchPosition referenceDirection;
+};
+
+struct GameInputButtonMapping
+{
+    GameInputElementKind controllerElementKind;
+    uint32_t             controllerIndex;
+
+    // When the button is mapped from an axis
+    bool isInverted;
+
+    // Button mapped from button only needs the index
+
+    // When the button is mapped from a switch
+    GameInputSwitchPosition switchPosition;
+};
+
+const IID IID_IGameInput = {0x20efc1c7, 0x5d9a, 0x43ba, {0xb2, 0x6f, 0xb8, 0x07, 0xfa, 0x48, 0x60, 0x9c}};
+
+DECLARE_INTERFACE_IID_(IGameInput, IUnknown, "20EFC1C7-5D9A-43BA-B26F-B807FA48609C")
+{
+    IFACEMETHOD_(uint64_t, GetCurrentTimestamp)() PURE;
+
+    IFACEMETHOD(GetCurrentReading)(
+        _In_ GameInputKind inputKind,
+        _In_opt_ IGameInputDevice* device,
+        _COM_Outptr_ IGameInputReading** reading) PURE;
+
+    IFACEMETHOD(GetNextReading)(
+        _In_ IGameInputReading* referenceReading,
+        _In_ GameInputKind inputKind,
+        _In_opt_ IGameInputDevice* device,
+        _COM_Outptr_ IGameInputReading** reading) PURE;
+
+    IFACEMETHOD(GetPreviousReading)(
+        _In_ IGameInputReading* referenceReading,
+        _In_ GameInputKind inputKind,
+        _In_opt_ IGameInputDevice* device,
+        _COM_Outptr_ IGameInputReading** reading) PURE;
+
+    IFACEMETHOD(RegisterReadingCallback)(
+        _In_opt_ IGameInputDevice* device,
+        _In_ GameInputKind inputKind,
+        _In_opt_ void* context,
+        _In_ GameInputReadingCallback callbackFunc,
+        _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken* callbackToken) PURE;
+
+    IFACEMETHOD(RegisterDeviceCallback)(
+        _In_opt_ IGameInputDevice* device,
+        _In_ GameInputKind inputKind,
+        _In_ GameInputDeviceStatus statusFilter,
+        _In_ GameInputEnumerationKind enumerationKind,
+        _In_opt_ void* context,
+        _In_ GameInputDeviceCallback callbackFunc,
+        _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken* callbackToken) PURE;
+
+    IFACEMETHOD(RegisterSystemButtonCallback)(
+        _In_opt_ IGameInputDevice* device,
+        _In_ GameInputSystemButtons buttonFilter,
+        _In_opt_ void* context,
+        _In_ GameInputSystemButtonCallback callbackFunc,
+        _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken* callbackToken) PURE;
+
+    IFACEMETHOD(RegisterKeyboardLayoutCallback)(
+        _In_opt_ IGameInputDevice* device,
+        _In_opt_ void* context,
+        _In_ GameInputKeyboardLayoutCallback callbackFunc,
+        _Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken* callbackToken) PURE;
+
+    IFACEMETHOD_(void, StopCallback)(
+        _In_ GameInputCallbackToken callbackToken) PURE;
+
+    IFACEMETHOD_(bool, UnregisterCallback)(
+        _In_ GameInputCallbackToken callbackToken) PURE;
+
+    IFACEMETHOD(CreateDispatcher)(
+        _COM_Outptr_ IGameInputDispatcher** dispatcher) PURE;
+
+    IFACEMETHOD(FindDeviceFromId)(
+        _In_ const APP_LOCAL_DEVICE_ID* value,
+        _COM_Outptr_ IGameInputDevice** device) PURE;
+
+    IFACEMETHOD(FindDeviceFromPlatformString)(
+        _In_ LPCWSTR value,
+        _COM_Outptr_ IGameInputDevice** device) PURE;
+
+    IFACEMETHOD_(void, SetFocusPolicy)(
+        _In_ GameInputFocusPolicy policy) PURE;
+
+    IFACEMETHOD(CreateAggregateDevice)(
+        _In_ GameInputKind inputKind,
+        _Out_ APP_LOCAL_DEVICE_ID* deviceId) PURE;
+
+    IFACEMETHOD(DisableAggregateDevice)(
+        _In_ const APP_LOCAL_DEVICE_ID* deviceId) PURE;
+};
+
+DECLARE_INTERFACE_IID_(IGameInputRawDeviceReport, IUnknown, "05A42D89-2CB6-45A3-874D-E635723587AB")
+{
+    IFACEMETHOD_(void, GetDevice)(
+        _Outptr_ IGameInputDevice** device) PURE;
+
+    IFACEMETHOD_(void, GetReportInfo)(
+        _Out_ GameInputRawDeviceReportInfo* reportInfo) PURE;
+
+    IFACEMETHOD_(size_t, GetRawDataSize)() PURE;
+
+    IFACEMETHOD_(size_t, GetRawData)(
+        _In_ size_t bufferSize,
+        _Out_writes_(bufferSize) void* buffer) PURE;
+
+    IFACEMETHOD_(bool, SetRawData)(
+        _In_ size_t bufferSize,
+        _In_reads_(bufferSize) const void* buffer) PURE;
+};
+
+DECLARE_INTERFACE_IID_(IGameInputReading, IUnknown, "C81C4CDE-ED1A-4631-A30F-C556A6241A1F")
+{
+    IFACEMETHOD_(GameInputKind, GetInputKind)() PURE;
+
+    IFACEMETHOD_(uint64_t, GetTimestamp)() PURE;
+
+    IFACEMETHOD_(void, GetDevice)(
+        _Outptr_ IGameInputDevice** device) PURE;
+
+    IFACEMETHOD_(uint32_t, GetControllerAxisCount)() PURE;
+
+    IFACEMETHOD_(uint32_t, GetControllerAxisState)(
+        _In_ uint32_t stateArrayCount,
+        _Out_writes_(stateArrayCount) float* stateArray) PURE;
+
+    IFACEMETHOD_(uint32_t, GetControllerButtonCount)() PURE;
+
+    IFACEMETHOD_(uint32_t, GetControllerButtonState)(
+        _In_ uint32_t stateArrayCount,
+        _Out_writes_(stateArrayCount) bool* stateArray) PURE;
+
+    IFACEMETHOD_(uint32_t, GetControllerSwitchCount)() PURE;
+
+    IFACEMETHOD_(uint32_t, GetControllerSwitchState)(
+        _In_ uint32_t stateArrayCount,
+        _Out_writes_(stateArrayCount) GameInputSwitchPosition* stateArray) PURE;
+
+    IFACEMETHOD_(uint32_t, GetKeyCount)() PURE;
+
+    IFACEMETHOD_(uint32_t, GetKeyState)(
+        _In_ uint32_t stateArrayCount,
+        _Out_writes_(stateArrayCount) GameInputKeyState* stateArray) PURE;
+
+    IFACEMETHOD_(bool, GetMouseState)(
+        _Out_ GameInputMouseState* state) PURE;
+
+    IFACEMETHOD_(bool, GetSensorsState)(
+        _Out_ GameInputSensorsState* state) PURE;
+
+    IFACEMETHOD_(bool, GetArcadeStickState)(
+        _Out_ GameInputArcadeStickState* state) PURE;
+
+    IFACEMETHOD_(bool, GetFlightStickState)(
+        _Out_ GameInputFlightStickState* state) PURE;
+
+    IFACEMETHOD_(bool, GetGamepadState)(
+        _Out_ GameInputGamepadState* state) PURE;
+
+    IFACEMETHOD_(bool, GetRacingWheelState)(
+        _Out_ GameInputRacingWheelState* state) PURE;
+
+    IFACEMETHOD_(bool, GetRawReport)(
+        _Outptr_result_maybenull_ IGameInputRawDeviceReport** report) PURE;
+};
+
+DECLARE_INTERFACE_IID_(IGameInputDevice, IUnknown, "63E2F38B-A399-4275-8AE7-D4C6E524D12A")
+{
+    IFACEMETHOD(GetDeviceInfo)(
+        _Outptr_ const GameInputDeviceInfo** info) PURE;
+
+    IFACEMETHOD(GetHapticInfo)(
+        _Out_ GameInputHapticInfo* info) PURE;
+
+    IFACEMETHOD_(GameInputDeviceStatus, GetDeviceStatus)() PURE;
+
+    IFACEMETHOD(CreateForceFeedbackEffect)(
+        _In_ uint32_t motorIndex,
+        _In_ const GameInputForceFeedbackParams* params,
+        _COM_Outptr_ IGameInputForceFeedbackEffect** effect) PURE;
+
+    IFACEMETHOD_(bool, IsForceFeedbackMotorPoweredOn)(
+        _In_ uint32_t motorIndex) PURE;
+
+    IFACEMETHOD_(void, SetForceFeedbackMotorGain)(
+        _In_ uint32_t motorIndex,
+        _In_ float masterGain) PURE;
+
+    IFACEMETHOD_(void, SetRumbleState)(
+        _In_opt_ const GameInputRumbleParams* params) PURE;
+
+    IFACEMETHOD(DirectInputEscape)(
+        _In_ uint32_t command,
+        _In_reads_bytes_(bufferInSize) const void* bufferIn,
+        _In_ uint32_t bufferInSize,
+        _Out_writes_bytes_(bufferOutSize) void* bufferOut,
+        _In_ uint32_t bufferOutSize,
+        _Out_opt_ uint32_t* bufferOutSizeWritten) PURE;
+
+    IFACEMETHOD(CreateInputMapper)(
+        _COM_Outptr_ IGameInputMapper** inputMapper) PURE;
+
+    IFACEMETHOD(GetExtraAxisCount)(
+        _In_ GameInputKind inputKind,
+        _Out_ uint32_t* extraAxisCount) PURE;
+
+    IFACEMETHOD(GetExtraButtonCount)(
+        _In_ GameInputKind inputKind,
+        _Out_ uint32_t* extraButtonCount) PURE;
+
+    IFACEMETHOD(GetExtraAxisIndexes)(
+        _In_ GameInputKind inputKind,
+        _In_ uint32_t extraAxisCount,
+        _Out_writes_(extraAxisCount) uint8_t* extraAxisIndexes) PURE;
+
+    IFACEMETHOD(GetExtraButtonIndexes)(
+        _In_ GameInputKind inputKind,
+        _In_ uint32_t extraButtonCount,
+        _Out_writes_(extraButtonCount) uint8_t* extraButtonIndexes) PURE;
+
+    IFACEMETHOD(CreateRawDeviceReport)(
+        _In_ uint32_t reportId,
+        _In_ GameInputRawDeviceReportKind reportKind,
+        _COM_Outptr_ IGameInputRawDeviceReport** report) PURE;
+
+    IFACEMETHOD(SendRawDeviceOutput)(
+        _In_ IGameInputRawDeviceReport* report) PURE;
+};
+
+DECLARE_INTERFACE_IID_(IGameInputDispatcher, IUnknown, "415EED2E-98CB-42C2-8F28-B94601074E31")
+{
+    IFACEMETHOD_(bool, Dispatch)(
+        _In_ uint64_t quotaInMicroseconds) PURE;
+
+    IFACEMETHOD(OpenWaitHandle)(
+        _Outptr_result_nullonfailure_ HANDLE* waitHandle) PURE;
+};
+
+DECLARE_INTERFACE_IID_(IGameInputForceFeedbackEffect, IUnknown, "FF61096A-3373-4093-A1DF-6D31846B3511")
+{
+    IFACEMETHOD_(void, GetDevice)(
+        _Outptr_ IGameInputDevice** device) PURE;
+
+    IFACEMETHOD_(uint32_t, GetMotorIndex)() PURE;
+
+    IFACEMETHOD_(float, GetGain)() PURE;
+
+    IFACEMETHOD_(void, SetGain)(
+        _In_ float gain) PURE;
+
+    IFACEMETHOD_(void, GetParams)(
+        _Out_ GameInputForceFeedbackParams* params) PURE;
+
+    IFACEMETHOD_(bool, SetParams)(
+        _In_ const GameInputForceFeedbackParams* params) PURE;
+
+    IFACEMETHOD_(GameInputFeedbackEffectState, GetState)() PURE;
+
+    IFACEMETHOD_(void, SetState)(
+        _In_ GameInputFeedbackEffectState state) PURE;
+};
+
+DECLARE_INTERFACE_IID_(IGameInputMapper, IUnknown, "3C600700-F16C-49CE-9BE6-6A2EF752ED5E")
+{
+    IFACEMETHOD_(bool, GetArcadeStickButtonMappingInfo)(
+        _In_ GameInputArcadeStickButtons buttonElement,
+		_Out_ GameInputButtonMapping* mapping) PURE;
+
+    IFACEMETHOD_(bool, GetFlightStickAxisMappingInfo)(
+        _In_ GameInputFlightStickAxes axisElement,
+		_Out_ GameInputAxisMapping* mapping) PURE;
+
+    IFACEMETHOD_(bool, GetFlightStickButtonMappingInfo)(
+        _In_ GameInputFlightStickButtons buttonElement,
+		_Out_ GameInputButtonMapping* mapping) PURE;
+
+    IFACEMETHOD_(bool, GetGamepadAxisMappingInfo)(
+        _In_ GameInputGamepadAxes axisElement,
+		_Out_ GameInputAxisMapping* mapping) PURE;
+
+    IFACEMETHOD_(bool, GetGamepadButtonMappingInfo)(
+        _In_ GameInputGamepadButtons buttonElement,
+		_Out_ GameInputButtonMapping* mapping) PURE;
+
+    IFACEMETHOD_(bool, GetRacingWheelAxisMappingInfo)(
+        _In_ GameInputRacingWheelAxes axisElement,
+		_Out_ GameInputAxisMapping* mapping) PURE;
+
+    IFACEMETHOD_(bool, GetRacingWheelButtonMappingInfo)(
+        _In_ GameInputRacingWheelButtons buttonElement,
+        _Out_ GameInputButtonMapping* mapping) PURE;
+};
+
+STDAPI GameInputInitialize(
+    _In_ REFIID riid,
+    _COM_Outptr_ LPVOID* ppv);
+
+inline HRESULT GameInputCreate(
+    _COM_Outptr_ IGameInput** gameInput)
+{
+    return GameInputInitialize(
+        IID_IGameInput,
+        reinterpret_cast<void**>(gameInput));
+}
+
+const LONG GAMEINPUT_FACILITY = 0x38A;
+
+const HRESULT GAMEINPUT_E_DEVICE_DISCONNECTED               = _HRESULT_TYPEDEF_(0x838A0001L);
+const HRESULT GAMEINPUT_E_DEVICE_NOT_FOUND                  = _HRESULT_TYPEDEF_(0x838A0002L);
+const HRESULT GAMEINPUT_E_READING_NOT_FOUND                 = _HRESULT_TYPEDEF_(0x838A0003L);
+const HRESULT GAMEINPUT_E_REFERENCE_READING_TOO_OLD         = _HRESULT_TYPEDEF_(0x838A0004L);
+const HRESULT GAMEINPUT_E_FEEDBACK_NOT_SUPPORTED            = _HRESULT_TYPEDEF_(0x838A0007L);
+const HRESULT GAMEINPUT_E_OBJECT_NO_LONGER_EXISTS           = _HRESULT_TYPEDEF_(0x838A0008L);
+const HRESULT GAMEINPUT_E_CALLBACK_NOT_FOUND                = _HRESULT_TYPEDEF_(0x838A0009L);
+const HRESULT GAMEINPUT_E_HAPTIC_INFO_NOT_FOUND             = _HRESULT_TYPEDEF_(0x838A000AL);
+const HRESULT GAMEINPUT_E_AGGREGATE_OPERATION_NOT_SUPPORTED = _HRESULT_TYPEDEF_(0x838A000BL);
+const HRESULT GAMEINPUT_E_INPUT_KIND_NOT_PRESENT            = _HRESULT_TYPEDEF_(0x838A000CL);
+
+}} // namespace GameInput::v3
+
+#endif // #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
+#pragma endregion // Application Family or OneCore Family or Games Family