diff --git a/crates/ely_app/src/shell/web_surface.rs b/crates/ely_app/src/shell/web_surface.rs index c3359e5..31018bc 100644 --- a/crates/ely_app/src/shell/web_surface.rs +++ b/crates/ely_app/src/shell/web_surface.rs @@ -137,9 +137,13 @@ impl WebSurfaceStore { .entry(tab_id.clone()) .and_modify(|current| *current = current.combined_with(delta)) .or_insert(delta); + // Drop any buffered click — its viewport coordinates were + // captured against the pre-scroll page, so applying it after + // the scroll would land on the wrong DOM element. Keep + // `keyboard_focus` and `typed_texts` though: Servo maintains + // its own DOM focus across scrolls, so a focused input keeps + // accepting the user's keystrokes after they wheel-scroll. self.click_points.remove(tab_id); - self.typed_texts.remove(tab_id); - self.keyboard_focus = None; true } diff --git a/crates/ely_app/src/shell/web_surface_controller.rs b/crates/ely_app/src/shell/web_surface_controller.rs index 9ad38ae..3fe1c8e 100644 --- a/crates/ely_app/src/shell/web_surface_controller.rs +++ b/crates/ely_app/src/shell/web_surface_controller.rs @@ -96,6 +96,14 @@ impl ElyShell { } } + /// Hand focus to the shell's root focus handle so subsequent + /// keystrokes route to the web surface. Called on the very first + /// mouse-down inside an external page so the user can start + /// typing without waiting for the click to fully resolve. + pub(super) fn focus_web_surface(&self, window: &mut gpui::Window) { + self.focus_handle.focus(window); + } + pub(super) fn type_text_in_external_web_viewport( &mut self, tab_id: TabId, diff --git a/crates/ely_app/src/shell/web_surface_view.rs b/crates/ely_app/src/shell/web_surface_view.rs index a1e30f5..dd7f09d 100644 --- a/crates/ely_app/src/shell/web_surface_view.rs +++ b/crates/ely_app/src/shell/web_surface_view.rs @@ -90,6 +90,7 @@ fn render_input_overlay( url: String, state_entity: Entity, ) -> impl IntoElement { + let down_entity = state_entity.clone(); let click_tab_id = tab_id.clone(); let click_url = url.clone(); let click_entity = state_entity.clone(); @@ -103,6 +104,16 @@ fn render_input_overlay( .absolute() .size_full() .occlude() + // Mouse-down hands focus to the shell's root focus handle so + // subsequent keystrokes route to the web surface instead of + // the omnibar Input. Doing this on mouse-down (not mouse-up) + // lets the user start typing as soon as they press, matching + // native browser focus semantics. + .on_mouse_down(MouseButton::Left, move |_event, window, cx| { + down_entity.update(cx, |shell, _cx| { + shell.focus_web_surface(window); + }); + }) .capture_any_mouse_up(move |event, window, cx| { if event.button != MouseButton::Left { return; diff --git a/crates/ely_servo_host/src/bin/ely_servo_sidecar/live.rs b/crates/ely_servo_host/src/bin/ely_servo_sidecar/live.rs index a780281..1b15d18 100644 --- a/crates/ely_servo_host/src/bin/ely_servo_sidecar/live.rs +++ b/crates/ely_servo_host/src/bin/ely_servo_sidecar/live.rs @@ -9,9 +9,9 @@ use std::{ use ely_domain::{DEFAULT_ZOOM_PERCENT, ProfileId, TabId, UrlText}; use ely_servo_host::{ - KeyboardTextRequest, MouseClickRequest, NavigationRequest, PageZoomRequest, PermissionDecision, - PermissionRequest, RenderedFrame, ResizeRequest, ScrollRequest, ServoHost, ServoHostError, - ServoSurfaceSize, SoftwareServoHost, WebViewSnapshot, WebViewState, + KeyboardTextRequest, MouseClickRequest, MouseHoverRequest, NavigationRequest, PageZoomRequest, + PermissionDecision, PermissionRequest, RenderedFrame, ResizeRequest, ScrollRequest, ServoHost, + ServoHostError, ServoSurfaceSize, SoftwareServoHost, WebViewSnapshot, WebViewState, }; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -230,7 +230,7 @@ fn apply_input( } if let (Some(x), Some(y)) = (hover_x, hover_y) { - host.hover(x, y)?; + host.hover(MouseHoverRequest { webview_id: session.webview_id.clone(), x, y })?; changed = true; } diff --git a/crates/ely_servo_host/src/host.rs b/crates/ely_servo_host/src/host.rs index 639354b..14fcf90 100644 --- a/crates/ely_servo_host/src/host.rs +++ b/crates/ely_servo_host/src/host.rs @@ -242,6 +242,13 @@ pub struct MouseClickRequest { pub y: u32, } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MouseHoverRequest { + pub webview_id: WebViewId, + pub x: u32, + pub y: u32, +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct MouseDragRequest { pub webview_id: WebViewId, diff --git a/crates/ely_servo_host/src/lib.rs b/crates/ely_servo_host/src/lib.rs index 3aa6b12..e9b27a7 100644 --- a/crates/ely_servo_host/src/lib.rs +++ b/crates/ely_servo_host/src/lib.rs @@ -15,9 +15,10 @@ mod runtime_webview; pub use error::ServoHostError; pub use host::{ - KeyboardTextRequest, MouseClickRequest, MouseDragRequest, NavigationRequest, PageZoomRequest, - PermissionDecision, PermissionRequest, RenderedFrame, RenderedFrameSummary, ResizeRequest, - ScreenshotRequest, ScrollRequest, ServoHost, TouchTapRequest, WebViewSnapshot, WebViewState, + KeyboardTextRequest, MouseClickRequest, MouseDragRequest, MouseHoverRequest, + NavigationRequest, PageZoomRequest, PermissionDecision, PermissionRequest, RenderedFrame, + RenderedFrameSummary, ResizeRequest, ScreenshotRequest, ScrollRequest, ServoHost, + TouchTapRequest, WebViewSnapshot, WebViewState, }; #[cfg(feature = "servo-engine")] pub use runtime::{ServoSurfaceSize, SoftwareServoHost}; diff --git a/crates/ely_servo_host/src/runtime.rs b/crates/ely_servo_host/src/runtime.rs index 50ed872..d4fc892 100644 --- a/crates/ely_servo_host/src/runtime.rs +++ b/crates/ely_servo_host/src/runtime.rs @@ -20,9 +20,10 @@ use servo::{ use url::Url; use crate::{ - KeyboardTextRequest, MouseClickRequest, MouseDragRequest, NavigationRequest, PageZoomRequest, - PermissionDecision, PermissionRequest, RenderedFrame, ResizeRequest, ScreenshotRequest, - ScrollRequest, ServoHost, ServoHostError, TouchTapRequest, WebViewSnapshot, WebViewState, + KeyboardTextRequest, MouseClickRequest, MouseDragRequest, MouseHoverRequest, + NavigationRequest, PageZoomRequest, PermissionDecision, PermissionRequest, RenderedFrame, + ResizeRequest, ScreenshotRequest, ScrollRequest, ServoHost, ServoHostError, TouchTapRequest, + WebViewSnapshot, WebViewState, runtime_input::{ send_keyboard_text, send_mouse_click, send_mouse_drag, send_mouse_hover, send_touch_tap, }, @@ -196,10 +197,13 @@ impl ServoHost for SoftwareServoHost { Ok(()) } - fn hover(&mut self, x: u32, y: u32) -> Result<(), ServoHostError> { - if let Some(webview) = self.webviews.values().next() { - send_mouse_hover(&webview.webview, x, y); - } + fn hover(&mut self, request: MouseHoverRequest) -> Result<(), ServoHostError> { + let webview = self + .webviews + .get(&request.webview_id) + .ok_or_else(|| ServoHostError::WebViewNotFound { id: request.webview_id.clone() })?; + + send_mouse_hover(&webview.webview, request.x, request.y); Ok(()) }