-
-
Notifications
You must be signed in to change notification settings - Fork 11.2k
Closed
Description
Version/Branch of Dear ImGui:
Version: any
Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_win32.cpp
Compiler: VS2019
Operating System: any
My Issue/Question:
My application designed to run on multiple Windows versions and load XInput library dynamically. So disable links to XInput library via macros will cause link error.
I rewrite the implement of Win32 XInput on my project. #3646
Screenshots/Video
none
Standalone, minimal, complete and verifiable example: (see #2261)
global datas:
static HMODULE g_hXInputDLL = NULL;
static DWORD (__stdcall *g_fXInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*) = NULL;
static DWORD (__stdcall *g_fXInputGetState)(DWORD, XINPUT_STATE*) = NULL;
static XINPUT_STATE g_tXInputState;
init:
ZeroMemory(&g_tXInputState, sizeof(XINPUT_STATE)); // clean it first
const wchar_t* xinput_dll_name[] = {
L"xinput1_4.dll", // Windows 8+
L"xinput1_3.dll", // DirectX SDK, Windows XP...
L"xinput9_1_0.dll", // Windows Vista, 7...
};
typedef DWORD (__stdcall *f_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
typedef DWORD (__stdcall *f_XInputGetState)(DWORD, XINPUT_STATE*);
for (size_t idx = 0; idx < 3; idx += 1)
{
HMODULE dll = LoadLibraryW(xinput_dll_name[idx]);
if (dll != NULL)
{
g_hXInputDLL = dll;
g_fXInputGetCapabilities = (f_XInputGetCapabilities)GetProcAddress(dll, "XInputGetCapabilities");
g_fXInputGetState = (f_XInputGetState)GetProcAddress(dll, "XInputGetState");
break;
}
}
shutdown:
g_fXInputGetCapabilities = NULL;
g_fXInputGetState = NULL;
if (g_hXInputDLL)
FreeLibrary(g_hXInputDLL);
g_hXInputDLL = NULL;
ZeroMemory(&g_tXInputState, sizeof(XINPUT_STATE));
update:
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
if (g_WantUpdateHasGamepad)
{
g_WantUpdateHasGamepad = false;
XINPUT_CAPABILITIES caps;
if (g_fXInputGetCapabilities)
g_HasGamepad = (g_fXInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
else
g_HasGamepad = false;
if (!g_HasGamepad)
ZeroMemory(&g_tXInputState, sizeof(XINPUT_STATE)); // clear if no gamepad
}
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
if (g_HasGamepad && g_fXInputGetState)
{
if (g_fXInputGetState(0, &g_tXInputState) == ERROR_SUCCESS)
{
const XINPUT_GAMEPAD& gamepad = g_tXInputState.Gamepad;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0);\
if (vn > 1.0f) vn = 1.0f;\
if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
#undef MAP_BUTTON
#undef MAP_ANALOG
}
}