From c5020f2b891a5f8941254fd27bcd24b51f6f4339 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Mon, 23 Mar 2026 10:46:05 -0500 Subject: [PATCH] Fix Enter key press not working by adding text field to keyDown events (#972) This PR fixes an issue where pressing the Enter key via the `press Enter` command had no effect on web pages, even though the command executed successfully without errors. ## Problem The Chrome DevTools Protocol `Input.dispatchKeyEvent` requires a `text` field in `keyDown` events for certain keys to trigger their default browser actions. Without this field, keys like Enter don't actually submit forms or perform their expected actions. ## Changes - Added new `key_text()` function that returns the appropriate text value for special keys: - Enter returns `"\r"` (carriage return) - Tab returns `"\t"` (tab character) - Space returns `" "` (space character) - Single printable characters return themselves - Non-printable keys (Escape, Arrow keys, etc.) return `None` - Modified `press_key_with_modifiers()` to populate both `text` and `unmodified_text` fields in the CDP keyDown event - Added comprehensive unit tests for the new functionality ## Implementation Details The fix ensures that when pressing Enter on a filled search box, the form actually submits as expected, matching the behavior of manually pressing the Enter key. Fixes #966 --- cli/src/native/interaction.rs | 40 +++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/cli/src/native/interaction.rs b/cli/src/native/interaction.rs index c858316..56c3a96 100644 --- a/cli/src/native/interaction.rs +++ b/cli/src/native/interaction.rs @@ -282,6 +282,7 @@ pub async fn press_key_with_modifiers( modifiers: Option, ) -> Result<(), String> { let (key_name, code, key_code) = named_key_info(key); + let text = key_text(&key_name); client .send_command_typed::<_, Value>( @@ -290,8 +291,8 @@ pub async fn press_key_with_modifiers( event_type: "keyDown".to_string(), key: Some(key_name.clone()), code: Some(code.clone()), - text: None, - unmodified_text: None, + text: text.clone(), + unmodified_text: text.clone(), windows_virtual_key_code: Some(key_code), native_virtual_key_code: Some(key_code), modifiers, @@ -1000,6 +1001,26 @@ fn punctuation_key_info(ch: char) -> (&'static str, i32) { } } +/// Return the `text` value that CDP `Input.dispatchKeyEvent` needs on the +/// `keyDown` event so that Chrome performs the default action for the key. +/// For example Enter needs `"\r"` to actually submit a form, and Tab needs +/// `"\t"` to move focus. Non-printable / navigation keys return `None`. +fn key_text(key_name: &str) -> Option { + match key_name { + "Enter" => Some("\r".to_string()), + "Tab" => Some("\t".to_string()), + " " => Some(" ".to_string()), + _ => { + // Single printable characters carry themselves as text. + if key_name.len() == 1 { + Some(key_name.to_string()) + } else { + None + } + } + } +} + fn named_key_info(key: &str) -> (String, String, i32) { match key.to_lowercase().as_str() { "enter" | "return" => ("Enter".to_string(), "Enter".to_string(), 13), @@ -1127,4 +1148,19 @@ mod tests { assert_eq!(key, ch.to_string()); } } + + #[test] + fn test_key_text_returns_correct_text_for_special_keys() { + assert_eq!(key_text("Enter"), Some("\r".to_string())); + assert_eq!(key_text("Tab"), Some("\t".to_string())); + assert_eq!(key_text(" "), Some(" ".to_string())); + // Single printable characters carry themselves. + assert_eq!(key_text("a"), Some("a".to_string())); + assert_eq!(key_text("Z"), Some("Z".to_string())); + // Non-printable named keys return None. + assert_eq!(key_text("Escape"), None); + assert_eq!(key_text("ArrowUp"), None); + assert_eq!(key_text("Backspace"), None); + assert_eq!(key_text("Delete"), None); + } }