diff --git a/src/XTerm.NET.Tests/KeyboardInputTests.cs b/src/XTerm.NET.Tests/KeyboardInputTests.cs index 70abc2b..9f1a83a 100644 --- a/src/XTerm.NET.Tests/KeyboardInputTests.cs +++ b/src/XTerm.NET.Tests/KeyboardInputTests.cs @@ -200,6 +200,27 @@ public void ControlKeys_GenerateCorrectSequences() Assert.Equal(" ", terminal.GenerateKeyInput(Key.Space)); } + [Fact] + public void Backspace_WithAlt_PrefixesEscape() + { + // Arrange + var terminal = CreateTerminal(); + + // Act & Assert + Assert.Equal("\x1B\x7F", terminal.GenerateKeyInput(Key.Backspace, KeyModifiers.Alt)); + } + + [Fact] + public void Backspace_WithControl_GeneratesBS() + { + // Arrange + var terminal = CreateTerminal(); + + // Act & Assert + Assert.Equal("\b", terminal.GenerateKeyInput(Key.Backspace, KeyModifiers.Control)); + Assert.Equal("\x1B\b", terminal.GenerateKeyInput(Key.Backspace, KeyModifiers.Control | KeyModifiers.Alt)); + } + [Fact] public void Tab_WithShift_GeneratesBackTab() { diff --git a/src/XTerm.NET/Input/KeyboardInputGenerator.cs b/src/XTerm.NET/Input/KeyboardInputGenerator.cs index 1751f46..1fce2a8 100644 --- a/src/XTerm.NET/Input/KeyboardInputGenerator.cs +++ b/src/XTerm.NET/Input/KeyboardInputGenerator.cs @@ -33,7 +33,7 @@ public string GenerateKeySequence(Key key, KeyModifiers modifiers = KeyModifiers // Control keys Key.Enter => "\r", Key.Tab => (modifiers & KeyModifiers.Shift) != 0 ? "\u001b[Z" : "\t", - Key.Backspace => "\u007f", // DEL (127) + Key.Backspace => GetBackspace(modifiers), // Escape sends ESC whatever the modifiers. CSI 27 ; mod ~ is not a sequence xterm // emits -- it belongs to the modifyOtherKeys and Kitty protocols, which an application // opts into. Sending it unasked meant a program that reads a bare ESC (vim leaving @@ -161,6 +161,14 @@ public string GenerateCharSequence(char c, KeyModifiers modifiers = KeyModifiers }; } + // xterm.js sends BS for Ctrl+Backspace and DEL otherwise, with an ESC prefix when Alt is + // held, which is how Alt+Backspace reaches a shell as backward-kill-word. + private static string GetBackspace(KeyModifiers modifiers) + { + var key = (modifiers & KeyModifiers.Control) != 0 ? "\b" : "\u007f"; + return (modifiers & KeyModifiers.Alt) != 0 ? "\u001b" + key : key; + } + private string GetArrowKey(char direction, KeyModifiers modifiers) { // Arrow keys respect ApplicationCursorKeys mode