use ely_domain::TabId; use gpui::{Context, KeyDownEvent, Window}; use super::{ElyShell, ShellState, web_surface::is_external_web_url}; impl ElyShell { pub(super) fn on_external_web_key_down( &mut self, event: &KeyDownEvent, _window: &mut Window, cx: &mut Context, ) { let Some((tab_id, requested_url)) = self.active_external_tab_target() else { return; }; if let Some(text) = printable_text_from_key_down(event) { if self.type_text_in_external_web_viewport(tab_id, requested_url, text, cx) { cx.stop_propagation(); } return; } if let Some(text) = special_key_text(event) && self.type_text_in_external_web_viewport(tab_id, requested_url, text, cx) { cx.stop_propagation(); } } fn active_external_tab_target(&self) -> Option<(TabId, String)> { let ShellState::Ready(core) = &self.state else { return None; }; let tab = core.active_tab().ok()?; let requested_url = tab.url().as_str(); if !is_external_web_url(requested_url) { return None; } Some((tab.id().clone(), requested_url.to_string())) } } fn printable_text_from_key_down(event: &KeyDownEvent) -> Option<&str> { let modifiers = &event.keystroke.modifiers; if modifiers.control || modifiers.platform || modifiers.function { return None; } let text = event.keystroke.key_char.as_deref()?; let mut chars = text.chars(); let character = chars.next()?; if chars.next().is_some() || character.is_control() { return None; } Some(text) } fn special_key_text(event: &KeyDownEvent) -> Option<&'static str> { if event.keystroke.modifiers.platform || event.keystroke.modifiers.control { return None; } match event.keystroke.key.as_str() { "enter" => Some("\n"), "backspace" => Some("\x08"), "tab" => Some("\t"), "escape" => Some("\x1b"), "delete" => Some("\x7f"), "left" => Some("\u{F702}"), "right" => Some("\u{F703}"), "up" => Some("\u{F700}"), "down" => Some("\u{F701}"), "home" => Some("\u{F729}"), "end" => Some("\u{F72B}"), "pageup" => Some("\u{F72C}"), "pagedown" => Some("\u{F72D}"), _ => None, } } #[cfg(test)] mod tests { use gpui::{KeyDownEvent, Keystroke, Modifiers}; use super::{printable_text_from_key_down, special_key_text}; #[test] fn typed_text_uses_printable_key_char() { let event = key_down("e", Some("e"), Modifiers::none()); assert_eq!(printable_text_from_key_down(&event), Some("e")); } #[test] fn typed_text_keeps_shifted_characters() { let mut modifiers = Modifiers::none(); modifiers.shift = true; let event = key_down("1", Some("!"), modifiers); assert_eq!(printable_text_from_key_down(&event), Some("!")); } #[test] fn typed_text_ignores_browser_shortcuts() { let mut modifiers = Modifiers::none(); modifiers.platform = true; let event = key_down("l", None, modifiers); assert_eq!(printable_text_from_key_down(&event), None); } #[test] fn special_key_enter() { let event = key_down("enter", None, Modifiers::none()); assert_eq!(special_key_text(&event), Some("\n")); } #[test] fn special_key_backspace() { let event = key_down("backspace", None, Modifiers::none()); assert_eq!(special_key_text(&event), Some("\x08")); } #[test] fn special_key_ignored_with_platform_modifier() { let mut modifiers = Modifiers::none(); modifiers.platform = true; let event = key_down("enter", None, modifiers); assert_eq!(special_key_text(&event), None); } #[test] fn special_key_arrows() { let event = key_down("left", None, Modifiers::none()); assert_eq!(special_key_text(&event), Some("\u{F702}")); let event = key_down("right", None, Modifiers::none()); assert_eq!(special_key_text(&event), Some("\u{F703}")); } fn key_down(key: &str, key_char: Option<&str>, modifiers: Modifiers) -> KeyDownEvent { KeyDownEvent { keystroke: Keystroke { modifiers, key: key.to_string(), key_char: key_char.map(str::to_string), }, is_held: false, } } }