fix(inject/host/windows): eager-create the XUSB pad on Arrival + refresh last_active (G10)
The XUSB manager's `handle` dropped `GamepadEvent::Arrival` via a `let else`, so the GameStream path never created the pad until the first `State` and missed the first XInput poll. Match on the event and `ensure` eagerly on Arrival, mirroring the DualSense backend. Also refresh `last_active` on create and unplug so a freshly-created pad's residual-rumble idle clock starts fresh rather than inheriting a stale Instant (which could force off a legitimate rumble at once). Verified: Windows .173 `cargo clippy -p punktfunk-host --all-targets -- -D warnings` (green). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -282,6 +282,7 @@ impl GamepadManager {
|
|||||||
);
|
);
|
||||||
self.pads[idx] = Some(p);
|
self.pads[idx] = Some(p);
|
||||||
self.last_rumble[idx] = (0, 0);
|
self.last_rumble[idx] = (0, 0);
|
||||||
|
self.last_active[idx] = Instant::now();
|
||||||
self.gate.on_success();
|
self.gate.on_success();
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -292,35 +293,41 @@ impl GamepadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(&mut self, ev: &GamepadEvent) {
|
pub fn handle(&mut self, ev: &GamepadEvent) {
|
||||||
let GamepadEvent::State(f) = ev else {
|
match ev {
|
||||||
return; // Arrival metadata — the pad is created lazily on the first State
|
GamepadEvent::Arrival { index, kind, .. } => {
|
||||||
};
|
tracing::info!(index, kind, "controller arrival (Xbox 360/Windows)");
|
||||||
let idx = f.index.max(0) as usize;
|
self.ensure(*index as usize);
|
||||||
if idx >= MAX_PADS {
|
}
|
||||||
return;
|
GamepadEvent::State(f) => {
|
||||||
}
|
let idx = f.index.max(0) as usize;
|
||||||
// Unplugs: drop any allocated pad whose mask bit cleared.
|
if idx >= MAX_PADS {
|
||||||
for (i, slot) in self.pads.iter_mut().enumerate() {
|
return;
|
||||||
if slot.is_some() && f.active_mask & (1 << i) == 0 {
|
}
|
||||||
tracing::info!(index = i, "controller unplugged (Xbox 360/Windows)");
|
// Unplugs: drop any allocated pad whose mask bit cleared.
|
||||||
*slot = None;
|
for (i, slot) in self.pads.iter_mut().enumerate() {
|
||||||
self.last_rumble[i] = (0, 0);
|
if slot.is_some() && f.active_mask & (1 << i) == 0 {
|
||||||
|
tracing::info!(index = i, "controller unplugged (Xbox 360/Windows)");
|
||||||
|
*slot = None;
|
||||||
|
self.last_rumble[i] = (0, 0);
|
||||||
|
self.last_active[i] = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f.active_mask & (1 << idx) == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.ensure(idx);
|
||||||
|
if let Some(pad) = self.pads[idx].as_mut() {
|
||||||
|
pad.write_state(
|
||||||
|
(f.buttons & 0xffff) as u16,
|
||||||
|
f.left_trigger,
|
||||||
|
f.right_trigger,
|
||||||
|
f.ls_x,
|
||||||
|
f.ls_y,
|
||||||
|
f.rs_x,
|
||||||
|
f.rs_y,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if f.active_mask & (1 << idx) == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.ensure(idx);
|
|
||||||
if let Some(pad) = self.pads[idx].as_mut() {
|
|
||||||
pad.write_state(
|
|
||||||
(f.buttons & 0xffff) as u16,
|
|
||||||
f.left_trigger,
|
|
||||||
f.right_trigger,
|
|
||||||
f.ls_x,
|
|
||||||
f.ls_y,
|
|
||||||
f.rs_x,
|
|
||||||
f.rs_y,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user