From 9ad65d9031e8cb16a7b553c0e6f74809e9811e92 Mon Sep 17 00:00:00 2001 From: akbash Date: Sat, 12 Sep 2026 00:38:57 +0300 Subject: fix: suppress Windows dead-key fallback characters in remote panes (#3972) refs #3948 Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> --- src/protocol/wire.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'src/protocol') diff --git a/src/protocol/wire.rs b/src/protocol/wire.rs index 96881b14..052c73a3 100644 --- a/src/protocol/wire.rs +++ b/src/protocol/wire.rs @@ -2066,7 +2066,7 @@ mod tests { else { panic!("pane dead key should remain a key"); }; - assert!(key.is_windows_shift_dead_key()); + assert!(key.is_windows_dead_key()); assert_eq!(key.windows_record(), None); assert!(crate::input::encode_terminal_key( key, @@ -2075,6 +2075,53 @@ mod tests { .is_empty()); } + #[tokio::test] + async fn client_shell_remote_altgr_dead_key_emits_only_composed_text() { + // Spanish ISO AltGr+4, then Space, captured in #3948: + // https://github.com/herdrdev/herdr/issues/3948#issuecomment-5633222390 + let records = [ + ('4', ClientKeyKind::Press, 52, 5, 0, 9), + ('4', ClientKeyKind::Release, 52, 5, 0, 9), + ('~', ClientKeyKind::Press, 32, 57, 126, 0), + (' ', ClientKeyKind::Release, 32, 57, 32, 0), + ]; + let (runtime, _rx) = crate::terminal::TerminalRuntime::test_with_channel(80, 24); + let mut output = Vec::new(); + for (ch, kind, virtual_key_code, virtual_scan_code, unicode, control_key_state) in records { + let event = ClientInputEvent::Key { + code: ClientKeyCode::Char(ch), + modifiers: 0, + kind, + repeat_count: 1, + generated_text: None, + source: ClientKeySource::WindowsConsole { + record: crate::input::WindowsKeyRecord { + key_down: kind == ClientKeyKind::Press, + repeat_count: 1, + virtual_key_code, + virtual_scan_code, + unicode, + control_key_state, + }, + }, + }; + let crate::raw_input::RawInputEvent::Key(key) = event.to_raw_input_event() else { + panic!("captured input should remain a key"); + }; + let pane_event = ClientPaneInputEvent::from_terminal_key(key).expect("pane key"); + let crate::raw_input::RawInputEvent::Key(key) = + pane_event.to_raw_input_event_with_windows_source(false) + else { + panic!("remote input should remain a key"); + }; + let bytes = runtime.encode_terminal_key(key); + let expected: &[u8] = if ch == '~' { b"~" } else { b"" }; + assert_eq!(bytes, expected, "captured {ch:?} {kind:?}"); + output.extend(bytes); + } + assert_eq!(output, b"~", "dead key must not insert its base character"); + } + #[test] fn client_shell_key_roundtrip_preserves_physical_generated_text_encoding() { let key = crate::input::TerminalKey::new( -- cgit v1.2.3