2 // System.ConsoleDriver
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (C) 2005,2006 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 // Defining this writes the output to console.log
36 using System.Collections;
39 using System.Runtime.InteropServices;
41 class TermInfoDriver : IConsoleDriver {
43 // This points to a variable that is updated by unmanage code on window size changes.
44 unsafe static int *native_terminal_size;
46 // The current size that we believe we have
47 static int terminal_size;
49 //static uint flag = 0xdeadbeef;
50 readonly static string [] locations = { "/etc/terminfo", "/usr/share/terminfo", "/usr/lib/terminfo" };
52 TermInfoReader reader;
55 string title = String.Empty;
56 string titleFormat = String.Empty;
57 bool cursorVisible = true;
76 string keypadXmit, keypadLocal;
79 object initLock = new object ();
84 ConsoleColor fgcolor = ConsoleColor.White;
85 ConsoleColor bgcolor = ConsoleColor.Black;
86 bool color16 = false; // terminal supports 16 colors
94 bool home_1_1; // if true, we have to add 1 to x and y when using cursorAddress
95 int rl_startx = -1, rl_starty = -1;
96 byte [] control_characters; // Indexed by ControlCharacters.XXXXXX
101 static string SearchTerminfo (string term)
103 if (term == null || term == String.Empty)
106 // Ignore TERMINFO and TERMINFO_DIRS by now
107 //string terminfo = Environment.GetEnvironmentVariable ("TERMINFO");
108 //string terminfoDirs = Environment.GetEnvironmentVariable ("TERMINFO_DIRS");
110 foreach (string dir in locations) {
111 if (!Directory.Exists (dir))
114 string path = Path.Combine (dir, term.Substring (0, 1));
115 if (!Directory.Exists (dir))
118 path = Path.Combine (path, term);
119 if (!File.Exists (path))
128 void WriteConsole (string str)
133 stdout.InternalWriteString (str);
136 public TermInfoDriver ()
137 : this (Environment.GetEnvironmentVariable ("TERM"))
141 public TermInfoDriver (string term)
144 File.Delete ("console.log");
145 logger = new StreamWriter (File.OpenWrite ("console.log"));
149 if (term == "xterm") {
150 reader = new TermInfoReader (term, KnownTerminals.xterm);
152 } else if (term == "linux") {
153 reader = new TermInfoReader (term, KnownTerminals.linux);
156 string filename = SearchTerminfo (term);
157 if (filename != null)
158 reader = new TermInfoReader (term, filename);
162 reader = new TermInfoReader (term, KnownTerminals.ansi);
164 if (!(Console.stdout is CStreamWriter)) {
165 // Application set its own stdout, we need a reference to the real stdout
166 stdout = new CStreamWriter (Console.OpenStandardOutput (0), Console.OutputEncoding);
167 ((StreamWriter) stdout).AutoFlush = true;
169 stdout = (CStreamWriter) Console.stdout;
173 public bool Initialized {
174 get { return inited; }
187 /* This should not happen any more, since it is checked for in Console */
188 if (!ConsoleDriver.IsConsole)
189 throw new IOException ("Not a tty.");
191 ConsoleDriver.SetEcho (false);
193 string endString = null;
194 keypadXmit = reader.Get (TermInfoStrings.KeypadXmit);
195 keypadLocal = reader.Get (TermInfoStrings.KeypadLocal);
196 if (keypadXmit != null) {
197 WriteConsole (keypadXmit); // Needed to get the arrows working
198 if (keypadLocal != null)
199 endString += keypadLocal;
202 origPair = reader.Get (TermInfoStrings.OrigPair);
203 origColors = reader.Get (TermInfoStrings.OrigColors);
204 setfgcolor = MangleParameters (reader.Get (TermInfoStrings.SetAForeground));
205 setbgcolor = MangleParameters (reader.Get (TermInfoStrings.SetABackground));
206 // lighter fg colours are 90 -> 97 rather than 30 -> 37
207 setlfgcolor = color16 ? setfgcolor.Replace ("[3", "[9") : setfgcolor;
208 // lighter bg colours are 100 -> 107 rather than 40 -> 47
209 setlbgcolor = color16 ? setbgcolor.Replace ("[4", "[10") : setbgcolor;
210 string resetColors = (origColors == null) ? origPair : origColors;
211 if (resetColors != null)
212 endString += resetColors;
215 if (!ConsoleDriver.TtySetup (keypadXmit, endString, out control_characters, out native_terminal_size)){
216 control_characters = new byte [17];
217 native_terminal_size = null;
218 //throw new IOException ("Error initializing terminal.");
222 stdin = new StreamReader (Console.OpenStandardInput (0), Console.InputEncoding);
223 clear = reader.Get (TermInfoStrings.ClearScreen);
224 bell = reader.Get (TermInfoStrings.Bell);
226 clear = reader.Get (TermInfoStrings.CursorHome);
227 clear += reader.Get (TermInfoStrings.ClrEos);
230 csrVisible = reader.Get (TermInfoStrings.CursorNormal);
231 if (csrVisible == null)
232 csrVisible = reader.Get (TermInfoStrings.CursorVisible);
234 csrInvisible = reader.Get (TermInfoStrings.CursorInvisible);
235 if (term == "cygwin" || term == "linux" || (term != null && term.StartsWith ("xterm")) ||
236 term == "rxvt" || term == "dtterm") {
237 titleFormat = "\x1b]0;{0}\x7"; // icon + window title
238 } else if (term == "iris-ansi") {
239 titleFormat = "\x1bP1.y{0}\x1b\\"; // not tested
240 } else if (term == "sun-cmd") {
241 titleFormat = "\x1b]l{0}\x1b\\"; // not tested
244 cursorAddress = reader.Get (TermInfoStrings.CursorAddress);
245 if (cursorAddress != null) {
246 string result = cursorAddress.Replace ("%i", String.Empty);
247 home_1_1 = (cursorAddress != result);
248 cursorAddress = MangleParameters (result);
251 GetCursorPosition ();
253 logger.WriteLine ("noGetPosition: {0} left: {1} top: {2}", noGetPosition, cursorLeft, cursorTop);
257 WriteConsole (clear);
264 static string MangleParameters (string str)
269 str = str.Replace ("{", "{{");
270 str = str.Replace ("}", "}}");
271 str = str.Replace ("%p1%d", "{0}");
272 return str.Replace ("%p2%d", "{1}");
275 static int TranslateColor (ConsoleColor desired, out bool light)
279 case ConsoleColor.Black:
282 case ConsoleColor.DarkRed:
285 case ConsoleColor.DarkGreen:
288 case ConsoleColor.DarkYellow:
291 case ConsoleColor.DarkBlue:
294 case ConsoleColor.DarkMagenta:
297 case ConsoleColor.DarkCyan:
300 case ConsoleColor.Gray:
304 case ConsoleColor.DarkGray:
307 case ConsoleColor.Red:
310 case ConsoleColor.Green:
313 case ConsoleColor.Yellow:
316 case ConsoleColor.Blue:
319 case ConsoleColor.Magenta:
322 case ConsoleColor.Cyan:
325 case ConsoleColor.White:
338 if (cursorLeft >= WindowWidth) {
341 if (cursorTop >= WindowHeight) {
342 // Writing beyond the initial screen
343 if (rl_starty != -1) rl_starty--;
349 // Should never get called unless inited
350 public void WriteSpecialKey (ConsoleKeyInfo key)
353 case ConsoleKey.Backspace:
354 if (cursorLeft > 0) {
355 if (cursorLeft <= rl_startx && cursorTop == rl_starty)
358 SetCursorPosition (cursorLeft, cursorTop);
360 SetCursorPosition (cursorLeft, cursorTop);
363 logger.WriteLine ("BS left: {0} top: {1}", cursorLeft, cursorTop);
368 int n = 8 - (cursorLeft % 8);
369 for (int i = 0; i < n; i++){
374 case ConsoleKey.Clear:
375 WriteConsole (clear);
379 case ConsoleKey.Enter:
385 logger.WriteLine ("left: {0} top: {1}", cursorLeft, cursorTop);
390 // Should never get called unless inited
391 public void WriteSpecialKey (char c)
393 WriteSpecialKey (CreateKeyInfoFromInt (c, false));
396 public bool IsSpecialKey (ConsoleKeyInfo key)
402 case ConsoleKey.Backspace:
406 case ConsoleKey.Clear:
408 case ConsoleKey.Enter:
411 if (cursorTop >= WindowHeight) {
417 // CStreamWriter will handle writing this key
423 public bool IsSpecialKey (char c)
425 return IsSpecialKey (CreateKeyInfoFromInt (c, false));
428 public ConsoleColor BackgroundColor {
444 int colour = TranslateColor (value, out light);
447 WriteConsole (String.Format (setlbgcolor, colour));
449 WriteConsole (String.Format (setbgcolor, colour));
453 public ConsoleColor ForegroundColor {
469 int colour = TranslateColor (value, out light);
472 WriteConsole (String.Format (setlfgcolor, colour));
474 WriteConsole (String.Format (setfgcolor, colour));
478 void GetCursorPosition ()
480 int row = 0, col = 0;
483 // First, get any data in the input buffer. Merely reduces the likelyhood of getting an error
484 int inqueue = ConsoleDriver.InternalKeyAvailable (0);
485 while (inqueue-- > 0){
490 // Then try to probe for the cursor coordinates
491 WriteConsole ("\x1b[6n");
492 if (ConsoleDriver.InternalKeyAvailable (1000) <= 0) {
493 noGetPosition = true;
498 while (b != '\x1b') {
500 if (ConsoleDriver.InternalKeyAvailable (100) <= 0)
507 AddToBuffer ('\x1b');
516 while ((b >= '0') && (b <= '9')) {
517 row = row * 10 + b - '0';
520 // Row/col is 0 based
528 while ((b >= '0') && (b <= '9')) {
529 col = col * 10 + b - '0';
532 // Row/col is 0 based
537 logger.WriteLine ("GetCursorPosition: {0}, {1}", col, row);
545 public int BufferHeight {
551 CheckWindowDimensions ();
559 throw new NotSupportedException ();
563 public int BufferWidth {
569 CheckWindowDimensions ();
577 throw new NotSupportedException ();
581 public bool CapsLock {
590 public int CursorLeft {
603 SetCursorPosition (value, CursorTop);
607 public int CursorTop {
620 SetCursorPosition (CursorLeft, value);
624 public bool CursorVisible {
630 return cursorVisible;
637 cursorVisible = value;
638 WriteConsole ((value ? csrVisible : csrInvisible));
642 // we have CursorNormal vs. CursorVisible...
644 public int CursorSize {
659 public bool KeyAvailable {
665 return (writepos > readpos || ConsoleDriver.InternalKeyAvailable (0) > 0);
669 // We don't know these next 2 values, so return something reasonable
670 public int LargestWindowHeight {
671 get { return WindowHeight; }
674 public int LargestWindowWidth {
675 get { return WindowWidth; }
678 public bool NumberLock {
688 public string Title {
702 WriteConsole (String.Format (titleFormat, value));
706 public bool TreatControlCAsInput {
711 return controlCAsInput;
718 if (controlCAsInput == value)
721 ConsoleDriver.SetBreak (value);
722 controlCAsInput = value;
727 // Requries that caller calls Init () if not !inited.
729 unsafe void CheckWindowDimensions ()
731 if (native_terminal_size == null || terminal_size == *native_terminal_size)
734 if (*native_terminal_size == -1){
735 int c = reader.Get (TermInfoNumbers.Columns);
739 c = reader.Get (TermInfoNumbers.Lines);
743 terminal_size = *native_terminal_size;
744 windowWidth = terminal_size >> 16;
745 windowHeight = terminal_size & 0xffff;
747 bufferHeight = windowHeight;
748 bufferWidth = windowWidth;
752 public int WindowHeight {
758 CheckWindowDimensions ();
766 throw new NotSupportedException ();
770 public int WindowLeft {
776 //CheckWindowDimensions ();
784 throw new NotSupportedException ();
788 public int WindowTop {
794 //CheckWindowDimensions ();
802 throw new NotSupportedException ();
806 public int WindowWidth {
812 CheckWindowDimensions ();
820 throw new NotSupportedException ();
830 WriteConsole (clear);
835 public void Beep (int frequency, int duration)
844 public void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
845 int targetLeft, int targetTop, Char sourceChar,
846 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
852 throw new NotImplementedException ();
855 void AddToBuffer (int b)
857 if (buffer == null) {
858 buffer = new char [1024];
859 } else if (writepos >= buffer.Length) {
860 char [] newbuf = new char [buffer.Length * 2];
861 Buffer.BlockCopy (buffer, 0, newbuf, 0, buffer.Length);
865 buffer [writepos++] = (char) b;
870 if (readpos >= writepos) {
871 readpos = writepos = 0;
875 ConsoleKeyInfo CreateKeyInfoFromInt (int n, bool alt)
878 ConsoleKey key = (ConsoleKey)n;
884 key = ConsoleKey.Enter;
887 key = ConsoleKey.Spacebar;
890 key = ConsoleKey.Subtract;
893 key = ConsoleKey.Add;
896 key = ConsoleKey.Divide;
899 key = ConsoleKey.Multiply;
901 case 8: case 9: case 12: case 13: case 19:
902 /* Values in ConsoleKey */
905 key = ConsoleKey.Escape;
909 if (n >= 1 && n <= 26) {
910 // For Ctrl-a to Ctrl-z.
912 key = ConsoleKey.A + n - 1;
913 } else if (n >= 'a' && n <= 'z') {
914 key = ConsoleKey.A - 'a' + n;
915 } else if (n >= 'A' && n <= 'Z') {
917 } else if (n >= '0' && n <= '9') {
923 return new ConsoleKeyInfo (c, key, shift, alt, ctrl);
926 object GetKeyFromBuffer (bool cooked)
928 if (readpos >= writepos)
931 int next = buffer [readpos];
932 if (!cooked || !rootmap.StartsWith (next)) {
935 return CreateKeyInfoFromInt (next, false);
939 TermInfoStrings str = rootmap.Match (buffer, readpos, writepos - readpos, out used);
940 if ((int) str == -1){
941 // Escape sequences: alt keys are sent as ESC-key
942 if (buffer [readpos] == 27 && (writepos - readpos) >= 2){
945 if (buffer [readpos+1] == 127)
946 return new ConsoleKeyInfo ((char)8, ConsoleKey.Backspace, false, true, false);
947 return CreateKeyInfoFromInt (buffer [readpos+1], true);
953 if (keymap [str] != null) {
954 key = (ConsoleKeyInfo) keymap [str];
958 return CreateKeyInfoFromInt (next, false);
966 ConsoleKeyInfo ReadKeyInternal (out bool fresh)
975 if ((o = GetKeyFromBuffer (true)) == null) {
977 if (ConsoleDriver.InternalKeyAvailable (150) > 0) {
979 AddToBuffer (stdin.Read ());
980 } while (ConsoleDriver.InternalKeyAvailable (0) > 0);
981 } else if (stdin.DataAvailable ()) {
983 AddToBuffer (stdin.Read ());
984 } while (stdin.DataAvailable ());
986 if ((o = GetKeyFromBuffer (false)) != null)
989 AddToBuffer (stdin.Read ());
992 o = GetKeyFromBuffer (true);
995 // freshly read character
998 // this char was pre-buffered (e.g. not fresh)
1002 return (ConsoleKeyInfo) o;
1005 #region Input echoing optimization
1006 bool InputPending ()
1008 // check if we've got pending input we can read immediately
1009 return readpos < writepos || stdin.DataAvailable ();
1012 char [] echobuf = null;
1015 // Queues a character to be echo'd back to the console
1016 void QueueEcho (char c)
1018 if (echobuf == null)
1019 echobuf = new char [1024];
1021 echobuf[echon++] = c;
1023 if (echon == echobuf.Length || !InputPending ()) {
1024 // blit our echo buffer to the console
1025 stdout.InternalWriteChars (echobuf, echon);
1030 // Queues a key to be echo'd back to the console
1031 void Echo (ConsoleKeyInfo key)
1033 if (!IsSpecialKey (key)) {
1034 QueueEcho (key.KeyChar);
1038 // flush pending echo's
1041 WriteSpecialKey (key);
1044 // Flush the pending echo queue
1050 // flush our echo buffer to the console
1051 stdout.InternalWriteChars (echobuf, echon);
1056 public int Read ([In, Out] char [] dest, int index, int count)
1058 bool fresh, echo = false;
1061 int BoL = 0; // Beginning-of-Line marker (can't backspace beyond this)
1065 sbuf = new StringBuilder ();
1067 // consume buffered keys first (do not echo, these have already been echo'd)
1069 if ((o = GetKeyFromBuffer (true)) == null)
1072 key = (ConsoleKeyInfo) o;
1075 if (key.Key != ConsoleKey.Backspace) {
1076 if (key.Key == ConsoleKey.Enter)
1080 } else if (sbuf.Length > BoL) {
1085 // continue reading until Enter is hit
1086 rl_startx = cursorLeft;
1087 rl_starty = cursorTop;
1090 key = ReadKeyInternal (out fresh);
1091 echo = echo || fresh;
1094 if (key.Key != ConsoleKey.Backspace) {
1095 if (key.Key == ConsoleKey.Enter)
1099 } else if (sbuf.Length > BoL) {
1105 // echo fresh keys back to the console
1108 } while (key.Key != ConsoleKey.Enter);
1115 // copy up to count chars into dest
1117 while (count > 0 && nread < sbuf.Length) {
1118 dest[index + nread] = sbuf[nread];
1123 // put the rest back into our key buffer
1124 for (int i = nread; i < sbuf.Length; i++)
1125 AddToBuffer (sbuf[i]);
1130 public ConsoleKeyInfo ReadKey (bool intercept)
1134 ConsoleKeyInfo key = ReadKeyInternal (out fresh);
1136 if (!intercept && fresh) {
1137 // echo the fresh key back to the console
1145 public string ReadLine ()
1150 // Hack to make Iron Python work (since it goes behind our backs
1151 // when writing to the console thus preventing us from keeping
1152 // cursor state normally).
1153 GetCursorPosition ();
1155 StringBuilder builder = new StringBuilder ();
1156 bool fresh, echo = false;
1160 rl_startx = cursorLeft;
1161 rl_starty = cursorTop;
1162 char eof = (char) control_characters [ControlCharacters.EOF];
1165 key = ReadKeyInternal (out fresh);
1166 echo = echo || fresh;
1168 // EOF -> Ctrl-D (EOT) pressed.
1169 if (c == eof && c != 0 && builder.Length == 0)
1172 if (key.Key != ConsoleKey.Enter) {
1173 if (key.Key != ConsoleKey.Backspace) {
1175 } else if (builder.Length > 0) {
1178 // skips over echoing the key to the console
1183 // echo fresh keys back to the console
1186 } while (key.Key != ConsoleKey.Enter);
1193 return builder.ToString ();
1196 public void ResetColor ()
1202 string str = (origPair != null) ? origPair : origColors;
1206 public void SetBufferSize (int width, int height)
1212 throw new NotImplementedException (String.Empty);
1215 public void SetCursorPosition (int left, int top)
1221 CheckWindowDimensions ();
1222 if (left < 0 || left >= bufferWidth)
1223 throw new ArgumentOutOfRangeException ("left", "Value must be positive and below the buffer width.");
1225 if (top < 0 || top >= bufferHeight)
1226 throw new ArgumentOutOfRangeException ("top", "Value must be positive and below the buffer height.");
1228 // Either CursorAddress or nothing.
1229 // We might want to play with up/down/left/right/home when ca is not available.
1230 if (cursorAddress == null)
1231 throw new NotSupportedException ("This terminal does not suport setting the cursor position.");
1233 int one = (home_1_1 ? 1 : 0);
1234 WriteConsole (String.Format (cursorAddress, top + one, left + one));
1239 public void SetWindowPosition (int left, int top)
1245 // No need to throw exceptions here.
1246 //throw new NotSupportedException ();
1249 public void SetWindowSize (int width, int height)
1255 // No need to throw exceptions here.
1256 //throw new NotSupportedException ();
1260 void CreateKeyMap ()
1262 keymap = new Hashtable ();
1264 keymap [TermInfoStrings.KeyBackspace] = new ConsoleKeyInfo ('\0', ConsoleKey.Backspace, false, false, false);
1265 keymap [TermInfoStrings.KeyClear] = new ConsoleKeyInfo ('\0', ConsoleKey.Clear, false, false, false);
1266 // Delete character...
1267 keymap [TermInfoStrings.KeyDown] = new ConsoleKeyInfo ('\0', ConsoleKey.DownArrow, false, false, false);
1268 keymap [TermInfoStrings.KeyF1] = new ConsoleKeyInfo ('\0', ConsoleKey.F1, false, false, false);
1269 keymap [TermInfoStrings.KeyF10] = new ConsoleKeyInfo ('\0', ConsoleKey.F10, false, false, false);
1270 keymap [TermInfoStrings.KeyF2] = new ConsoleKeyInfo ('\0', ConsoleKey.F2, false, false, false);
1271 keymap [TermInfoStrings.KeyF3] = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, false, false);
1272 keymap [TermInfoStrings.KeyF4] = new ConsoleKeyInfo ('\0', ConsoleKey.F4, false, false, false);
1273 keymap [TermInfoStrings.KeyF5] = new ConsoleKeyInfo ('\0', ConsoleKey.F5, false, false, false);
1274 keymap [TermInfoStrings.KeyF6] = new ConsoleKeyInfo ('\0', ConsoleKey.F6, false, false, false);
1275 keymap [TermInfoStrings.KeyF7] = new ConsoleKeyInfo ('\0', ConsoleKey.F7, false, false, false);
1276 keymap [TermInfoStrings.KeyF8] = new ConsoleKeyInfo ('\0', ConsoleKey.F8, false, false, false);
1277 keymap [TermInfoStrings.KeyF9] = new ConsoleKeyInfo ('\0', ConsoleKey.F9, false, false, false);
1278 keymap [TermInfoStrings.KeyHome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
1279 keymap [TermInfoStrings.KeyLeft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, false, false, false);
1280 keymap [TermInfoStrings.KeyLl] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
1281 keymap [TermInfoStrings.KeyNpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
1282 keymap [TermInfoStrings.KeyPpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
1283 keymap [TermInfoStrings.KeyRight] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, false, false, false);
1284 keymap [TermInfoStrings.KeySf] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
1285 keymap [TermInfoStrings.KeySr] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
1286 keymap [TermInfoStrings.KeyUp] = new ConsoleKeyInfo ('\0', ConsoleKey.UpArrow, false, false, false);
1287 keymap [TermInfoStrings.KeyA1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad7, false, false, false);
1288 keymap [TermInfoStrings.KeyA3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad9, false, false, false);
1289 keymap [TermInfoStrings.KeyB2] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad5, false, false, false);
1290 keymap [TermInfoStrings.KeyC1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
1291 keymap [TermInfoStrings.KeyC3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad3, false, false, false);
1292 keymap [TermInfoStrings.KeyBtab] = new ConsoleKeyInfo ('\0', ConsoleKey.Tab, true, false, false);
1293 keymap [TermInfoStrings.KeyBeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
1294 keymap [TermInfoStrings.KeyCopy] = new ConsoleKeyInfo ('C', ConsoleKey.C, false, true, false);
1295 keymap [TermInfoStrings.KeyEnd] = new ConsoleKeyInfo ('\0', ConsoleKey.End, false, false, false);
1296 keymap [TermInfoStrings.KeyEnter] = new ConsoleKeyInfo ('\n', ConsoleKey.Enter, false, false, false);
1297 keymap [TermInfoStrings.KeyHelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, false, false, false);
1298 keymap [TermInfoStrings.KeyPrint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, false, false, false);
1299 keymap [TermInfoStrings.KeyUndo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z , false, true, false);
1300 keymap [TermInfoStrings.KeySbeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
1301 keymap [TermInfoStrings.KeyScopy] = new ConsoleKeyInfo ('C', ConsoleKey.C , true, true, false);
1302 keymap [TermInfoStrings.KeySdc] = new ConsoleKeyInfo ('\x9', ConsoleKey.Delete, true, false, false);
1303 keymap [TermInfoStrings.KeyShelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, true, false, false);
1304 keymap [TermInfoStrings.KeyShome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
1305 keymap [TermInfoStrings.KeySleft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, true, false, false);
1306 keymap [TermInfoStrings.KeySprint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, true, false, false);
1307 keymap [TermInfoStrings.KeySright] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, true, false, false);
1308 keymap [TermInfoStrings.KeySundo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z, true, false, false);
1309 keymap [TermInfoStrings.KeyF11] = new ConsoleKeyInfo ('\0', ConsoleKey.F11, false, false, false);
1310 keymap [TermInfoStrings.KeyF12] = new ConsoleKeyInfo ('\0', ConsoleKey.F12 , false, false, false);
1311 keymap [TermInfoStrings.KeyF13] = new ConsoleKeyInfo ('\0', ConsoleKey.F13, false, false, false);
1312 keymap [TermInfoStrings.KeyF14] = new ConsoleKeyInfo ('\0', ConsoleKey.F14, false, false, false);
1313 keymap [TermInfoStrings.KeyF15] = new ConsoleKeyInfo ('\0', ConsoleKey.F15, false, false, false);
1314 keymap [TermInfoStrings.KeyF16] = new ConsoleKeyInfo ('\0', ConsoleKey.F16, false, false, false);
1315 keymap [TermInfoStrings.KeyF17] = new ConsoleKeyInfo ('\0', ConsoleKey.F17, false, false, false);
1316 keymap [TermInfoStrings.KeyF18] = new ConsoleKeyInfo ('\0', ConsoleKey.F18, false, false, false);
1317 keymap [TermInfoStrings.KeyF19] = new ConsoleKeyInfo ('\0', ConsoleKey.F19, false, false, false);
1318 keymap [TermInfoStrings.KeyF20] = new ConsoleKeyInfo ('\0', ConsoleKey.F20, false, false, false);
1319 keymap [TermInfoStrings.KeyF21] = new ConsoleKeyInfo ('\0', ConsoleKey.F21, false, false, false);
1320 keymap [TermInfoStrings.KeyF22] = new ConsoleKeyInfo ('\0', ConsoleKey.F22, false, false, false);
1321 keymap [TermInfoStrings.KeyF23] = new ConsoleKeyInfo ('\0', ConsoleKey.F23, false, false, false);
1322 keymap [TermInfoStrings.KeyF24] = new ConsoleKeyInfo ('\0', ConsoleKey.F24, false, false, false);
1323 // These were previously missing:
1324 keymap [TermInfoStrings.KeyDc] = new ConsoleKeyInfo ('\0', ConsoleKey.Delete, false, false, false);
1325 keymap [TermInfoStrings.KeyIc] = new ConsoleKeyInfo ('\0', ConsoleKey.Insert, false, false, false);
1334 rootmap = new ByteMatcher ();
1337 // The keys that we know about and use
1339 var UsedKeys = new [] {
1340 TermInfoStrings.KeyBackspace,
1341 TermInfoStrings.KeyClear,
1342 TermInfoStrings.KeyDown,
1343 TermInfoStrings.KeyF1,
1344 TermInfoStrings.KeyF10,
1345 TermInfoStrings.KeyF2,
1346 TermInfoStrings.KeyF3,
1347 TermInfoStrings.KeyF4,
1348 TermInfoStrings.KeyF5,
1349 TermInfoStrings.KeyF6,
1350 TermInfoStrings.KeyF7,
1351 TermInfoStrings.KeyF8,
1352 TermInfoStrings.KeyF9,
1353 TermInfoStrings.KeyHome,
1354 TermInfoStrings.KeyLeft,
1355 TermInfoStrings.KeyLl,
1356 TermInfoStrings.KeyNpage,
1357 TermInfoStrings.KeyPpage,
1358 TermInfoStrings.KeyRight,
1359 TermInfoStrings.KeySf,
1360 TermInfoStrings.KeySr,
1361 TermInfoStrings.KeyUp,
1362 TermInfoStrings.KeyA1,
1363 TermInfoStrings.KeyA3,
1364 TermInfoStrings.KeyB2,
1365 TermInfoStrings.KeyC1,
1366 TermInfoStrings.KeyC3,
1367 TermInfoStrings.KeyBtab,
1368 TermInfoStrings.KeyBeg,
1369 TermInfoStrings.KeyCopy,
1370 TermInfoStrings.KeyEnd,
1371 TermInfoStrings.KeyEnter,
1372 TermInfoStrings.KeyHelp,
1373 TermInfoStrings.KeyPrint,
1374 TermInfoStrings.KeyUndo,
1375 TermInfoStrings.KeySbeg,
1376 TermInfoStrings.KeyScopy,
1377 TermInfoStrings.KeySdc,
1378 TermInfoStrings.KeyShelp,
1379 TermInfoStrings.KeyShome,
1380 TermInfoStrings.KeySleft,
1381 TermInfoStrings.KeySprint,
1382 TermInfoStrings.KeySright,
1383 TermInfoStrings.KeySundo,
1384 TermInfoStrings.KeyF11,
1385 TermInfoStrings.KeyF12,
1386 TermInfoStrings.KeyF13,
1387 TermInfoStrings.KeyF14,
1388 TermInfoStrings.KeyF15,
1389 TermInfoStrings.KeyF16,
1390 TermInfoStrings.KeyF17,
1391 TermInfoStrings.KeyF18,
1392 TermInfoStrings.KeyF19,
1393 TermInfoStrings.KeyF20,
1394 TermInfoStrings.KeyF21,
1395 TermInfoStrings.KeyF22,
1396 TermInfoStrings.KeyF23,
1397 TermInfoStrings.KeyF24,
1399 // These were missing
1400 TermInfoStrings.KeyDc,
1401 TermInfoStrings.KeyIc
1404 foreach (TermInfoStrings tis in UsedKeys)
1405 AddStringMapping (tis);
1407 rootmap.AddMapping (TermInfoStrings.KeyBackspace, new byte [] { control_characters [ControlCharacters.Erase] });
1412 void AddStringMapping (TermInfoStrings s)
1414 byte [] bytes = reader.GetStringBytes (s);
1418 rootmap.AddMapping (s, bytes);
1423 Hashtable map = new Hashtable ();
1424 Hashtable starts = new Hashtable ();
1426 public void AddMapping (TermInfoStrings key, byte [] val)
1428 if (val.Length == 0)
1432 starts [(int) val [0]] = true;
1439 public bool StartsWith (int c)
1441 return (starts [c] != null);
1444 public TermInfoStrings Match (char [] buffer, int offset, int length, out int used)
1446 foreach (byte [] bytes in map.Keys) {
1447 for (int i = 0; i < bytes.Length && i < length; i++) {
1448 if ((char) bytes [i] != buffer [offset + i])
1451 if (bytes.Length - 1 == i) {
1452 used = bytes.Length;
1453 return (TermInfoStrings) map [bytes];
1459 return (TermInfoStrings) (-1);