aboutsummaryrefslogtreecommitdiff
path: root/src/protocol
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-09-12 00:38:57 +0300
committerGitHub <noreply@github.com>2026-09-12 01:38:57 +0400
commit9ad65d9031e8cb16a7b553c0e6f74809e9811e92 (patch)
tree84fb346571442899f6fe1b1a6b60783d2be764b2 /src/protocol
parentfb5525fc2234a246dfdfc9e0d7ed73c824cbd8a6 (diff)
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>
Diffstat (limited to 'src/protocol')
-rw-r--r--src/protocol/wire.rs49
1 files changed, 48 insertions, 1 deletions
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(