fix: route keyboard type through text input (#1014)
This commit is contained in:
@@ -3115,6 +3115,33 @@ async fn handle_keyboard(cmd: &Value, state: &DaemonState) -> Result<Value, Stri
|
||||
let mgr = state.browser.as_ref().ok_or("Browser not launched")?;
|
||||
let session_id = mgr.active_session_id()?.to_string();
|
||||
|
||||
match cmd.get("subaction").and_then(|v| v.as_str()) {
|
||||
Some("type") => {
|
||||
let text = cmd
|
||||
.get("text")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or("Missing 'text' parameter")?;
|
||||
interaction::type_text_into_active_context(&mgr.client, &session_id, text, None)
|
||||
.await?;
|
||||
return Ok(json!({ "typed": text }));
|
||||
}
|
||||
Some("insertText") => {
|
||||
let text = cmd
|
||||
.get("text")
|
||||
.and_then(|v| v.as_str())
|
||||
.ok_or("Missing 'text' parameter")?;
|
||||
mgr.client
|
||||
.send_command(
|
||||
"Input.insertText",
|
||||
Some(json!({ "text": text })),
|
||||
Some(&session_id),
|
||||
)
|
||||
.await?;
|
||||
return Ok(json!({ "inserted": true }));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let event_type = cmd
|
||||
.get("eventType")
|
||||
.and_then(|v| v.as_str())
|
||||
|
||||
@@ -202,25 +202,21 @@ pub async fn type_text(
|
||||
.await?;
|
||||
}
|
||||
|
||||
type_text_into_active_context(client, session_id, text, delay_ms).await
|
||||
}
|
||||
|
||||
pub async fn type_text_into_active_context(
|
||||
client: &CdpClient,
|
||||
session_id: &str,
|
||||
text: &str,
|
||||
delay_ms: Option<u64>,
|
||||
) -> Result<(), String> {
|
||||
let delay = delay_ms.unwrap_or(0);
|
||||
|
||||
for ch in text.chars() {
|
||||
let text_str = ch.to_string();
|
||||
let (key, code, key_code) = char_to_key_info(ch);
|
||||
|
||||
// Characters that have no US-keyboard mapping (key_code == 0 and empty
|
||||
// code) are inserted via `Input.insertText`, matching Playwright's
|
||||
// keyboard.type() fallback behaviour. This handles emoji, CJK, and
|
||||
// other characters that don't correspond to a physical key.
|
||||
if key_code == 0 && code.is_empty() {
|
||||
client
|
||||
.send_command_typed::<_, Value>(
|
||||
"Input.insertText",
|
||||
&InsertTextParams { text: text_str },
|
||||
Some(session_id),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
if matches!(ch, '\n' | '\r' | '\t') {
|
||||
let (key, code, key_code) = char_to_key_info(ch);
|
||||
let text_str = key_text(&key);
|
||||
client
|
||||
.send_command_typed::<_, Value>(
|
||||
"Input.dispatchKeyEvent",
|
||||
@@ -228,8 +224,8 @@ pub async fn type_text(
|
||||
event_type: "keyDown".to_string(),
|
||||
key: Some(key.clone()),
|
||||
code: Some(code.clone()),
|
||||
text: Some(text_str.clone()),
|
||||
unmodified_text: Some(text_str.clone()),
|
||||
text: text_str.clone(),
|
||||
unmodified_text: text_str,
|
||||
windows_virtual_key_code: Some(key_code),
|
||||
native_virtual_key_code: Some(key_code),
|
||||
modifiers: None,
|
||||
@@ -254,6 +250,19 @@ pub async fn type_text(
|
||||
Some(session_id),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
// VS Code/Electron webviews reject repeated dispatchKeyEvent calls
|
||||
// carrying printable `text`. Insert printable characters directly
|
||||
// and reserve key events for controls like Enter and Tab.
|
||||
client
|
||||
.send_command_typed::<_, Value>(
|
||||
"Input.insertText",
|
||||
&InsertTextParams {
|
||||
text: ch.to_string(),
|
||||
},
|
||||
Some(session_id),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if delay > 0 {
|
||||
|
||||
Reference in New Issue
Block a user