-
Notifications
You must be signed in to change notification settings - Fork 5.3k
[Unix] Console.ReadKey rewrite #72193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
d929235
c8887ec
cf77107
c6f3a60
acd4f24
f5e3641
d3cdb93
7ea9f50
dc0af6b
c927091
f30f02e
5ffdd67
9230c81
41a92bf
af92ab3
9a2ed71
69f12c9
5bbac1d
a9db7db
c2e02d8
620d1a0
20593ef
c612f4f
3e62636
aa07430
254c762
4023725
d65c6e7
8cd9e3d
7fea037
16e983f
dd07418
632267c
69f6434
9c352b4
f974992
b3366a8
dc82fb5
214da94
7766ed3
c8010c5
c28d600
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
remove UXTerm as its the same as Term
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -67,18 +67,40 @@ private static bool TryParseTerminalInputSequence(char[] buffer, ConsolePal.Term | |||||
| character = default; | ||||||
| key = default; | ||||||
|
|
||||||
| // xterm and VT sequences start with "^[[", some xterm start with "^[O" ("^[" stands for Escape (27)) | ||||||
| // sequences start with either "^[[" or "^[O". "^[" stands for Escape (27). | ||||||
| if (input.Length < MinimalSequenceLength || input[0] != Escape || (input[1] != '[' && input[1] != 'O')) | ||||||
| { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| // Is it a three character sequence? (examples: '^[[H' (Home), '^[OP' (F1), '^[Ow' (End)) | ||||||
| if (input[1] == 'O' || char.IsAsciiLetter(input[2])) | ||||||
| // Is it a three character sequence? (examples: '^[[H' (Home), '^[OP' (F1)) | ||||||
| if (input[1] == 'O' || char.IsAsciiLetter(input[2]) || input.Length == MinimalSequenceLength) | ||||||
| { | ||||||
| if (!TryMapUsingTerminfoDb(buffer.AsMemory(startIndex, MinimalSequenceLength), terminalFormatStrings, ref key, ref isShift, ref isAlt, ref isCtrl)) | ||||||
| { | ||||||
| key = MapKeyId(input[2]); // fallback to well known mappings | ||||||
| // All terminals which use "^[O{letter}" escape sequences don't define conflicting mappings. | ||||||
| // Example: ^[OH either means Home or simply is not used by given terminal. | ||||||
| // But with "^[[{character}" sequences, there are conflicts between rxvt and SCO. | ||||||
| // Example: "^[[a" is Shift+UpArrow for rxvt and Shift+F3 for SCO. | ||||||
| if (input[1] == 'O'|| terminalFormatStrings.IsRxvtTerm) | ||||||
jozkee marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| { | ||||||
| key = MapKeyIdOXterm(input[2]); // fallback to well known mappings | ||||||
|
|
||||||
| if (key != default) | ||||||
| { | ||||||
| // lowercase characters are used by rxvt to express Shift modifier for the arrow keys | ||||||
| isShift = char.IsBetween(input[2], 'a', 'd'); | ||||||
| } | ||||||
| } | ||||||
| else | ||||||
| { | ||||||
| (key, ConsoleModifiers mod) = MapSCO(input[2]); // fallback to well known mappings | ||||||
|
|
||||||
| if (key != default) | ||||||
| { | ||||||
| Apply(mod, ref isShift, ref isAlt, ref isCtrl); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if (key == default) | ||||||
| { | ||||||
|
|
@@ -90,9 +112,15 @@ private static bool TryParseTerminalInputSequence(char[] buffer, ConsolePal.Term | |||||
| return true; | ||||||
| } | ||||||
|
|
||||||
| if (input.Length == MinimalSequenceLength) | ||||||
| // Is it a four character sequence used by Linux Console or PuTTy configured to emulate it? (examples: '^[[[A' (F1), '^[[[B' (F2)) | ||||||
| if (input[1] == '[' && input[2] == '[' && char.IsBetween(input[3], 'A', 'E')) | ||||||
| { | ||||||
| return false; | ||||||
| if (!TryMapUsingTerminfoDb(buffer.AsMemory(startIndex, 4), terminalFormatStrings, ref key, ref isShift, ref isAlt, ref isCtrl)) | ||||||
| { | ||||||
| key = ConsoleKey.F1 + input[3] - 'A'; | ||||||
| } | ||||||
| startIndex += 4; | ||||||
| return true; | ||||||
| } | ||||||
|
|
||||||
| // If sequence does not start with a letter, it must start with one or two digits that represent the Sequence Number | ||||||
|
|
@@ -142,7 +170,7 @@ private static bool TryParseTerminalInputSequence(char[] buffer, ConsolePal.Term | |||||
|
|
||||||
| key = input[SequencePrefixLength + digitCount + 2] is VtSequenceEndTag | ||||||
| ? MapEscapeSequenceNumber(byte.Parse(input.Slice(SequencePrefixLength, digitCount))) | ||||||
| : MapKeyId(input[SequencePrefixLength + digitCount + 2]); | ||||||
| : MapKeyIdOXterm(input[SequencePrefixLength + digitCount + 2]); | ||||||
|
|
||||||
| if (key != default) | ||||||
| { | ||||||
|
|
@@ -166,24 +194,53 @@ static bool TryMapUsingTerminfoDb(ReadOnlyMemory<char> inputSequence, ConsolePal | |||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| static ConsoleKey MapKeyId(char single) | ||||||
| => single switch | ||||||
| // maps "^[O{character}" for all Terminals and "^[[{character}" for rxvt Terminals | ||||||
| static ConsoleKey MapKeyIdOXterm(char character) | ||||||
| => character switch | ||||||
| { | ||||||
| // lowercase characters are used by rxvt | ||||||
| 'A' or 'a' => ConsoleKey.UpArrow, | ||||||
| 'B' or 'b' => ConsoleKey.DownArrow, | ||||||
| 'C' or 'c' => ConsoleKey.RightArrow, | ||||||
| 'D' or 'd' => ConsoleKey.LeftArrow, | ||||||
| 'F' or 'w' => ConsoleKey.End, | ||||||
| 'H' => ConsoleKey.Home, | ||||||
| 'M' => ConsoleKey.Enter, | ||||||
| 'P' => ConsoleKey.F1, | ||||||
| 'Q' => ConsoleKey.F2, | ||||||
| 'R' => ConsoleKey.F3, | ||||||
| 'S' => ConsoleKey.F4, | ||||||
| 'T' => ConsoleKey.F5, // VT 100+ | ||||||
| 'U' => ConsoleKey.F6, // VT 100+ | ||||||
| 'V' => ConsoleKey.F7, // VT 100+ | ||||||
| 'W' => ConsoleKey.F8, // VT 100+ | ||||||
| 'X' => ConsoleKey.F9, // VT 100+ | ||||||
| 'Y' => ConsoleKey.F10, // VT 100+ | ||||||
| 'Z' => ConsoleKey.F11, // VT 100+ | ||||||
| '[' => ConsoleKey.F12, // VT 100+ | ||||||
| _ => default | ||||||
| }; | ||||||
|
|
||||||
| // maps "^[[{character}" for SCO terminals, based on https://vt100.net/docs/vt510-rm/chapter6.html | ||||||
| static (ConsoleKey key, ConsoleModifiers modifiers) MapSCO(char character) | ||||||
| => character switch | ||||||
| { | ||||||
| 'H' => (ConsoleKey.Home, 0), | ||||||
| _ when char.IsBetween(character, 'M', 'X') => (ConsoleKey.F1 + character - 'M', 0), | ||||||
| _ when char.IsBetween(character, 'Y', 'Z') => (ConsoleKey.F1 + character - 'Y', ConsoleModifiers.Shift), | ||||||
| _ when char.IsBetween(character, 'a', 'j') => (ConsoleKey.F3 + character - 'a', ConsoleModifiers.Shift), | ||||||
| _ when char.IsBetween(character, 'k', 'v') => (ConsoleKey.F1 + character - 'k', ConsoleModifiers.Control), | ||||||
| _ when char.IsBetween(character, 'w', 'z') => (ConsoleKey.F1 + character - 'w', ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| '@' => (ConsoleKey.F5, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| '[' => (ConsoleKey.F6, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| '<' or '\\' => (ConsoleKey.F7, ConsoleModifiers.Control | ConsoleModifiers.Shift), // the Spec says <, PuTTy uses \. | ||||||
| ']' => (ConsoleKey.F8, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| '^' => (ConsoleKey.F9, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| '_' => (ConsoleKey.F10, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| '`' => (ConsoleKey.F11, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This one looks to me as
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, but PuTTy uses '`' for it and it's the only Terminal that supports SCO emulation that I could find and test https://serverfault.com/questions/429901/how-to-change-the-terminal-to-sco-compliant-in-ubuntu |
||||||
| '{' => (ConsoleKey.F12, ConsoleModifiers.Control | ConsoleModifiers.Shift), | ||||||
| _ => default | ||||||
| }; | ||||||
|
|
||||||
| // based on https://en.wikipedia.org/wiki/ANSI_escape_code#Fe_Escape_sequences | ||||||
| static ConsoleKey MapEscapeSequenceNumber(byte number) | ||||||
| => number switch | ||||||
| { | ||||||
|
|
@@ -214,10 +271,11 @@ static ConsoleKey MapEscapeSequenceNumber(byte number) | |||||
| 32 => ConsoleKey.F18, | ||||||
| 33 => ConsoleKey.F19, | ||||||
| 34 => ConsoleKey.F20, | ||||||
| // 9, 16, 22, 27, 30 and 35 have no mapping (https://en.wikipedia.org/wiki/ANSI_escape_code#Fe_Escape_sequences) | ||||||
| // 9, 16, 22, 27, 30 and 35 have no mapping | ||||||
| _ => default | ||||||
| }; | ||||||
|
|
||||||
| // based on https://www.xfree86.org/current/ctlseqs.html | ||||||
| static ConsoleModifiers MapXtermModifiers(char modifier) | ||||||
| => modifier switch | ||||||
| { | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.