refactor(host/W6.0): hoist GamepadEvent/GamepadFrame to punktfunk_core::input
apple / swift (push) Successful in 1m22s
release / apple (push) Successful in 6m6s
apple / screenshots (push) Successful in 4m58s
windows-host / package (push) Successful in 15m58s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m59s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 4m2s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m58s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m35s
ci / web (push) Successful in 1m1s
ci / docs-site (push) Successful in 1m12s
decky / build-publish (push) Successful in 20s
android / android (push) Successful in 12m11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has started running
ci / bench (push) Successful in 6m17s
arch / build-publish (push) Successful in 13m21s
docker / deploy-docs (push) Successful in 11s
flatpak / build-publish (push) Successful in 6m37s
deb / build-publish (push) Successful in 12m28s
ci / rust (push) Successful in 21m52s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 13m43s
apple / swift (push) Successful in 1m22s
release / apple (push) Successful in 6m6s
apple / screenshots (push) Successful in 4m58s
windows-host / package (push) Successful in 15m58s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m59s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 4m2s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m58s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 5m35s
ci / web (push) Successful in 1m1s
ci / docs-site (push) Successful in 1m12s
decky / build-publish (push) Successful in 20s
android / android (push) Successful in 12m11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 7s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 9s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 8s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has started running
ci / bench (push) Successful in 6m17s
arch / build-publish (push) Successful in 13m21s
docker / deploy-docs (push) Successful in 11s
flatpak / build-publish (push) Successful in 6m37s
deb / build-publish (push) Successful in 12m28s
ci / rust (push) Successful in 21m52s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 13m43s
First de-coupling for the host crate carve (plan §W6.0 / §2.4): the GameStream (Moonlight-plane) decoded controller types were defined in gamestream/gamepad.rs — the "junk drawer" — yet consumed 18× by the platform-neutral input injectors AND by the Moonlight decode path. Once inject becomes pf-inject, reaching them via crate::gamestream would be an illegal upward edge. Move the two types to core::input (below both planes; inject already depends on core) and repoint every consumer. Also consolidate the duplicated MAX_PADS onto the existing core::input::MAX_PADS. The gamestream BTN_* const aliases stay for now (separate follow-up); decode()/rumble/tests remain in the Moonlight plane, now importing the types from core. Verified: Linux (home-worker-5) clippy -p punktfunk-core -p punktfunk-host --all-targets -D warnings + gamepad tests green; Windows (192.168.1.158) clippy -p punktfunk-host --features nvenc,amf-qsv --all-targets green (the inject/windows/* consumers compile). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -320,6 +320,42 @@ impl InputEvent {
|
||||
}
|
||||
}
|
||||
|
||||
/// One decoded GameStream (Moonlight-plane) controller event. Shared vocabulary: the host's
|
||||
/// GameStream/Moonlight decode path produces these, and the platform-neutral input injectors
|
||||
/// (`pf-inject`) consume them — so the type lives in `core::input`, below both, rather than in
|
||||
/// either plane. The `buttons` bitmask uses the same [`gamepad`] `BTN_*` layout as the native
|
||||
/// [`GamepadSnapshot`] (GameStream's `buttonFlags | buttonFlags2 << 16` is bit-identical).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum GamepadEvent {
|
||||
/// Full state of one controller + the set of attached controllers.
|
||||
State(GamepadFrame),
|
||||
/// Sunshine arrival metadata (precedes the first State for that pad).
|
||||
Arrival {
|
||||
index: u8,
|
||||
/// 0 unknown, 1 xbox, 2 ps, 3 nintendo.
|
||||
kind: u8,
|
||||
/// LI_CCAP_* bits (0x02 = rumble).
|
||||
capabilities: u16,
|
||||
},
|
||||
}
|
||||
|
||||
/// Snapshot of one controller's inputs (Moonlight conventions: sticks −32768..32767 with +Y
|
||||
/// up, triggers 0..255, buttons = `buttonFlags | buttonFlags2 << 16`). The decoded-frame twin of
|
||||
/// [`GamepadSnapshot`] on the GameStream/Moonlight plane; see [`GamepadEvent`] for why it lives here.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct GamepadFrame {
|
||||
pub index: i16,
|
||||
/// Bit n set = controller n attached; a clear bit for an allocated pad means unplug.
|
||||
pub active_mask: u16,
|
||||
pub buttons: u32,
|
||||
pub left_trigger: u8,
|
||||
pub right_trigger: u8,
|
||||
pub ls_x: i16,
|
||||
pub ls_y: i16,
|
||||
pub rs_x: i16,
|
||||
pub rs_y: i16,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -220,7 +220,7 @@ pub fn deck_windows_spike(args: &[String]) -> Result<()> {
|
||||
/// removes the devnode.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn dualsense_windows_test(args: &[String]) -> Result<()> {
|
||||
use crate::gamestream::gamepad::{GamepadEvent, GamepadFrame};
|
||||
use punktfunk_core::input::{GamepadEvent, GamepadFrame};
|
||||
use std::time::{Duration, Instant};
|
||||
let secs: u64 = args
|
||||
.iter()
|
||||
|
||||
@@ -16,39 +16,10 @@ const MAGIC_MULTI_CONTROLLER: u32 = 0x0C;
|
||||
/// Sunshine extension: controller arrival metadata (type/capabilities).
|
||||
const MAGIC_CONTROLLER_ARRIVAL: u32 = 0x5500_0004;
|
||||
|
||||
/// Most controllers a session tracks (Sunshine's MAX_GAMEPADS).
|
||||
pub const MAX_PADS: usize = 16;
|
||||
|
||||
/// One decoded controller event.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum GamepadEvent {
|
||||
/// Full state of one controller + the set of attached controllers.
|
||||
State(GamepadFrame),
|
||||
/// Sunshine arrival metadata (precedes the first State for that pad).
|
||||
Arrival {
|
||||
index: u8,
|
||||
/// 0 unknown, 1 xbox, 2 ps, 3 nintendo.
|
||||
kind: u8,
|
||||
/// LI_CCAP_* bits (0x02 = rumble).
|
||||
capabilities: u16,
|
||||
},
|
||||
}
|
||||
|
||||
/// Snapshot of one controller's inputs (Moonlight conventions: sticks −32768..32767 with +Y
|
||||
/// up, triggers 0..255, buttons = `buttonFlags | buttonFlags2 << 16`).
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct GamepadFrame {
|
||||
pub index: i16,
|
||||
/// Bit n set = controller n attached; a clear bit for an allocated pad means unplug.
|
||||
pub active_mask: u16,
|
||||
pub buttons: u32,
|
||||
pub left_trigger: u8,
|
||||
pub right_trigger: u8,
|
||||
pub ls_x: i16,
|
||||
pub ls_y: i16,
|
||||
pub rs_x: i16,
|
||||
pub rs_y: i16,
|
||||
}
|
||||
// The decoded controller types ([`GamepadEvent`]/[`GamepadFrame`]) and the pad count
|
||||
// ([`punktfunk_core::input::MAX_PADS`]) are shared vocabulary between this Moonlight decode path and
|
||||
// the platform-neutral injectors, so they live in `core::input` (below both) rather than here.
|
||||
use punktfunk_core::input::{GamepadEvent, GamepadFrame};
|
||||
|
||||
// GameStream's `buttonFlags | buttonFlags2 << 16` layout (Limelight.h) is bit-identical to
|
||||
// punktfunk's native gamepad wire, so source these from the single point of truth in `punktfunk_core`
|
||||
|
||||
@@ -321,7 +321,7 @@ pub mod gamepad {
|
||||
pub fn new() -> Self {
|
||||
GamepadManager
|
||||
}
|
||||
pub fn handle(&mut self, _ev: &crate::gamestream::gamepad::GamepadEvent) {}
|
||||
pub fn handle(&mut self, _ev: &punktfunk_core::input::GamepadEvent) {}
|
||||
pub fn pump_rumble(&mut self, _send: impl FnMut(u16, u16, u16)) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ impl PadProto for DsLinuxProto {
|
||||
|
||||
/// Merge buttons/sticks/triggers from the frame, preserving touch + motion + pad clicks (those
|
||||
/// come on the rich-input plane and must survive a button-only frame).
|
||||
fn merge_frame(&self, prev: &DsState, f: &crate::gamestream::gamepad::GamepadFrame) -> DsState {
|
||||
fn merge_frame(&self, prev: &DsState, f: &punktfunk_core::input::GamepadFrame) -> DsState {
|
||||
// Steam back grips have no DualSense slot — fold them onto standard buttons per the
|
||||
// configured policy (default drop) so they aren't silently lost.
|
||||
let buttons = crate::inject::steam_remap::fold_paddles(f.buttons, self.remap.paddles);
|
||||
@@ -355,7 +355,7 @@ impl PadProto for DsEdgeLinuxProto {
|
||||
/// Merge buttons/sticks/triggers from the frame, preserving the rich-plane fields — like the
|
||||
/// plain DualSense, EXCEPT the wire paddles are not folded away: they land on the Edge's own
|
||||
/// `buttons[2]` bits (rebuilt from every button frame, so no extra persistence).
|
||||
fn merge_frame(&self, prev: &DsState, f: &crate::gamestream::gamepad::GamepadFrame) -> DsState {
|
||||
fn merge_frame(&self, prev: &DsState, f: &punktfunk_core::input::GamepadFrame) -> DsState {
|
||||
let mut s = DsState::from_gamepad(
|
||||
f.buttons,
|
||||
f.ls_x,
|
||||
|
||||
@@ -335,7 +335,7 @@ impl PadProto for Ds4LinuxProto {
|
||||
|
||||
/// Merge buttons/sticks/triggers from the frame, preserving touch + motion + pad clicks (those
|
||||
/// arrive on the rich-input plane and must survive a button-only frame).
|
||||
fn merge_frame(&self, prev: &DsState, f: &crate::gamestream::gamepad::GamepadFrame) -> DsState {
|
||||
fn merge_frame(&self, prev: &DsState, f: &punktfunk_core::input::GamepadFrame) -> DsState {
|
||||
// Steam back grips have no DS4 slot — fold them onto standard buttons per the configured
|
||||
// policy (default drop) so they aren't silently lost.
|
||||
let buttons = crate::inject::steam_remap::fold_paddles(f.buttons, self.remap.paddles);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! 360 pad", `045e:028e`) so SDL/Steam/Proton match their built-in mapping with zero
|
||||
//! configuration — exactly what Sunshine emulates. One [`VirtualPad`] per attached client
|
||||
//! controller, managed by [`GamepadManager`] from decoded
|
||||
//! [`GamepadFrame`](crate::gamestream::gamepad::GamepadFrame)s.
|
||||
//! [`GamepadFrame`](punktfunk_core::input::GamepadFrame)s.
|
||||
//!
|
||||
//! Rumble flows the *other* way on the same fd: games upload force-feedback effects
|
||||
//! (`EV_UINPUT`/`UI_FF_UPLOAD` → `UI_BEGIN/END_FF_UPLOAD` ioctls) and trigger them with
|
||||
@@ -18,9 +18,10 @@
|
||||
// Every `unsafe` block in this file carries a `// SAFETY:` proof; enforce it (unsafe-proof program).
|
||||
#![deny(clippy::undocumented_unsafe_blocks)]
|
||||
|
||||
use crate::gamestream::gamepad::{self, GamepadFrame, MAX_PADS};
|
||||
use crate::gamestream::gamepad;
|
||||
use crate::inject::pad_slots::PadSlots;
|
||||
use anyhow::{bail, Result};
|
||||
use punktfunk_core::input::{GamepadFrame, MAX_PADS};
|
||||
use std::collections::HashMap;
|
||||
use std::os::fd::{AsRawFd, OwnedFd};
|
||||
use std::time::Instant;
|
||||
@@ -582,8 +583,8 @@ impl GamepadManager {
|
||||
}
|
||||
|
||||
/// Handle one decoded controller event (create/destroy by mask, then apply state).
|
||||
pub fn handle(&mut self, ev: &crate::gamestream::gamepad::GamepadEvent) {
|
||||
use crate::gamestream::gamepad::GamepadEvent;
|
||||
pub fn handle(&mut self, ev: &punktfunk_core::input::GamepadEvent) {
|
||||
use punktfunk_core::input::GamepadEvent;
|
||||
match ev {
|
||||
GamepadEvent::Arrival { index, kind, .. } => {
|
||||
tracing::info!(index, kind, "controller arrival ({})", self.slots.label());
|
||||
|
||||
@@ -402,7 +402,7 @@ impl PadProto for SteamProto {
|
||||
fn merge_frame(
|
||||
&self,
|
||||
prev: &SteamState,
|
||||
f: &crate::gamestream::gamepad::GamepadFrame,
|
||||
f: &punktfunk_core::input::GamepadFrame,
|
||||
) -> SteamState {
|
||||
let mut s = SteamState::from_gamepad(
|
||||
f.buttons,
|
||||
@@ -511,7 +511,7 @@ impl PadProto for ScProto {
|
||||
fn merge_frame(
|
||||
&self,
|
||||
prev: &SteamState,
|
||||
f: &crate::gamestream::gamepad::GamepadFrame,
|
||||
f: &punktfunk_core::input::GamepadFrame,
|
||||
) -> SteamState {
|
||||
use punktfunk_core::input::gamepad as gs;
|
||||
let native = f.buttons & (gs::BTN_PADDLE1 | gs::BTN_PADDLE2);
|
||||
|
||||
@@ -329,7 +329,7 @@ impl PadProto for TritonProto {
|
||||
fn merge_frame(
|
||||
&self,
|
||||
prev: &TritonState,
|
||||
f: &crate::gamestream::gamepad::GamepadFrame,
|
||||
f: &punktfunk_core::input::GamepadFrame,
|
||||
) -> TritonState {
|
||||
let mut s = TritonState::from_gamepad(
|
||||
f.buttons,
|
||||
|
||||
@@ -277,7 +277,7 @@ impl PadProto for SwitchProProto {
|
||||
fn merge_frame(
|
||||
&self,
|
||||
prev: &SwitchState,
|
||||
f: &crate::gamestream::gamepad::GamepadFrame,
|
||||
f: &punktfunk_core::input::GamepadFrame,
|
||||
) -> SwitchState {
|
||||
let buttons = crate::inject::steam_remap::fold_paddles(f.buttons, self.remap.paddles);
|
||||
let mut s = SwitchState::from_gamepad(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Shared virtual-pad slot table + creation lifecycle, used by every backend manager (Linux
|
||||
//! uinput/uhid, Windows XUSB/UMDF). See [`PadSlots`].
|
||||
|
||||
use crate::gamestream::gamepad::MAX_PADS;
|
||||
use crate::inject::pad_gate::PadGate;
|
||||
use anyhow::Result;
|
||||
use punktfunk_core::input::MAX_PADS;
|
||||
use std::time::Instant;
|
||||
|
||||
// The unplug sweep walks a u16 `active_mask` (the wire type); every slot must have a bit.
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
//! Windows XUSB) write frames straight through with no state vec / heartbeat / rich plane, so they
|
||||
//! use [`PadSlots`] directly instead.
|
||||
|
||||
use crate::gamestream::gamepad::{GamepadEvent, GamepadFrame, MAX_PADS};
|
||||
use crate::inject::hidout_dedup::HidoutDedup;
|
||||
use crate::inject::pad_slots::PadSlots;
|
||||
use anyhow::Result;
|
||||
use punktfunk_core::input::{GamepadEvent, GamepadFrame, MAX_PADS};
|
||||
use punktfunk_core::quic::{HidOutput, RichInput};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ impl PadProto for DsEdgeWinProto {
|
||||
/// Merge buttons/sticks/triggers from the frame, preserving the rich-plane fields — like the
|
||||
/// plain DualSense, EXCEPT the wire paddles land on the Edge's own `buttons[2]` bits
|
||||
/// (rebuilt from every button frame, so no extra persistence).
|
||||
fn merge_frame(&self, prev: &DsState, f: &crate::gamestream::gamepad::GamepadFrame) -> DsState {
|
||||
fn merge_frame(&self, prev: &DsState, f: &punktfunk_core::input::GamepadFrame) -> DsState {
|
||||
let mut s = DsState::from_gamepad(
|
||||
f.buttons,
|
||||
f.ls_x,
|
||||
|
||||
@@ -438,7 +438,7 @@ impl PadProto for DsWinProto {
|
||||
|
||||
/// Merge buttons/sticks/triggers from the frame, preserving touch + motion + pad clicks (rich-
|
||||
/// plane fields that must survive a button-only frame) — exactly as `linux/dualsense.rs` does.
|
||||
fn merge_frame(&self, prev: &DsState, f: &crate::gamestream::gamepad::GamepadFrame) -> DsState {
|
||||
fn merge_frame(&self, prev: &DsState, f: &punktfunk_core::input::GamepadFrame) -> DsState {
|
||||
// Steam back grips have no DualSense slot — fold them onto standard buttons per the
|
||||
// configured policy (default drop) so they aren't silently lost.
|
||||
let buttons = crate::inject::steam_remap::fold_paddles(f.buttons, self.remap.paddles);
|
||||
|
||||
@@ -187,7 +187,7 @@ impl PadProto for Ds4WinProto {
|
||||
|
||||
/// Merge buttons/sticks/triggers from the frame, preserving touch + motion + pad clicks (rich-
|
||||
/// plane fields that must survive a button-only frame) — exactly as `linux/dualshock4.rs` does.
|
||||
fn merge_frame(&self, prev: &DsState, f: &crate::gamestream::gamepad::GamepadFrame) -> DsState {
|
||||
fn merge_frame(&self, prev: &DsState, f: &punktfunk_core::input::GamepadFrame) -> DsState {
|
||||
// Steam back grips have no DS4 slot — fold them onto standard buttons per the configured
|
||||
// policy (default drop) so they aren't silently lost.
|
||||
let buttons = crate::inject::steam_remap::fold_paddles(f.buttons, self.remap.paddles);
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
//! level changes to the client (the universal 0xCA plane), mirroring the Linux `EV_FF` read path.
|
||||
|
||||
use super::gamepad_raii::{sw_create_cb, PadChannel, SwCreateCtx};
|
||||
use crate::gamestream::gamepad::{GamepadEvent, MAX_PADS};
|
||||
use crate::inject::pad_slots::PadSlots;
|
||||
use anyhow::{anyhow, Result};
|
||||
use punktfunk_core::input::{GamepadEvent, MAX_PADS};
|
||||
use std::ffi::c_void;
|
||||
use std::sync::atomic::{fence, AtomicU32, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@@ -179,7 +179,7 @@ impl PadProto for DeckWinProto {
|
||||
fn merge_frame(
|
||||
&self,
|
||||
prev: &SteamState,
|
||||
f: &crate::gamestream::gamepad::GamepadFrame,
|
||||
f: &punktfunk_core::input::GamepadFrame,
|
||||
) -> SteamState {
|
||||
use super::steam_proto::btn;
|
||||
let mut s = SteamState::from_gamepad(
|
||||
|
||||
@@ -56,8 +56,8 @@ impl PadState {
|
||||
self.rs_y = s.rs_y;
|
||||
}
|
||||
|
||||
fn frame(&self, index: usize, active_mask: u16) -> crate::gamestream::gamepad::GamepadFrame {
|
||||
crate::gamestream::gamepad::GamepadFrame {
|
||||
fn frame(&self, index: usize, active_mask: u16) -> punktfunk_core::input::GamepadFrame {
|
||||
punktfunk_core::input::GamepadFrame {
|
||||
index: index as i16,
|
||||
active_mask,
|
||||
buttons: self.buttons,
|
||||
@@ -192,8 +192,8 @@ impl Pads {
|
||||
self.kinds[idx] = resolved;
|
||||
}
|
||||
|
||||
fn handle(&mut self, ev: &crate::gamestream::gamepad::GamepadEvent) {
|
||||
use crate::gamestream::gamepad::GamepadEvent;
|
||||
fn handle(&mut self, ev: &punktfunk_core::input::GamepadEvent) {
|
||||
use punktfunk_core::input::GamepadEvent;
|
||||
// Present = a create/update frame (the pad's mask bit is set); a cleared bit is the
|
||||
// removal frame emitted by the native detach path (`GamepadRemove`).
|
||||
let (idx, present) = match ev {
|
||||
@@ -212,7 +212,7 @@ impl Pads {
|
||||
}
|
||||
|
||||
/// Dispatch a decoded event to the manager for `kind`, creating it lazily.
|
||||
fn route_handle(&mut self, kind: GamepadPref, ev: &crate::gamestream::gamepad::GamepadEvent) {
|
||||
fn route_handle(&mut self, kind: GamepadPref, ev: &punktfunk_core::input::GamepadEvent) {
|
||||
match kind {
|
||||
#[cfg(target_os = "linux")]
|
||||
GamepadPref::DualSense => self
|
||||
@@ -682,7 +682,7 @@ pub(super) fn input_thread(
|
||||
if idx < MAX_WIRE_PADS && pad_state[idx].apply(&ev) {
|
||||
pad_mask |= 1 << idx;
|
||||
let frame = pad_state[idx].frame(idx, pad_mask);
|
||||
pads.handle(&crate::gamestream::gamepad::GamepadEvent::State(frame));
|
||||
pads.handle(&punktfunk_core::input::GamepadEvent::State(frame));
|
||||
}
|
||||
}
|
||||
InputKind::GamepadState => {
|
||||
@@ -704,9 +704,7 @@ pub(super) fn input_thread(
|
||||
if first || pad_state[idx] != before {
|
||||
pad_mask |= 1 << idx;
|
||||
let frame = pad_state[idx].frame(idx, pad_mask);
|
||||
pads.handle(&crate::gamestream::gamepad::GamepadEvent::State(
|
||||
frame,
|
||||
));
|
||||
pads.handle(&punktfunk_core::input::GamepadEvent::State(frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -729,7 +727,7 @@ pub(super) fn input_thread(
|
||||
pad_mask &= !(1 << idx);
|
||||
pad_state[idx] = PadState::default();
|
||||
let frame = pad_state[idx].frame(idx, pad_mask);
|
||||
pads.handle(&crate::gamestream::gamepad::GamepadEvent::State(frame));
|
||||
pads.handle(&punktfunk_core::input::GamepadEvent::State(frame));
|
||||
tracing::info!(pad = idx, "gamepad unplugged (native detach)");
|
||||
}
|
||||
// Fresh feedback bookkeeping so a later re-plug on this index inherits no
|
||||
|
||||
Reference in New Issue
Block a user