From 750cbdf7062735a3d3229b6d22f4300ced36f5aa Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Mon, 19 Sep 2022 20:35:32 +0200 Subject: [PATCH] KeyChar should be preserved for Ctrl+Letter --- src/libraries/System.Console/src/System/IO/KeyParser.cs | 8 +++++--- src/libraries/System.Console/tests/KeyParserTests.cs | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Console/src/System/IO/KeyParser.cs b/src/libraries/System.Console/src/System/IO/KeyParser.cs index d54e0800a42b9..1167d00ec81c7 100644 --- a/src/libraries/System.Console/src/System/IO/KeyParser.cs +++ b/src/libraries/System.Console/src/System/IO/KeyParser.cs @@ -333,7 +333,7 @@ private static ConsoleKeyInfo ParseFromSingleChar(char single, bool isAlt) _ when char.IsAsciiLetterLower(single) => ConsoleKey.A + single - 'a', _ when char.IsAsciiLetterUpper(single) => UppercaseCharacter(single, out isShift), _ when char.IsAsciiDigit(single) => ConsoleKey.D0 + single - '0', // We can't distinguish DX and Ctrl+DX as they produce same values. Limitation: Ctrl+DX can't be mapped. - _ when char.IsBetween(single, (char)1, (char)26) => ControlAndLetterPressed(single, out keyChar, out isCtrl), + _ when char.IsBetween(single, (char)1, (char)26) => ControlAndLetterPressed(single, isAlt, out keyChar, out isCtrl), _ when char.IsBetween(single, (char)28, (char)31) => ControlAndDigitPressed(single, out keyChar, out isCtrl), '\u0000' => ControlAndDigitPressed(single, out keyChar, out isCtrl), _ => default @@ -359,7 +359,7 @@ static ConsoleKey UppercaseCharacter(char single, out bool isShift) return ConsoleKey.A + single - 'A'; } - static ConsoleKey ControlAndLetterPressed(char single, out char keyChar, out bool isCtrl) + static ConsoleKey ControlAndLetterPressed(char single, bool isAlt, out char keyChar, out bool isCtrl) { // Ctrl+(a-z) characters are mapped to values from 1 to 26. // Ctrl+H is mapped to 8, which also maps to Ctrl+Backspace. @@ -370,7 +370,9 @@ static ConsoleKey ControlAndLetterPressed(char single, out char keyChar, out boo Debug.Assert(single != 'b' && single != '\t' && single != '\n' && single != '\r'); isCtrl = true; - keyChar = default; // we could use the letter here, but it's impossible to distinguish upper vs lowercase (and Windows doesn't do it as well) + // Preserve the original character the same way Windows does (#75795), + // but only when Alt was not pressed at the same time. + keyChar = isAlt ? default : single; return ConsoleKey.A + single - 1; } diff --git a/src/libraries/System.Console/tests/KeyParserTests.cs b/src/libraries/System.Console/tests/KeyParserTests.cs index f5cebdeeff17e..bf672b6b8788f 100644 --- a/src/libraries/System.Console/tests/KeyParserTests.cs +++ b/src/libraries/System.Console/tests/KeyParserTests.cs @@ -264,6 +264,8 @@ public void ExtendedStringCodePath() { get { + // Control+C + yield return (new string((char)3, 1), new[] { new ConsoleKeyInfo((char)3, ConsoleKey.C, false, false, true) }); // Backspace yield return (new string((char)127, 1), new[] { new ConsoleKeyInfo((char)127, ConsoleKey.Backspace, false, false, false) }); // Ctrl+Backspace @@ -448,7 +450,7 @@ public class GNOMETerminalData : TerminalData { yield return (new byte[] { 90 }, new ConsoleKeyInfo('Z', ConsoleKey.Z, true, false, false)); yield return (new byte[] { 97 }, new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false)); - yield return (new byte[] { 1 }, new ConsoleKeyInfo(default, ConsoleKey.A, false, false, true)); + yield return (new byte[] { 1 }, new ConsoleKeyInfo((char)1, ConsoleKey.A, false, false, true)); yield return (new byte[] { 27, 97 }, new ConsoleKeyInfo('a', ConsoleKey.A, false, true, false)); yield return (new byte[] { 27, 1 }, new ConsoleKeyInfo(default, ConsoleKey.A, false, true, true)); yield return (new byte[] { 49 }, new ConsoleKeyInfo('1', ConsoleKey.D1, false, false, false)); @@ -613,7 +615,7 @@ public class XTermData : TerminalData { yield return (new byte[] { 90 }, new ConsoleKeyInfo('Z', ConsoleKey.Z, true, false, false)); yield return (new byte[] { 97 }, new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false)); - yield return (new byte[] { 1 }, new ConsoleKeyInfo(default, ConsoleKey.A, false, false, true)); + yield return (new byte[] { 1 }, new ConsoleKeyInfo((char)1, ConsoleKey.A, false, false, true)); yield return (new byte[] { 195, 161 }, new ConsoleKeyInfo('\u00E1', default, false, false, false)); yield return (new byte[] { 194, 129 }, new ConsoleKeyInfo('\u0081', default, false, false, false)); yield return (new byte[] { 49 }, new ConsoleKeyInfo('1', ConsoleKey.D1, false, false, false)); @@ -886,7 +888,7 @@ public class WindowsTerminalData : TerminalData { yield return (new byte[] { 90 }, new ConsoleKeyInfo('Z', ConsoleKey.Z, true, false, false)); yield return (new byte[] { 97 }, new ConsoleKeyInfo('a', ConsoleKey.A, false, false, false)); - yield return (new byte[] { 1 }, new ConsoleKeyInfo(default, ConsoleKey.A, false, false, true)); + yield return (new byte[] { 1 }, new ConsoleKeyInfo((char)1, ConsoleKey.A, false, false, true)); yield return (new byte[] { 27, 97 }, new ConsoleKeyInfo('a', ConsoleKey.A, false, true, false)); yield return (new byte[] { 27, 1 }, new ConsoleKeyInfo(default, ConsoleKey.A, false, true, true)); yield return (new byte[] { 49 }, new ConsoleKeyInfo('1', ConsoleKey.D1, false, false, false));