diff --git a/crates/gpui/src/interactive.rs b/crates/gpui/src/interactive.rs index dafe623dfada7ba7b21140fc36c7c824e8b5f3f6..dd521ff718322d663f761e05598edce83432bf2d 100644 --- a/crates/gpui/src/interactive.rs +++ b/crates/gpui/src/interactive.rs @@ -115,6 +115,16 @@ impl InputEvent for MouseDownEvent { } impl MouseEvent for MouseDownEvent {} +impl MouseDownEvent { + /// Returns true if this mouse up event should focus the element. + pub fn is_focusing(&self) -> bool { + match self.button { + MouseButton::Left => true, + _ => false, + } + } +} + /// A mouse up event from the platform #[derive(Clone, Debug, Default)] pub struct MouseUpEvent { @@ -137,8 +147,19 @@ impl InputEvent for MouseUpEvent { PlatformInput::MouseUp(self) } } + impl MouseEvent for MouseUpEvent {} +impl MouseUpEvent { + /// Returns true if this mouse up event should focus the element. + pub fn is_focusing(&self) -> bool { + match self.button { + MouseButton::Left => true, + _ => false, + } + } +} + /// A click event, generated when a mouse button is pressed and released. #[derive(Clone, Debug, Default)] pub struct MouseClickEvent { @@ -482,6 +503,7 @@ impl InputEvent for MouseExitEvent { PlatformInput::MouseExited(self) } } + impl MouseEvent for MouseExitEvent {} impl Deref for MouseExitEvent { diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 17d09e67dbafbf51be604180f3ff1333cc732cfd..80f6fdf9f537a3147455fae0dc8d9a5bab0ebdb6 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -822,6 +822,12 @@ impl Frame { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +enum InputModality { + Mouse, + Keyboard, +} + /// Holds the state for a specific window. pub struct Window { pub(crate) handle: AnyWindowHandle, @@ -870,7 +876,7 @@ pub struct Window { hovered: Rc>, pub(crate) needs_present: Rc>, pub(crate) last_input_timestamp: Rc>, - last_input_was_keyboard: bool, + last_input_modality: InputModality, pub(crate) refreshing: bool, pub(crate) activation_observers: SubscriberSet<(), AnyObserver>, pub(crate) focus: Option, @@ -1254,7 +1260,7 @@ impl Window { hovered, needs_present, last_input_timestamp, - last_input_was_keyboard: false, + last_input_modality: InputModality::Mouse, refreshing: false, activation_observers: SubscriberSet::new(), focus: None, @@ -1910,7 +1916,7 @@ impl Window { /// Returns true if the last input event was keyboard-based (key press, tab navigation, etc.) /// This is used for focus-visible styling to show focus indicators only for keyboard navigation. pub fn last_input_was_keyboard(&self) -> bool { - self.last_input_was_keyboard + self.last_input_modality == InputModality::Keyboard } /// The current state of the keyboard's capslock @@ -3591,12 +3597,13 @@ impl Window { self.last_input_timestamp.set(Instant::now()); // Track whether this input was keyboard-based for focus-visible styling - self.last_input_was_keyboard = matches!( - event, - PlatformInput::KeyDown(_) - | PlatformInput::KeyUp(_) - | PlatformInput::ModifiersChanged(_) - ); + self.last_input_modality = match &event { + PlatformInput::KeyDown(_) | PlatformInput::ModifiersChanged(_) => { + InputModality::Keyboard + } + PlatformInput::MouseDown(e) if e.is_focusing() => InputModality::Mouse, + _ => self.last_input_modality, + }; // Handlers may set this to false by calling `stop_propagation`. cx.propagate_event = true;