debug(gamestream): surface the pointer plane's silent failure modes
An on-glass 'touch does nothing' currently leaves NO trace: log the first SS_TOUCH per session at info (proves the client sends + we decode), and warn when a packet carrying a pointer magic fails the body parse (layout mismatch) instead of vanishing into the unknown-magic drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -289,6 +289,14 @@ fn on_receive(
|
|||||||
let _ = inj_tx.send(ev);
|
let _ = inj_tx.send(ev);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
} else if super::input::is_pointer_magic(&pt) {
|
||||||
|
// A pointer magic that failed the body parse — a layout mismatch against this
|
||||||
|
// client, exactly what an on-glass "touch/pen does nothing" needs surfaced.
|
||||||
|
tracing::warn!(
|
||||||
|
len = pt.len(),
|
||||||
|
"gamestream: SS_TOUCH/SS_PEN packet failed to decode (malformed/unexpected layout)"
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let events = super::input::decode(&pt);
|
let events = super::input::decode(&pt);
|
||||||
|
|||||||
@@ -150,6 +150,18 @@ pub enum SsPointer {
|
|||||||
Touch(SsTouch),
|
Touch(SsTouch),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this control plaintext carries a pointer magic ([`decode_pointer`]'s domain) —
|
||||||
|
/// lets the caller tell "malformed pointer packet" (worth a warn) apart from "some other
|
||||||
|
/// message" when `decode_pointer` returns `None`.
|
||||||
|
pub fn is_pointer_magic(plaintext: &[u8]) -> bool {
|
||||||
|
plaintext.len() >= 12
|
||||||
|
&& u16::from_le_bytes([plaintext[0], plaintext[1]]) == INPUT_DATA_TYPE
|
||||||
|
&& matches!(
|
||||||
|
u32::from_le_bytes([plaintext[8], plaintext[9], plaintext[10], plaintext[11]]),
|
||||||
|
MAGIC_SS_TOUCH | MAGIC_SS_PEN
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Decode a control plaintext into a pen/touch pointer event, or `None` for every other
|
/// Decode a control plaintext into a pen/touch pointer event, or `None` for every other
|
||||||
/// message (the caller then falls through to [`decode`]). Bounds- and sanity-checked like the
|
/// message (the caller then falls through to [`decode`]). Bounds- and sanity-checked like the
|
||||||
/// rest of the plane: short bodies and non-finite floats (a forged NaN must never reach the
|
/// rest of the plane: short bodies and non-finite floats (a forged NaN must never reach the
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ pub struct GsPointer {
|
|||||||
saw_hover: bool,
|
saw_hover: bool,
|
||||||
/// Active forwarded touch ids, for `CANCEL_ALL` replay as per-id ups.
|
/// Active forwarded touch ids, for `CANCEL_ALL` replay as per-id ups.
|
||||||
touch_ids: Vec<u32>,
|
touch_ids: Vec<u32>,
|
||||||
|
/// Whether this session's first SS_TOUCH was logged (the one observable breadcrumb an
|
||||||
|
/// on-glass "touch does nothing" report needs — every later stage logs its own failure).
|
||||||
|
touch_seen: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GsPointer {
|
impl GsPointer {
|
||||||
@@ -80,6 +83,7 @@ impl GsPointer {
|
|||||||
last: PenSample::default(),
|
last: PenSample::default(),
|
||||||
saw_hover: false,
|
saw_hover: false,
|
||||||
touch_ids: Vec::new(),
|
touch_ids: Vec::new(),
|
||||||
|
touch_seen: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +203,13 @@ impl GsPointer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn apply_touch(&mut self, t: &SsTouch, mut sink: impl FnMut(InputEvent)) {
|
fn apply_touch(&mut self, t: &SsTouch, mut sink: impl FnMut(InputEvent)) {
|
||||||
|
if !self.touch_seen {
|
||||||
|
self.touch_seen = true;
|
||||||
|
tracing::info!(
|
||||||
|
event_type = t.event_type,
|
||||||
|
"gamestream: touch plane active (first SS_TOUCH from this client)"
|
||||||
|
);
|
||||||
|
}
|
||||||
let ev = |kind: InputKind, id: u32, x: f32, y: f32| InputEvent {
|
let ev = |kind: InputKind, id: u32, x: f32, y: f32| InputEvent {
|
||||||
kind,
|
kind,
|
||||||
_pad: [0; 3],
|
_pad: [0; 3],
|
||||||
|
|||||||
Reference in New Issue
Block a user