fix(scroll): keep default scroll on window.scrollBy; wheel only for --at/--frame (#36)

The centered-wheel default no-op'd on some pages (headless e2e_hover_scroll_press
regressed). Restore window.scrollBy for plain page scroll; the coordinate wheel
stays opt-in via --at/--frame for cross-origin iframe content.
This commit is contained in:
leeguooooo
2026-06-17 02:01:23 +09:00
parent 32e203b908
commit 0296bc7a88
+33 -20
View File
@@ -3499,27 +3499,40 @@ async fn handle_scroll(cmd: &Value, state: &mut DaemonState) -> Result<Value, St
return Ok(json!({ "scrolled": true, "via": "selector" })); return Ok(json!({ "scrolled": true, "via": "selector" }));
} }
// No selector: dispatch a real (isTrusted) wheel at a viewport coordinate. // `--at x,y` / `--frame n`: dispatch a real (isTrusted) wheel at a viewport
// This hits the compositor and scrolls whatever scroll container is under the // coordinate. This hits the compositor and scrolls whatever scroll container
// pointer — including cross-origin iframes that `window.scrollBy` on the top // is under the pointer — including cross-origin iframes that `window.scrollBy`
// document silently no-ops on (issue #36). The coordinate is, in priority: // on the top document silently no-ops on (issue #36).
// --at x,y → that exact pixel if cmd.get("at").is_some() || cmd.get("frame").is_some() {
// --frame n → the center of frame n from `chrome-use frames` let (x, y, via) = if let Some(at) = cmd.get("at").and_then(|v| v.as_array()) {
// default → the viewport center let x = at.first().and_then(|v| v.as_f64()).unwrap_or(0.0);
let (x, y, via) = if let Some(at) = cmd.get("at").and_then(|v| v.as_array()) { let y = at.get(1).and_then(|v| v.as_f64()).unwrap_or(0.0);
let x = at.first().and_then(|v| v.as_f64()).unwrap_or(0.0); (x, y, "at")
let y = at.get(1).and_then(|v| v.as_f64()).unwrap_or(0.0); } else {
(x, y, "at") let n = cmd.get("frame").and_then(|v| v.as_u64()).unwrap_or(0);
} else if let Some(n) = cmd.get("frame").and_then(|v| v.as_u64()) { let (x, y) = frame_center(mgr, &session_id, &state.iframe_sessions, n as usize).await?;
let (x, y) = frame_center(mgr, &session_id, &state.iframe_sessions, n as usize).await?; (x, y, "frame")
(x, y, "frame") };
} else { dispatch_wheel(&mgr.client, &session_id, x, y, dx, dy).await?;
let (x, y) = viewport_center(mgr, &session_id).await?; return Ok(json!({ "scrolled": true, "via": via, "at": [x, y] }));
(x, y, "center") }
};
dispatch_wheel(&mgr.client, &session_id, x, y, dx, dy).await?; // Default (no selector/at/frame): scroll the page with `window.scrollBy`. This
Ok(json!({ "scrolled": true, "via": via, "at": [x, y] })) // is the reliable path for ordinary page scrolling; a coordinate wheel at the
// viewport centre is NOT a dependable substitute (it no-ops on some pages,
// e.g. headless), so the wheel stays opt-in via `--at`/`--frame` for the
// cross-origin-iframe case (issue #36).
interaction::scroll(
&mgr.client,
&session_id,
&state.ref_map,
None,
dx,
dy,
&state.iframe_sessions,
)
.await?;
Ok(json!({ "scrolled": true, "via": "page" }))
} }
/// Viewport center in CSS pixels, used as the default wheel landing point for /// Viewport center in CSS pixels, used as the default wheel landing point for