- injector bitness gate: IsWow64Process2 failure was treated as "native", which would send the x64 DLL into a 32-bit target. Fall back to the legacy IsWow64Process before giving up to permissive. - injector helper exit: GetExitCodeProcess's BOOL was ignored; on a failed query surface GetLastError instead of a misleading exit code. - window_capture: CreateShaderResourceView's HRESULT was ignored, and width_/ height_ were committed even on failure, so the (latest_ == nullptr) recreate guard never retried -- a silently black mirror until the next resize. Only commit the dims on success; otherwise drop latest_ so the next frame retries. - xinput rumble: make the best-effort XInputSetState ignore explicit (a disconnected pad re-syncs on the next refresh; the result isn't actionable). The GetClientRect/ClientToScreen reads in mkb_forward are left as-is: a failure there is a single self-correcting frame (the mapping is rejected and reused next frame), so checking them adds no actionable behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
55 lines
1.4 KiB
C++
55 lines
1.4 KiB
C++
#include "input/xinput_source.hpp"
|
|
|
|
#include <windows.h>
|
|
#include <xinput.h>
|
|
|
|
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<int>(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<DWORD>(slot), &v);
|
|
}
|
|
|
|
} // namespace coop
|