#include "input/xinput_source.hpp" #include #include namespace coop { void XInputSource::poll() { for (DWORD i = 0; i < kMaxPads; ++i) { XINPUT_STATE state = {}; const DWORD result = XInputGetState(i, &state); PadInfo& info = pads_[i]; if (result == ERROR_SUCCESS) { info.connected = true; info.source = "XInput #" + std::to_string(i); // XINPUT_GAMEPAD is laid out identically to the tail of CoopPadState, // so copy field by field to keep the mapping explicit and safe. const XINPUT_GAMEPAD& g = state.Gamepad; info.state.connected = 1; info.state.packet = state.dwPacketNumber; info.state.buttons = g.wButtons; info.state.left_trigger = g.bLeftTrigger; info.state.right_trigger = g.bRightTrigger; info.state.thumb_lx = g.sThumbLX; info.state.thumb_ly = g.sThumbLY; info.state.thumb_rx = g.sThumbRX; info.state.thumb_ry = g.sThumbRY; } else { info = PadInfo{}; } } } void XInputSource::set_rumble(int slot, std::uint16_t left, std::uint16_t right) { if (slot < 0 || slot >= static_cast(kMaxPads)) { return; } XINPUT_VIBRATION v{left, right}; // Best-effort: if the device just disconnected this returns ERROR_DEVICE_NOT_CONNECTED, but rumble // is fire-and-forget (the next connected-pad refresh re-syncs state), so the result isn't acted on. (void)XInputSetState(static_cast(slot), &v); } } // namespace coop