mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-07-31 04:28:56 +00:00
windows: vendor GameInput headers
This commit is contained in:
committed by
Anonymous Maarten
parent
331e10c2a3
commit
b048e8e6f8
15
.github/workflows/create-test-plan.py
vendored
15
.github/workflows/create-test-plan.py
vendored
@@ -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
|
||||
|
||||
7
.github/workflows/generic.yml
vendored
7
.github/workflows/generic.yml
vendored
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
@@ -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": {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
src/core/windows/gameinput/gameinput.cpp
Normal file
637
src/core/windows/gameinput/gameinput.cpp
Normal file
@@ -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",
|
||||
®GetValue));
|
||||
|
||||
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
src/core/windows/gameinput/gameinput.h
Normal file
1332
src/core/windows/gameinput/gameinput.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user