From 9bf79a42426c0c2a9269bdb252a416875bcd7016 Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Sat, 13 Jun 2026 23:58:30 +0900 Subject: [PATCH] fix(keyboard): keydown/keyup send full key descriptor so hold-to-move works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `keydown`/`keyup` dispatched a minimal Input.dispatchKeyEvent carrying only {key}, so games/handlers that read event.code ("KeyD", "ArrowRight") or event.keyCode saw nothing — a held key set no movement flag and the player barely moved (dogfood: Dead Cell). They now build the same descriptor `press` uses (key + code + windows/nativeVirtualKeyCode + printable text on down) via a shared interaction::dispatch_single_key. Verified live: holding a direction now drives continuous movement (player ran into an enemy and took damage), where before it nudged ~80px. --- cli/src/native/actions.rs | 16 ++----------- cli/src/native/interaction.rs | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/cli/src/native/actions.rs b/cli/src/native/actions.rs index 646cc46..551e594 100644 --- a/cli/src/native/actions.rs +++ b/cli/src/native/actions.rs @@ -8785,13 +8785,7 @@ async fn handle_keydown(cmd: &Value, state: &DaemonState) -> Result Result .and_then(|v| v.as_str()) .ok_or("Missing 'key' parameter")?; - mgr.client - .send_command( - "Input.dispatchKeyEvent", - Some(json!({ "type": "keyUp", "key": key })), - Some(&session_id), - ) - .await?; + interaction::dispatch_single_key(&mgr.client, &session_id, key, "keyUp").await?; Ok(json!({ "keyup": key })) } diff --git a/cli/src/native/interaction.rs b/cli/src/native/interaction.rs index f746d22..c4fbdd0 100644 --- a/cli/src/native/interaction.rs +++ b/cli/src/native/interaction.rs @@ -557,6 +557,48 @@ pub async fn press_key_with_modifiers( Ok(()) } +/// Dispatch a SINGLE key event (`keyDown` or `keyUp`) carrying the full key +/// descriptor — `key`, `code`, `windowsVirtualKeyCode`/`nativeVirtualKeyCode`, +/// and (on key-down) printable `text`. Powers the `keydown`/`keyup` commands. +/// +/// The previous implementation sent only `{key}`, so games and shortcut handlers +/// that read `event.code` (e.g. `"KeyD"`, `"ArrowRight"`) or `event.keyCode` saw +/// nothing — a held key set no movement flag and did nothing (dogfood: holding a +/// direction in a canvas platformer barely nudged the player). Sending the same +/// descriptor `press` uses makes hold-to-move work regardless of which field the +/// page keys off. +pub async fn dispatch_single_key( + client: &CdpClient, + session_id: &str, + key: &str, + event_type: &str, +) -> Result<(), String> { + let (key_name, code, key_code) = named_key_info(key); + // Printable text is only meaningful on key-down; key-up never inserts. + let text = if event_type == "keyDown" { + key_text(&key_name) + } else { + None + }; + client + .send_command_typed::<_, Value>( + "Input.dispatchKeyEvent", + &DispatchKeyEventParams { + event_type: event_type.to_string(), + key: Some(key_name), + code: Some(code), + text: text.clone(), + unmodified_text: text, + windows_virtual_key_code: Some(key_code), + native_virtual_key_code: Some(key_code), + modifiers: None, + }, + Some(session_id), + ) + .await?; + Ok(()) +} + pub async fn scroll( client: &CdpClient, session_id: &str,