diff --git a/crates/ely_app/src/shell/web_surface_keyboard.rs b/crates/ely_app/src/shell/web_surface_keyboard.rs index 0c9ea1f..ab8773f 100644 --- a/crates/ely_app/src/shell/web_surface_keyboard.rs +++ b/crates/ely_app/src/shell/web_surface_keyboard.rs @@ -10,15 +10,21 @@ impl ElyShell { _window: &mut Window, cx: &mut Context, ) { - let Some(text) = typed_text_from_key_down(event) else { - return; - }; let Some((tab_id, requested_url)) = self.active_external_tab_target() else { return; }; - if self.type_text_in_external_web_viewport(tab_id, requested_url, text, cx) { - cx.stop_propagation(); + 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) { + if self.type_text_in_external_web_viewport(tab_id, requested_url, text, cx) { + cx.stop_propagation(); + } } } @@ -36,7 +42,7 @@ impl ElyShell { } } -fn typed_text_from_key_down(event: &KeyDownEvent) -> Option<&str> { +fn printable_text_from_key_down(event: &KeyDownEvent) -> Option<&str> { let modifiers = &event.keystroke.modifiers; if modifiers.control || modifiers.platform || modifiers.function { return None; @@ -52,17 +58,39 @@ fn typed_text_from_key_down(event: &KeyDownEvent) -> Option<&str> { 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::typed_text_from_key_down; + 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!(typed_text_from_key_down(&event), Some("e")); + assert_eq!(printable_text_from_key_down(&event), Some("e")); } #[test] @@ -71,7 +99,7 @@ mod tests { modifiers.shift = true; let event = key_down("1", Some("!"), modifiers); - assert_eq!(typed_text_from_key_down(&event), Some("!")); + assert_eq!(printable_text_from_key_down(&event), Some("!")); } #[test] @@ -80,7 +108,36 @@ mod tests { modifiers.platform = true; let event = key_down("l", None, modifiers); - assert_eq!(typed_text_from_key_down(&event), None); + 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 { diff --git a/crates/ely_servo_host/src/keyboard.rs b/crates/ely_servo_host/src/keyboard.rs index 627f744..2c33546 100644 --- a/crates/ely_servo_host/src/keyboard.rs +++ b/crates/ely_servo_host/src/keyboard.rs @@ -1,6 +1,25 @@ -use servo::Code; +use servo::{Code, Key}; -pub(crate) fn keyboard_code_for_character(character: char) -> Code { +pub(crate) fn key_and_code_for_character(character: char) -> (Key, Code) { + match character { + '\n' | '\r' => (Key::Enter, Code::Enter), + '\x08' => (Key::Backspace, Code::Backspace), + '\t' => (Key::Tab, Code::Tab), + '\x1b' => (Key::Escape, Code::Escape), + '\x7f' => (Key::Delete, Code::Delete), + '\u{F700}' => (Key::ArrowUp, Code::ArrowUp), + '\u{F701}' => (Key::ArrowDown, Code::ArrowDown), + '\u{F702}' => (Key::ArrowLeft, Code::ArrowLeft), + '\u{F703}' => (Key::ArrowRight, Code::ArrowRight), + '\u{F729}' => (Key::Home, Code::Home), + '\u{F72B}' => (Key::End, Code::End), + '\u{F72C}' => (Key::PageUp, Code::PageUp), + '\u{F72D}' => (Key::PageDown, Code::PageDown), + _ => (Key::Character(character.to_string()), printable_code(character)), + } +} + +fn printable_code(character: char) -> Code { match character { 'a' | 'A' => Code::KeyA, 'b' | 'B' => Code::KeyB, diff --git a/crates/ely_servo_host/src/runtime_input.rs b/crates/ely_servo_host/src/runtime_input.rs index 0231cd9..f19f6e3 100644 --- a/crates/ely_servo_host/src/runtime_input.rs +++ b/crates/ely_servo_host/src/runtime_input.rs @@ -1,10 +1,10 @@ use servo::{ - DevicePoint, InputEvent, Key, KeyState, KeyboardEvent, Location, Modifiers, MouseButton, + DevicePoint, InputEvent, KeyState, KeyboardEvent, Location, Modifiers, MouseButton, MouseButtonAction, MouseButtonEvent, MouseMoveEvent, TouchEvent, TouchEventType, TouchId, WebView, WebViewPoint, }; -use crate::keyboard::keyboard_code_for_character; +use crate::keyboard::key_and_code_for_character; pub(super) fn send_mouse_click(webview: &WebView, x: u32, y: u32) { let point = point(x, y); @@ -32,8 +32,7 @@ pub(super) fn send_touch_tap(webview: &WebView, x: u32, y: u32) { pub(super) fn send_keyboard_text(webview: &WebView, text: &str) { for character in text.chars() { - let key = Key::Character(character.to_string()); - let code = keyboard_code_for_character(character); + let (key, code) = key_and_code_for_character(character); webview.notify_input_event(InputEvent::Keyboard(KeyboardEvent::new_without_event( KeyState::Down, key.clone(),