From 5b202483359b1cbbe347dac0ffeb1f624e9b3307 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Tue, 7 Oct 2025 17:42:09 -0700 Subject: [PATCH 1/2] GamePadTest updated for GameInput v3 --- Inc/GamePad.h | 4 +++- Inc/Keyboard.h | 5 ++++- Inc/Mouse.h | 5 ++++- Src/GamePad.cpp | 43 +++++++++++++++++++++++++++++++++++++----- Src/Keyboard.cpp | 49 +++++++++++++++++++++++++++++++++++++----------- Src/Mouse.cpp | 48 +++++++++++++++++++++++++++++++++++++---------- 6 files changed, 125 insertions(+), 29 deletions(-) diff --git a/Inc/GamePad.h b/Inc/GamePad.h index 0b20bec1..03e372bc 100644 --- a/Inc/GamePad.h +++ b/Inc/GamePad.h @@ -28,7 +28,7 @@ #ifdef USING_GAMEINPUT #include -#if !defined(_GAMING_XBOX) && defined(_MSC_VER) +#if defined(_MSC_VER) && (defined(_GAMING_XBOX) || defined(GAMEINPUT_API_VERSION)) #pragma comment(lib,"gameinput.lib") #endif @@ -335,6 +335,8 @@ namespace DirectX using GameInputDevice_t = GameInput::v1::IGameInputDevice; #elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 2) using GameInputDevice_t = GameInput::v2::IGameInputDevice; + #elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 3) + using GameInputDevice_t = GameInput::v3::IGameInputDevice; #else using GameInputDevice_t = ::IGameInputDevice; #endif diff --git a/Inc/Keyboard.h b/Inc/Keyboard.h index 3e5c75f5..6ac3b45c 100644 --- a/Inc/Keyboard.h +++ b/Inc/Keyboard.h @@ -24,9 +24,12 @@ #endif // !USING_XINPUT && !USING_GAMEINPUT && !USING_WINDOWS_GAMING_INPUT -#if defined(USING_GAMEINPUT) && !defined(_GAMING_XBOX) && defined(_MSC_VER) +#ifdef USING_GAMEINPUT +#include +#if defined(_MSC_VER) && (defined(_GAMING_XBOX) || defined(GAMEINPUT_API_VERSION)) #pragma comment(lib,"gameinput.lib") #endif +#endif #include #include diff --git a/Inc/Mouse.h b/Inc/Mouse.h index db0c1f0b..f1cc9ef6 100644 --- a/Inc/Mouse.h +++ b/Inc/Mouse.h @@ -24,9 +24,12 @@ #endif // !USING_XINPUT && !USING_GAMEINPUT && !USING_WINDOWS_GAMING_INPUT -#if defined(USING_GAMEINPUT) && !defined(_GAMING_XBOX) && defined(_MSC_VER) +#ifdef USING_GAMEINPUT +#include +#if defined(_MSC_VER) && (defined(_GAMING_XBOX) || defined(GAMEINPUT_API_VERSION)) #pragma comment(lib,"gameinput.lib") #endif +#endif #include #include diff --git a/Src/GamePad.cpp b/Src/GamePad.cpp index 929ab5ac..18d38fed 100644 --- a/Src/GamePad.cpp +++ b/Src/GamePad.cpp @@ -84,15 +84,19 @@ namespace #pragma region Implementations #ifdef USING_GAMEINPUT +//====================================================================================== +// GameInput +//====================================================================================== + #if defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 1) using namespace GameInput::v1; #elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 2) using namespace GameInput::v2; +#elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 3) +using namespace GameInput::v3; #endif -//====================================================================================== -// GameInput -//====================================================================================== +using GameInputCreateFn = HRESULT(*)(IGameInput**); class GamePad::Impl { @@ -110,7 +114,26 @@ class GamePad::Impl s_gamePad = this; + #if defined(_GAMING_XBOX) || defined(GAMEINPUT_API_VERSION) HRESULT hr = GameInputCreate(mGameInput.GetAddressOf()); + #else + if (!s_gameInputCreate) + { + s_gameInputModule = LoadLibraryExW(L"GameInput.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (s_gameInputModule) + { + s_gameInputCreate = reinterpret_cast(static_cast(GetProcAddress(s_gameInputModule, "GameInputCreate"))); + } + + if (!s_gameInputCreate) + { + DebugTrace("ERROR: GetProcAddress GameInputCreate failed\n"); + throw std::runtime_error("GameInput.dll is not installed on this system"); + } + } + + HRESULT hr = s_gameInputCreate(mGameInput.GetAddressOf()); + #endif if (SUCCEEDED(hr)) { ThrowIfFailed(mGameInput->RegisterDeviceCallback( @@ -126,8 +149,8 @@ class GamePad::Impl { DebugTrace("ERROR: GameInputCreate [gamepad] failed with %08X\n", static_cast(hr)); #ifdef _GAMING_XBOX - ThrowIfFailed(hr); - #elif defined(_DEBUG) + throw com_exception(hr); + #else DebugTrace( "\t**** Check that the 'GameInput Service' is running on this system. ****\n" "\t**** NOTE: All calls to GetState will be reported as 'not connected'. ****\n"); @@ -417,10 +440,20 @@ class GamePad::Impl SetEvent(impl->mCtrlChanged); } } + +#if !defined(_GAMING_XBOX) && !defined(GAMEINPUT_API_VERSION) + static HMODULE s_gameInputModule; + static GameInputCreateFn s_gameInputCreate; +#endif }; GamePad::Impl* GamePad::Impl::s_gamePad = nullptr; +#if !defined(_GAMING_XBOX) && !defined(GAMEINPUT_API_VERSION) +HMODULE GamePad::Impl::s_gameInputModule = nullptr; +GameInputCreateFn GamePad::Impl::s_gameInputCreate = nullptr; +#endif + void GamePad::RegisterEvents(HANDLE ctrlChanged) noexcept { pImpl->mCtrlChanged = (!ctrlChanged) ? INVALID_HANDLE_VALUE : ctrlChanged; diff --git a/Src/Keyboard.cpp b/Src/Keyboard.cpp index 7a96d8b1..16091c3c 100644 --- a/Src/Keyboard.cpp +++ b/Src/Keyboard.cpp @@ -51,18 +51,19 @@ namespace #pragma region Implementations #ifdef USING_GAMEINPUT -#include +//====================================================================================== +// GameInput +//====================================================================================== #if defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 1) using namespace GameInput::v1; #elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 2) using namespace GameInput::v2; +#elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 3) +using namespace GameInput::v3; #endif - -//====================================================================================== -// GameInput -//====================================================================================== +using GameInputCreateFn = HRESULT(*)(IGameInput**); class Keyboard::Impl { @@ -80,7 +81,26 @@ class Keyboard::Impl s_keyboard = this; + #if defined(_GAMING_XBOX) || defined(GAMEINPUT_API_VERSION) HRESULT hr = GameInputCreate(mGameInput.GetAddressOf()); + #else + if (!s_gameInputCreate) + { + s_gameInputModule = LoadLibraryExW(L"GameInput.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (s_gameInputModule) + { + s_gameInputCreate = reinterpret_cast(static_cast(GetProcAddress(s_gameInputModule, "GameInputCreate"))); + } + + if (!s_gameInputCreate) + { + DebugTrace("ERROR: GetProcAddress GameInputCreate failed\n"); + throw std::runtime_error("GameInput.dll is not installed on this system"); + } + } + + HRESULT hr = s_gameInputCreate(mGameInput.GetAddressOf()); + #endif if (SUCCEEDED(hr)) { ThrowIfFailed(mGameInput->RegisterDeviceCallback( @@ -96,12 +116,11 @@ class Keyboard::Impl { DebugTrace("ERROR: GameInputCreate [keyboard] failed with %08X\n", static_cast(hr)); #ifdef _GAMING_XBOX - ThrowIfFailed(hr); - #elif defined(_DEBUG) + throw com_exception(hr); + #else DebugTrace( - "\t**** Check that the 'GameInput Service' is running on this system. ****\n" - "\t**** NOTE: No keys will be returned and IsConnected will return false. ****\n" - ); + "\t**** Check that the 'GameInput Service' is running on this system. ****\n" + "\t**** NOTE: All calls to GetState will be reported as 'not connected'. ****\n"); #endif } } @@ -208,11 +227,19 @@ class Keyboard::Impl --impl->mConnected; } } -}; +#if !defined(_GAMING_XBOX) && !defined(GAMEINPUT_API_VERSION) + static HMODULE s_gameInputModule; + static GameInputCreateFn s_gameInputCreate; +#endif +}; Keyboard::Impl* Keyboard::Impl::s_keyboard = nullptr; +#if !defined(_GAMING_XBOX) && !defined(GAMEINPUT_API_VERSION) +HMODULE Keyboard::Impl::s_gameInputModule = nullptr; +GameInputCreateFn Keyboard::Impl::s_gameInputCreate = nullptr; +#endif void Keyboard::ProcessMessage(UINT, WPARAM, LPARAM) noexcept { diff --git a/Src/Mouse.cpp b/Src/Mouse.cpp index b5de5543..6f28e168 100644 --- a/Src/Mouse.cpp +++ b/Src/Mouse.cpp @@ -19,17 +19,19 @@ using Microsoft::WRL::ComPtr; #pragma region Implementations #ifdef USING_GAMEINPUT -#include +//====================================================================================== +// Win32 + GameInput implementation +//====================================================================================== #if defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 1) using namespace GameInput::v1; #elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 2) using namespace GameInput::v2; +#elif defined(GAMEINPUT_API_VERSION) && (GAMEINPUT_API_VERSION == 3) +using namespace GameInput::v3; #endif -//====================================================================================== -// Win32 + GameInput implementation -//====================================================================================== +using GameInputCreateFn = HRESULT(*)(IGameInput**); // // Call this static function from your Window Message Procedure @@ -83,7 +85,26 @@ class Mouse::Impl s_mouse = this; + #if defined(_GAMING_XBOX) || defined(GAMEINPUT_API_VERSION) HRESULT hr = GameInputCreate(mGameInput.GetAddressOf()); + #else + if (!s_gameInputCreate) + { + s_gameInputModule = LoadLibraryExW(L"GameInput.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (s_gameInputModule) + { + s_gameInputCreate = reinterpret_cast(static_cast(GetProcAddress(s_gameInputModule, "GameInputCreate"))); + } + + if (!s_gameInputCreate) + { + DebugTrace("ERROR: GetProcAddress GameInputCreate failed\n"); + throw std::runtime_error("GameInput.dll is not installed on this system"); + } + } + + HRESULT hr = s_gameInputCreate(mGameInput.GetAddressOf()); + #endif if (SUCCEEDED(hr)) { ThrowIfFailed(mGameInput->RegisterDeviceCallback( @@ -99,12 +120,11 @@ class Mouse::Impl { DebugTrace("ERROR: GameInputCreate [mouse] failed with %08X\n", static_cast(hr)); #ifdef _GAMING_XBOX - ThrowIfFailed(hr); - #elif defined(_DEBUG) + throw com_exception(hr); + #else DebugTrace( - "\t**** Check that the 'GameInput Service' is running on this system. ****\n" - "\t**** NOTE: No relative movement be returned and IsConnected will return false. ****\n" - ); + "\t**** Check that the 'GameInput Service' is running on this system. ****\n" + "\t**** NOTE: All calls to GetState will be reported as 'not connected'. ****\n"); #endif } @@ -367,12 +387,20 @@ class Mouse::Impl ClipCursor(&rect); #endif } + +#if !defined(_GAMING_XBOX) && !defined(GAMEINPUT_API_VERSION) + static HMODULE s_gameInputModule; + static GameInputCreateFn s_gameInputCreate; +#endif }; +#if !defined(_GAMING_XBOX) && !defined(GAMEINPUT_API_VERSION) +HMODULE Mouse::Impl::s_gameInputModule = nullptr; +GameInputCreateFn Mouse::Impl::s_gameInputCreate = nullptr; +#endif Mouse::Impl* Mouse::Impl::s_mouse = nullptr; - void Mouse::ProcessMessage(UINT message, WPARAM wParam, LPARAM lParam) { auto pImpl = Impl::s_mouse; From 92d127419a578e342a47193dbc1c88f6c6b99c70 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Wed, 8 Oct 2025 12:06:21 -0700 Subject: [PATCH 2/2] Code review feedback --- Src/GamePad.cpp | 2 +- Src/Keyboard.cpp | 2 +- Src/Mouse.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Src/GamePad.cpp b/Src/GamePad.cpp index 18d38fed..58ae1cde 100644 --- a/Src/GamePad.cpp +++ b/Src/GamePad.cpp @@ -152,7 +152,7 @@ class GamePad::Impl throw com_exception(hr); #else DebugTrace( - "\t**** Check that the 'GameInput Service' is running on this system. ****\n" + "\t**** Install the latest GameInputRedist package on this system. ****\n" "\t**** NOTE: All calls to GetState will be reported as 'not connected'. ****\n"); #endif } diff --git a/Src/Keyboard.cpp b/Src/Keyboard.cpp index 16091c3c..607f4633 100644 --- a/Src/Keyboard.cpp +++ b/Src/Keyboard.cpp @@ -119,7 +119,7 @@ class Keyboard::Impl throw com_exception(hr); #else DebugTrace( - "\t**** Check that the 'GameInput Service' is running on this system. ****\n" + "\t**** Install the latest GameInputRedist package on this system. ****\n" "\t**** NOTE: All calls to GetState will be reported as 'not connected'. ****\n"); #endif } diff --git a/Src/Mouse.cpp b/Src/Mouse.cpp index 6f28e168..c4735cab 100644 --- a/Src/Mouse.cpp +++ b/Src/Mouse.cpp @@ -123,7 +123,7 @@ class Mouse::Impl throw com_exception(hr); #else DebugTrace( - "\t**** Check that the 'GameInput Service' is running on this system. ****\n" + "\t**** Install the latest GameInputRedist package on this system. ****\n" "\t**** NOTE: All calls to GetState will be reported as 'not connected'. ****\n"); #endif }