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 mgr = state.browser.as_ref().ok_or("Browser not launched")?;
|
||||||
let session_id = mgr.active_session_id()?.to_string();
|
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
|
let event_type = cmd
|
||||||
.get("eventType")
|
.get("eventType")
|
||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
|
|||||||
@@ -202,25 +202,21 @@ pub async fn type_text(
|
|||||||
.await?;
|
.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);
|
let delay = delay_ms.unwrap_or(0);
|
||||||
|
|
||||||
for ch in text.chars() {
|
for ch in text.chars() {
|
||||||
let text_str = ch.to_string();
|
if matches!(ch, '\n' | '\r' | '\t') {
|
||||||
let (key, code, key_code) = char_to_key_info(ch);
|
let (key, code, key_code) = char_to_key_info(ch);
|
||||||
|
let text_str = key_text(&key);
|
||||||
// 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 {
|
|
||||||
client
|
client
|
||||||
.send_command_typed::<_, Value>(
|
.send_command_typed::<_, Value>(
|
||||||
"Input.dispatchKeyEvent",
|
"Input.dispatchKeyEvent",
|
||||||
@@ -228,8 +224,8 @@ pub async fn type_text(
|
|||||||
event_type: "keyDown".to_string(),
|
event_type: "keyDown".to_string(),
|
||||||
key: Some(key.clone()),
|
key: Some(key.clone()),
|
||||||
code: Some(code.clone()),
|
code: Some(code.clone()),
|
||||||
text: Some(text_str.clone()),
|
text: text_str.clone(),
|
||||||
unmodified_text: Some(text_str.clone()),
|
unmodified_text: text_str,
|
||||||
windows_virtual_key_code: Some(key_code),
|
windows_virtual_key_code: Some(key_code),
|
||||||
native_virtual_key_code: Some(key_code),
|
native_virtual_key_code: Some(key_code),
|
||||||
modifiers: None,
|
modifiers: None,
|
||||||
@@ -254,6 +250,19 @@ pub async fn type_text(
|
|||||||
Some(session_id),
|
Some(session_id),
|
||||||
)
|
)
|
||||||
.await?;
|
.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 {
|
if delay > 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user