Gamepad navigation mapping
| 297 | |
| 298 | // Gamepad navigation mapping |
| 299 | static void ImGui_ImplWin32_UpdateGamepads() |
| 300 | { |
| 301 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD |
| 302 | ImGuiIO& io = ImGui::GetIO(); |
| 303 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); |
| 304 | //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. |
| 305 | // return; |
| 306 | |
| 307 | // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. |
| 308 | // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. |
| 309 | if (bd->WantUpdateHasGamepad) |
| 310 | { |
| 311 | XINPUT_CAPABILITIES caps = {}; |
| 312 | bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false; |
| 313 | bd->WantUpdateHasGamepad = false; |
| 314 | } |
| 315 | |
| 316 | io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; |
| 317 | XINPUT_STATE xinput_state; |
| 318 | XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; |
| 319 | if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS) |
| 320 | return; |
| 321 | io.BackendFlags |= ImGuiBackendFlags_HasGamepad; |
| 322 | |
| 323 | #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) |
| 324 | #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); } |
| 325 | #define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); } |
| 326 | MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START); |
| 327 | MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK); |
| 328 | MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X); |
| 329 | MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B); |
| 330 | MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y); |
| 331 | MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A); |
| 332 | MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); |
| 333 | MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); |
| 334 | MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP); |
| 335 | MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN); |
| 336 | MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER); |
| 337 | MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER); |
| 338 | MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255); |
| 339 | MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255); |
| 340 | MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB); |
| 341 | MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB); |
| 342 | MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); |
| 343 | MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); |
| 344 | MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); |
| 345 | MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); |
| 346 | MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); |
| 347 | MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); |
| 348 | MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); |
| 349 | MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); |
| 350 | #undef MAP_BUTTON |
| 351 | #undef MAP_ANALOG |
| 352 | #endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD |
| 353 | } |
| 354 | |
| 355 | void ImGui_ImplWin32_NewFrame() |
| 356 | { |
no test coverage detected