merge r67228-r67235, r67237, r67251 and r67256-67259 to trunk (they are
[mono.git] / mcs / class / corlib / System / TermInfoDriver.cs
1 //
2 // System.ConsoleDriver
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2005,2006 Novell, Inc (http://www.novell.com)
8 //
9
10 //
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:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
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.
29 //
30 #if NET_2_0
31 //#define DEBUG
32 using System.Collections;
33 using System.IO;
34 using System.Text;
35 using System.Runtime.InteropServices;
36 namespace System {
37         class TermInfoDriver : IConsoleDriver {
38                 static string [] locations = { "/etc/terminfo", "/usr/share/terminfo", "/usr/lib/terminfo" };
39
40                 TermInfoReader reader;
41                 int cursorLeft;
42                 int cursorTop;
43                 string title = String.Empty;
44                 string titleFormat = String.Empty;
45                 bool cursorVisible = true;
46                 string csrVisible;
47                 string csrInvisible;
48                 string clear;
49                 string bell;
50                 string term;
51                 Stream stdin;
52                 internal byte verase;
53                 byte vsusp;
54                 byte intr;
55
56                 int windowWidth;
57                 int windowHeight;
58                 //int windowTop;
59                 //int windowLeft;
60                 int bufferHeight;
61                 int bufferWidth;
62
63                 byte [] buffer;
64                 int readpos;
65                 int writepos;
66                 string keypadXmit, keypadLocal;
67                 bool controlCAsInput;
68                 bool inited;
69                 bool initKeys;
70                 bool noEcho;
71                 string origPair;
72                 string origColors;
73                 string cursorAddress;
74                 ConsoleColor fgcolor = ConsoleColor.White;
75                 ConsoleColor bgcolor = ConsoleColor.Black;
76                 string setafcolor; // TODO: use setforeground/setbackground if available for better
77                 string setabcolor; // color mapping.
78                 bool noGetPosition;
79                 Hashtable keymap;
80                 ByteMatcher rootmap;
81                 bool home_1_1; // if true, we have to add 1 to x and y when using cursorAddress
82                 int rl_startx = -1, rl_starty = -1;
83 #if DEBUG
84                 StreamWriter logger;
85 #endif
86
87                 static string SearchTerminfo (string term)
88                 {
89                         if (term == null || term == String.Empty)
90                                 return null;
91
92                         // Ignore TERMINFO and TERMINFO_DIRS by now
93                         //string terminfo = Environment.GetEnvironmentVariable ("TERMINFO");
94                         //string terminfoDirs = Environment.GetEnvironmentVariable ("TERMINFO_DIRS");
95
96                         foreach (string dir in locations) {
97                                 if (!Directory.Exists (dir))
98                                         continue;
99
100                                 string path = Path.Combine (dir, term.Substring (0, 1));
101                                 if (!Directory.Exists (dir))
102                                         continue;
103
104                                 path = Path.Combine (path, term);
105                                 if (!File.Exists (path))
106                                         continue;
107
108                                 return path;
109                         }
110
111                         return null;
112                 }
113
114                 static void WriteConsole (string str)
115                 {
116                         if (str == null)
117                                 return;
118
119                         ((CStreamWriter) Console.stdout).InternalWriteString (str);
120                 }
121
122                 public TermInfoDriver ()
123                         : this (Environment.GetEnvironmentVariable ("TERM"))
124                 {
125                 }
126
127                 public TermInfoDriver (string term)
128                 {
129 #if DEBUG
130                         File.Delete ("console.log");
131                         logger = new StreamWriter (File.OpenWrite ("console.log"));
132 #endif
133                         this.term = term;
134
135                         if (term == "xterm") {
136                                 reader = new TermInfoReader (term, KnownTerminals.xterm);
137                         } else if (term == "linux") {
138                                 reader = new TermInfoReader (term, KnownTerminals.linux);
139                         } else {
140                                 string filename = SearchTerminfo (term);
141                                 if (filename != null)
142                                         reader = new TermInfoReader (term, filename);
143                         }
144
145                         if (reader == null)
146                                 reader = new TermInfoReader (term, KnownTerminals.ansi);
147                 }
148
149                 public bool Initialized {
150                         get { return inited; }
151                 }
152                 
153                 public void Init ()
154                 {
155                         if (inited)
156                                 return;
157                         
158                         /* This should not happen any more, since it is checked for in Console */
159                         if (!ConsoleDriver.IsConsole)
160                                 throw new IOException ("Not a tty.");
161
162                         inited = true;
163                         ConsoleDriver.SetEcho (false);
164                         string endString = null;
165                         keypadXmit = reader.Get (TermInfoStrings.KeypadXmit);
166                         keypadLocal = reader.Get (TermInfoStrings.KeypadLocal);
167                         if (keypadXmit != null) {
168                                 WriteConsole (keypadXmit); // Needed to get the arrows working
169                                 if (keypadLocal != null)
170                                         endString += keypadLocal;
171                         }
172
173                         origPair = reader.Get (TermInfoStrings.OrigPair);
174                         origColors = reader.Get (TermInfoStrings.OrigColors);
175                         setafcolor = MangleParameters (reader.Get (TermInfoStrings.SetAForeground));
176                         setabcolor = MangleParameters (reader.Get (TermInfoStrings.SetABackground));
177                         string resetColors = (origColors == null) ? origPair : origColors;
178                         if (resetColors != null)
179                                 endString += resetColors;
180
181                         if (!ConsoleDriver.TtySetup (endString, out verase, out vsusp, out intr))
182                                 throw new IOException ("Error initializing terminal.");
183
184                         stdin = Console.OpenStandardInput (0);
185                         clear = reader.Get (TermInfoStrings.ClearScreen);
186                         bell = reader.Get (TermInfoStrings.Bell);
187                         if (clear == null) {
188                                 clear = reader.Get (TermInfoStrings.CursorHome);
189                                 clear += reader.Get (TermInfoStrings.ClrEos);
190                         }
191
192                         csrVisible = reader.Get (TermInfoStrings.CursorNormal);
193                         if (csrVisible == null)
194                                 csrVisible = reader.Get (TermInfoStrings.CursorVisible);
195
196                         csrInvisible = reader.Get (TermInfoStrings.CursorInvisible);
197                         if (term == "cygwin" || term == "linux" || (term != null && term.StartsWith ("xterm")) ||
198                                 term == "rxvt" || term == "dtterm") {
199                                 titleFormat = "\x1b]0;{0}\x7"; // icon + window title
200                         } else if (term == "iris-ansi") {
201                                 titleFormat = "\x1bP1.y{0}\x1b\\"; // not tested
202                         } else if (term == "sun-cmd") {
203                                 titleFormat = "\x1b]l{0}\x1b\\"; // not tested
204                         }
205
206                         cursorAddress = reader.Get (TermInfoStrings.CursorAddress);
207                         if (cursorAddress != null) {
208                                 string result = cursorAddress.Replace ("%i", String.Empty);
209                                 home_1_1 = (cursorAddress != result);
210                                 cursorAddress = MangleParameters (result);
211                         }
212
213                         GetCursorPosition ();
214 #if DEBUG
215                         logger.WriteLine ("noGetPosition: {0} left: {1} top: {2}", noGetPosition, cursorLeft, cursorTop);
216                         logger.Flush ();
217 #endif
218                         if (noGetPosition) {
219                                 WriteConsole (clear);
220                                 cursorLeft = 0;
221                                 cursorTop = 0;
222                         }
223                 }
224
225                 static string MangleParameters (string str)
226                 {
227                         if (str == null)
228                                 return null;
229
230                         str = str.Replace ("{", "{{");
231                         str = str.Replace ("}", "}}");
232                         str = str.Replace ("%p1%d", "{0}");
233                         return str.Replace ("%p2%d", "{1}");
234                 }
235
236                 static int TranslateColor (ConsoleColor desired)
237                 {
238                         switch (desired) {
239                         case ConsoleColor.Black:
240                         case ConsoleColor.DarkGray:
241                                 return 0;
242                         case ConsoleColor.DarkBlue:
243                         case ConsoleColor.Blue:
244                                 return 4;
245                         case ConsoleColor.DarkGreen:
246                         case ConsoleColor.Green:
247                                 return 2;
248                         case ConsoleColor.DarkCyan:
249                         case ConsoleColor.Cyan:
250                                 return 6;
251                         case ConsoleColor.DarkRed:
252                         case ConsoleColor.Red:
253                                 return 1;
254                         case ConsoleColor.DarkMagenta:
255                         case ConsoleColor.Magenta:
256                                 return 5;
257                         case ConsoleColor.DarkYellow:
258                         case ConsoleColor.Yellow:
259                                 return 3;
260                         case ConsoleColor.Gray:
261                         case ConsoleColor.White:
262                                 return 7;
263                         }
264
265                         return 0;
266                 }
267
268                 void IncrementX ()
269                 {
270                         cursorLeft++;
271                         if (cursorLeft >= WindowWidth) {
272                                 cursorTop++;
273                                 cursorLeft = 0;
274                                 if (cursorTop >= WindowHeight) {
275                                         // Writing beyond the initial screen
276                                         if (rl_starty != -1) rl_starty--;
277                                         cursorTop--;
278                                 }
279                         }
280                 }
281
282                 public bool NotifyWrite (ConsoleKeyInfo key)
283                 {
284                         switch (key.Key) {
285                         case ConsoleKey.Backspace:
286                                 if (cursorLeft > 0) {
287                                         if (cursorLeft <= rl_startx && cursorTop == rl_starty)
288                                                 return false;
289                                         cursorLeft--;
290                                         SetCursorPosition (cursorLeft, cursorTop);
291                                         WriteConsole (" ");
292                                         SetCursorPosition (cursorLeft, cursorTop);
293                                 }
294 #if DEBUG
295                                 logger.WriteLine ("BS left: {0} top: {1}", cursorLeft, cursorTop);
296                                 logger.Flush ();
297 #endif
298                                 return false;
299                         case ConsoleKey.Tab:
300                                 int n = 8 - (cursorLeft % 8);
301                                 for (int i = 0; i < n; i++) IncrementX ();
302                                 return true;
303                         case ConsoleKey.Clear:
304                                 return false;
305                         case ConsoleKey.Enter:
306                                 cursorLeft = 0;
307                                 cursorTop++;
308                                 if (cursorTop >= WindowHeight) {
309                                         cursorTop--;
310                                         //TODO: scroll up
311                                 }
312 #if DEBUG
313                                 logger.WriteLine ("ENTER left: {0} top: {1}", cursorLeft, cursorTop);
314                                 logger.Flush ();
315 #endif
316                                 return true;
317                         }
318                         IncrementX ();
319 #if DEBUG
320                         logger.WriteLine ("left: {0} top: {1}", cursorLeft, cursorTop);
321                         logger.Flush ();
322 #endif
323                         return true;
324                 }
325
326                 public bool NotifyWrite (char val)
327                 {
328                         return NotifyWrite (CreateKeyInfoFromInt (val));
329                 }
330
331                 public ConsoleColor BackgroundColor {
332                         get { return bgcolor; }
333                         set {
334                                 bgcolor = value;
335                                 WriteConsole (String.Format (setabcolor, TranslateColor (value)));
336                         }
337                 }
338
339                 public ConsoleColor ForegroundColor {
340                         get { return fgcolor; }
341                         set {
342                                 fgcolor = value;
343                                 WriteConsole (String.Format (setafcolor, TranslateColor (value)));
344                         }
345                 }
346
347                 // Only used once.
348                 void GetCursorPosition ()
349                 {
350                         int row = 0, col = 0;
351                         bool prevEcho = Echo;
352                         Echo = false;
353                         try {
354                                 WriteConsole ("\x1b[6n");
355                                 if (ConsoleDriver.InternalKeyAvailable (1000) <= 0) {
356                                         noGetPosition = true;
357                                         return;
358                                 }
359
360                                 int b = stdin.ReadByte ();
361                                 while (b != '\x1b') {
362                                         AddToBuffer (b);
363                                         if (ConsoleDriver.InternalKeyAvailable (100) <= 0)
364                                                 return;
365                                         b = stdin.ReadByte ();
366                                 }
367
368                                 b = stdin.ReadByte ();
369                                 if (b != '[') {
370                                         AddToBuffer ('\x1b');
371                                         AddToBuffer (b);
372                                         return;
373                                 }
374
375                                 b = stdin.ReadByte ();
376                                 if (b != ';') {
377                                         row = b - '0';
378                                         b = stdin.ReadByte ();
379                                         while ((b >= '0') && (b <= '9')) {
380                                                 row = row * 10 + b - '0';
381                                                 b = stdin.ReadByte ();
382                                         }
383                                         // Row/col is 0 based
384                                         row --;
385                                 }
386
387                                 b = stdin.ReadByte ();
388                                 if (b != 'R') {
389                                         col = b - '0';
390                                         b = stdin.ReadByte ();
391                                         while ((b >= '0') && (b <= '9')) {
392                                                 col = col * 10 + b - '0';
393                                                 b = stdin.ReadByte ();
394                                         }
395                                         // Row/col is 0 based
396                                         col --;
397                                 }
398                         } finally {
399                                 Echo = prevEcho;
400                         }
401
402                         cursorLeft = col;
403                         cursorTop = row;
404                 }
405
406                 public int BufferHeight {
407                         get {
408                                 return bufferHeight;
409                         }
410                         set {
411                                 throw new NotSupportedException ();
412                         }
413                 }
414
415                 public int BufferWidth {
416                         get {
417                                 return bufferWidth;
418                         }
419                         set {
420                                 throw new NotSupportedException ();
421                         }
422                 }
423
424                 public bool CapsLock {
425                         get { throw new NotSupportedException (); }
426                 }
427
428                 public int CursorLeft {
429                         get {
430                                 return cursorLeft;
431                         }
432                         set {
433                                 SetCursorPosition (value, CursorTop);
434                                 cursorLeft = value;
435                         }
436                 }
437
438                 public int CursorTop {
439                         get {
440                                 return cursorTop;
441                         }
442                         set {
443                                 SetCursorPosition (CursorLeft, value);
444                                 cursorTop = value;
445                         }
446                 }
447
448                 public bool CursorVisible {
449                         get {
450                                 return cursorVisible;
451                         }
452                         set {
453                                 cursorVisible = value;
454                                 WriteConsole ((value ? csrVisible : csrInvisible));
455                         }
456                 }
457
458                 // we have CursorNormal vs. CursorVisible...
459                 [MonoTODO]
460                 public int CursorSize {
461                         get { return 1; }
462                         set {}
463                 }
464
465                 public bool Echo {
466                         get { return !noEcho; }
467                         set {
468                                 if (value != noEcho)
469                                         return;
470
471                                 noEcho = !value;
472                         }
473                 }
474
475                 public bool KeyAvailable {
476                         get {
477                                 return (writepos > readpos || ConsoleDriver.InternalKeyAvailable (0) > 0);
478                         }
479                 }
480
481                 // We don't know these next 2 values, so return something reasonable
482                 public int LargestWindowHeight {
483                         get { return WindowHeight; }
484                 }
485
486                 public int LargestWindowWidth {
487                         get { return WindowWidth; }
488                 }
489
490                 public bool NumberLock {
491                         get { throw new NotSupportedException (); }
492                 }
493
494                 public string Title {
495                         get { return title; }
496                         
497                         set {
498                                 title = value;
499                                 WriteConsole (String.Format (titleFormat, value));
500                         }
501                 }
502
503                 public bool TreatControlCAsInput {
504                         get { return controlCAsInput; }
505                         set {
506                                 if (controlCAsInput == value)
507                                         return;
508
509                                 ConsoleDriver.SetBreak (value);
510                                 controlCAsInput = value;
511                         }
512                 }
513
514                 // TODO: use this at the beginning and on every SIGWINCH
515                 void GetWindowDimensions ()
516                 {
517                         /* Try the ioctl first */
518                         if (!ConsoleDriver.GetTtySize (MonoIO.ConsoleOutput, out windowWidth, out windowHeight)) {
519                                 windowWidth = reader.Get (TermInfoNumbers.Columns);
520                                 string env = Environment.GetEnvironmentVariable ("COLUMNS");
521                                 if (env != null) {
522                                         try {
523                                                 windowWidth = (int) UInt32.Parse (env);
524                                         } catch {
525                                         }
526                                 }
527
528                                 windowHeight = reader.Get (TermInfoNumbers.Lines);
529                                 env = Environment.GetEnvironmentVariable ("LINES");
530                                 if (env != null) {
531                                         try {
532                                                 windowHeight = (int) UInt32.Parse (env);
533                                         } catch {
534                                         }
535                                 }
536                         }
537
538                         bufferHeight = windowHeight;
539                         bufferWidth = windowWidth;
540                 }
541
542                 public int WindowHeight {
543                         get {
544                                 GetWindowDimensions ();
545                                 return windowHeight;
546                         }
547                         set {
548                                 throw new NotSupportedException ();
549                         }
550                 }
551
552                 public int WindowLeft {
553                         get {
554                                 //GetWindowDimensions ();
555                                 return 0;
556                         }
557                         set {
558                                 throw new NotSupportedException ();
559                         }
560                 }
561
562                 public int WindowTop {
563                         get {
564                                 //GetWindowDimensions ();
565                                 return 0;
566                         }
567                         set {
568                                 throw new NotSupportedException ();
569                         }
570                 }
571
572                 public int WindowWidth {
573                         get {
574                                 GetWindowDimensions ();
575                                 return windowWidth;
576                         }
577                         set {
578                                 throw new NotSupportedException ();
579                         }
580                 }
581
582                 public void Clear ()
583                 {
584                         WriteConsole (clear);
585                 }
586
587                 public void Beep (int frequency, int duration)
588                 {
589                         WriteConsole (bell);
590                 }
591
592                 public void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
593                                         int targetLeft, int targetTop, Char sourceChar,
594                                         ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
595                 {
596                         throw new NotImplementedException ();
597                 }
598
599                 void AddToBuffer (int b)
600                 {
601                         if (buffer == null)
602                                 buffer = new byte [1024];
603
604                         buffer [writepos++] = (byte) b;
605                 }
606
607                 ConsoleKeyInfo CreateKeyInfoFromInt (int n)
608                 {
609                         char c = (char) n;
610                         ConsoleKey key = (ConsoleKey)n;
611                         bool shift = false;
612                         bool ctrl = false;
613                         bool alt = false;
614
615                         if (n == 10) {
616                                 key = ConsoleKey.Enter;
617                         } else if (n == 8 || n == 9 || n == 12 || n == 13 || n == 19) {
618                                 /* Values in ConsoleKey */
619                         } else if (n >= 1 && n <= 26) {
620                                 // For Ctrl-a to Ctrl-z.
621                                 ctrl = true;
622                                 key = ConsoleKey.A + n - 1;
623                         } else if (n == 27) {
624                                 key = ConsoleKey.Escape;
625                         } else if (n >= 'a' && n <= 'z') {
626                                 key = ConsoleKey.A - 'a' + n;
627                         } else if (n >= 'A' && n <= 'Z') {
628                                 shift = true;
629                         } else if (n >= '0' && n <= '9') {
630                         } else {
631                                 key = 0;
632                         }
633
634                         return new ConsoleKeyInfo (c, key, shift, alt, ctrl);
635                 }
636
637                 object GetKeyFromBuffer (bool cooked)
638                 {
639                         if (readpos >= writepos)
640                                 return null;
641
642                         int next = buffer [readpos];
643                         if (!cooked || !rootmap.StartsWith (next)) {
644                                 readpos++;
645                                 return CreateKeyInfoFromInt (next);
646                         }
647
648                         int used;
649                         TermInfoStrings str = rootmap.Match (buffer, readpos, writepos - readpos, out used);
650                         if ((int) str == -1)
651                                 return null;
652
653                         ConsoleKeyInfo key;
654                         if (keymap [str] != null) {
655                                 key = (ConsoleKeyInfo) keymap [str];
656                         } else {
657                                 readpos++;
658                                 return CreateKeyInfoFromInt (next);
659                         }
660
661                         readpos += used;
662                         if (readpos >= writepos)
663                                 readpos = writepos = 0;
664
665                         return key;
666                 }
667
668                 ConsoleKeyInfo ReadKeyInternal ()
669                 {
670                         InitKeys ();
671                         object o = null;
672                         while (o == null) {
673                                 o = GetKeyFromBuffer (true);
674                                 if (o == null) {
675                                         if (ConsoleDriver.InternalKeyAvailable (150) > 0) {
676                                                 do {
677                                                         AddToBuffer (stdin.ReadByte ());
678                                                 } while (ConsoleDriver.InternalKeyAvailable (0) > 0);
679                                         } else {
680                                                 o = GetKeyFromBuffer (false);
681                                                 if (o == null)
682                                                         AddToBuffer (stdin.ReadByte ());
683                                         }
684                                 }
685                         }
686
687                         return (ConsoleKeyInfo) o;
688                 }
689
690                 public ConsoleKeyInfo ReadKey (bool intercept)
691                 {
692                         bool prevEcho = Echo;
693                         if (prevEcho == intercept)
694                                 Echo  = !intercept;
695
696                         ConsoleKeyInfo key = ReadKeyInternal ();
697                         if (prevEcho == intercept)
698                                 Echo = prevEcho;
699
700                         return key;
701                 }
702
703                 public string ReadLine ()
704                 {
705                         bool prevEcho = Echo;
706                         if (prevEcho == false)
707                                 Echo  = true;
708                         StringBuilder builder = new StringBuilder ();
709                         bool exit = false;
710                         CStreamWriter writer = Console.stdout as CStreamWriter;
711                         rl_startx = cursorLeft;
712                         rl_starty = cursorLeft;
713                         do {
714                                 ConsoleKeyInfo key = ReadKeyInternal ();
715                                 char c = key.KeyChar;
716                                 exit = (c == '\n');
717                                 if (!exit)
718                                         builder.Append (c);
719                                 if (writer != null)
720                                         writer.WriteKey (key);
721                                 else
722                                         Console.stdout.Write (c);
723                         } while (!exit);
724                         if (prevEcho == false)
725                                 Echo = prevEcho;
726                         rl_startx = -1;
727                         rl_starty = -1;
728                         return builder.ToString ();
729                 }
730
731                 public void ResetColor ()
732                 {
733                         string str = (origPair != null) ? origPair : origColors;
734                         WriteConsole (str);
735                 }
736
737                 public void SetBufferSize (int width, int height)
738                 {
739                         throw new NotImplementedException (String.Empty);
740                 }
741
742                 public void SetCursorPosition (int left, int top)
743                 {
744                         if (bufferWidth == 0)
745                                 GetWindowDimensions ();
746
747                         if (left < 0 || left >= bufferWidth)
748                                 throw new ArgumentOutOfRangeException ("left", "Value must be positive and below the buffer width.");
749
750                         if (top < 0 || top >= bufferHeight)
751                                 throw new ArgumentOutOfRangeException ("top", "Value must be positive and below the buffer height.");
752
753                         // Either CursorAddress or nothing.
754                         // We might want to play with up/down/left/right/home when ca is not available.
755                         if (cursorAddress == null)
756                                 throw new NotSupportedException ("This terminal does not suport setting the cursor position.");
757
758                         int one = (home_1_1 ? 1 : 0);
759                         WriteConsole (String.Format (cursorAddress, top + one, left + one));
760                         cursorLeft = left;
761                         cursorTop = top;
762                 }
763
764                 public void SetWindowPosition (int left, int top)
765                 {
766                         // No need to throw exceptions here.
767                         //throw new NotSupportedException ();
768                 }
769
770                 public void SetWindowSize (int width, int height)
771                 {
772                         // No need to throw exceptions here.
773                         //throw new NotSupportedException ();
774                 }
775
776
777                 void CreateKeyMap ()
778                 {
779                         keymap = new Hashtable ();
780                         keymap [TermInfoStrings.KeyBackspace] = new ConsoleKeyInfo ('\0', ConsoleKey.Backspace, false, false, false);
781                         keymap [TermInfoStrings.KeyClear] = new ConsoleKeyInfo ('\0', ConsoleKey.Clear, false, false, false);
782                         // Delete character...
783                         keymap [TermInfoStrings.KeyDown] = new ConsoleKeyInfo ('\0', ConsoleKey.DownArrow, false, false, false);
784                         keymap [TermInfoStrings.KeyF1] = new ConsoleKeyInfo ('\0', ConsoleKey.F1, false, false, false);
785                         keymap [TermInfoStrings.KeyF10] = new ConsoleKeyInfo ('\0', ConsoleKey.F10, false, false, false);
786                         keymap [TermInfoStrings.KeyF2] = new ConsoleKeyInfo ('\0', ConsoleKey.F2, false, false, false);
787                         keymap [TermInfoStrings.KeyF3] = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, false, false);
788                         keymap [TermInfoStrings.KeyF4] = new ConsoleKeyInfo ('\0', ConsoleKey.F4, false, false, false);
789                         keymap [TermInfoStrings.KeyF5] = new ConsoleKeyInfo ('\0', ConsoleKey.F5, false, false, false);
790                         keymap [TermInfoStrings.KeyF6] = new ConsoleKeyInfo ('\0', ConsoleKey.F6, false, false, false);
791                         keymap [TermInfoStrings.KeyF7] = new ConsoleKeyInfo ('\0', ConsoleKey.F7, false, false, false);
792                         keymap [TermInfoStrings.KeyF8] = new ConsoleKeyInfo ('\0', ConsoleKey.F8, false, false, false);
793                         keymap [TermInfoStrings.KeyF9] = new ConsoleKeyInfo ('\0', ConsoleKey.F9, false, false, false);
794                         keymap [TermInfoStrings.KeyHome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
795
796                         keymap [TermInfoStrings.KeyLeft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, false, false, false);
797                         keymap [TermInfoStrings.KeyLl] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
798                         keymap [TermInfoStrings.KeyNpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
799                         keymap [TermInfoStrings.KeyPpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
800                         keymap [TermInfoStrings.KeyRight] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, false, false, false);
801                         keymap [TermInfoStrings.KeySf] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
802                         keymap [TermInfoStrings.KeySr] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
803                         keymap [TermInfoStrings.KeyUp] = new ConsoleKeyInfo ('\0', ConsoleKey.UpArrow, false, false, false);
804                         keymap [TermInfoStrings.KeyA1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad7, false, false, false);
805                         keymap [TermInfoStrings.KeyA3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad9, false, false, false);
806                         keymap [TermInfoStrings.KeyB2] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad5, false, false, false);
807                         keymap [TermInfoStrings.KeyC1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
808                         keymap [TermInfoStrings.KeyC3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad3, false, false, false);
809                         keymap [TermInfoStrings.KeyBtab] = new ConsoleKeyInfo ('\0', ConsoleKey.Tab, true, false, false);
810                         keymap [TermInfoStrings.KeyBeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
811                         keymap [TermInfoStrings.KeyCopy] = new ConsoleKeyInfo ('C', ConsoleKey.C, false, true, false);
812                         keymap [TermInfoStrings.KeyEnd] = new ConsoleKeyInfo ('\0', ConsoleKey.End, false, false, false);
813                         keymap [TermInfoStrings.KeyEnter] = new ConsoleKeyInfo ('\n', ConsoleKey.Enter, false, false, false);
814                         keymap [TermInfoStrings.KeyHelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, false, false, false);
815                         keymap [TermInfoStrings.KeyPrint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, false, false, false);
816                         keymap [TermInfoStrings.KeyUndo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z , false, true, false);
817                         keymap [TermInfoStrings.KeySbeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
818                         keymap [TermInfoStrings.KeyScopy] = new ConsoleKeyInfo ('C', ConsoleKey.C , true, true, false);
819                         keymap [TermInfoStrings.KeySdc] = new ConsoleKeyInfo ('\x9', ConsoleKey.Delete, true, false, false);
820                         keymap [TermInfoStrings.KeyShelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, true, false, false);
821                         keymap [TermInfoStrings.KeyShome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
822                         keymap [TermInfoStrings.KeySleft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, true, false, false);
823                         keymap [TermInfoStrings.KeySprint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, true, false, false);
824                         keymap [TermInfoStrings.KeySright] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, true, false, false);
825                         keymap [TermInfoStrings.KeySundo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z, true, false, false);
826                         keymap [TermInfoStrings.KeyF11] = new ConsoleKeyInfo ('\0', ConsoleKey.F11, false, false, false);
827                         keymap [TermInfoStrings.KeyF12] = new ConsoleKeyInfo ('\0', ConsoleKey.F12 , false, false, false);
828                         keymap [TermInfoStrings.KeyF13] = new ConsoleKeyInfo ('\0', ConsoleKey.F13, false, false, false);
829                         keymap [TermInfoStrings.KeyF14] = new ConsoleKeyInfo ('\0', ConsoleKey.F14, false, false, false);
830                         keymap [TermInfoStrings.KeyF15] = new ConsoleKeyInfo ('\0', ConsoleKey.F15, false, false, false);
831                         keymap [TermInfoStrings.KeyF16] = new ConsoleKeyInfo ('\0', ConsoleKey.F16, false, false, false);
832                         keymap [TermInfoStrings.KeyF17] = new ConsoleKeyInfo ('\0', ConsoleKey.F17, false, false, false);
833                         keymap [TermInfoStrings.KeyF18] = new ConsoleKeyInfo ('\0', ConsoleKey.F18, false, false, false);
834                         keymap [TermInfoStrings.KeyF19] = new ConsoleKeyInfo ('\0', ConsoleKey.F19, false, false, false);
835                         keymap [TermInfoStrings.KeyF20] = new ConsoleKeyInfo ('\0', ConsoleKey.F20, false, false, false);
836                         keymap [TermInfoStrings.KeyF21] = new ConsoleKeyInfo ('\0', ConsoleKey.F21, false, false, false);
837                         keymap [TermInfoStrings.KeyF22] = new ConsoleKeyInfo ('\0', ConsoleKey.F22, false, false, false);
838                         keymap [TermInfoStrings.KeyF23] = new ConsoleKeyInfo ('\0', ConsoleKey.F23, false, false, false);
839                         keymap [TermInfoStrings.KeyF24] = new ConsoleKeyInfo ('\0', ConsoleKey.F24, false, false, false);
840                 }
841
842                 void InitKeys ()
843                 {
844                         if (initKeys)
845                                 return;
846
847                         CreateKeyMap ();
848                         rootmap = new ByteMatcher ();
849                         AddStringMapping (TermInfoStrings.KeyBackspace);
850                         AddStringMapping (TermInfoStrings.KeyClear);
851                         AddStringMapping (TermInfoStrings.KeyDown);
852                         AddStringMapping (TermInfoStrings.KeyF1);
853                         AddStringMapping (TermInfoStrings.KeyF10);
854                         AddStringMapping (TermInfoStrings.KeyF2);
855                         AddStringMapping (TermInfoStrings.KeyF3);
856                         AddStringMapping (TermInfoStrings.KeyF4);
857                         AddStringMapping (TermInfoStrings.KeyF5);
858                         AddStringMapping (TermInfoStrings.KeyF6);
859                         AddStringMapping (TermInfoStrings.KeyF7);
860                         AddStringMapping (TermInfoStrings.KeyF8);
861                         AddStringMapping (TermInfoStrings.KeyF9);
862                         AddStringMapping (TermInfoStrings.KeyHome);
863                         AddStringMapping (TermInfoStrings.KeyLeft);
864                         AddStringMapping (TermInfoStrings.KeyLl);
865                         AddStringMapping (TermInfoStrings.KeyNpage);
866                         AddStringMapping (TermInfoStrings.KeyPpage);
867                         AddStringMapping (TermInfoStrings.KeyRight);
868                         AddStringMapping (TermInfoStrings.KeySf);
869                         AddStringMapping (TermInfoStrings.KeySr);
870                         AddStringMapping (TermInfoStrings.KeyUp);
871                         AddStringMapping (TermInfoStrings.KeyA1);
872                         AddStringMapping (TermInfoStrings.KeyA3);
873                         AddStringMapping (TermInfoStrings.KeyB2);
874                         AddStringMapping (TermInfoStrings.KeyC1);
875                         AddStringMapping (TermInfoStrings.KeyC3);
876                         AddStringMapping (TermInfoStrings.KeyBtab);
877                         AddStringMapping (TermInfoStrings.KeyBeg);
878                         AddStringMapping (TermInfoStrings.KeyCopy);
879                         AddStringMapping (TermInfoStrings.KeyEnd);
880                         AddStringMapping (TermInfoStrings.KeyEnter);
881                         AddStringMapping (TermInfoStrings.KeyHelp);
882                         AddStringMapping (TermInfoStrings.KeyPrint);
883                         AddStringMapping (TermInfoStrings.KeyUndo);
884                         AddStringMapping (TermInfoStrings.KeySbeg);
885                         AddStringMapping (TermInfoStrings.KeyScopy);
886                         AddStringMapping (TermInfoStrings.KeySdc);
887                         AddStringMapping (TermInfoStrings.KeyShelp);
888                         AddStringMapping (TermInfoStrings.KeyShome);
889                         AddStringMapping (TermInfoStrings.KeySleft);
890                         AddStringMapping (TermInfoStrings.KeySprint);
891                         AddStringMapping (TermInfoStrings.KeySright);
892                         AddStringMapping (TermInfoStrings.KeySundo);
893                         AddStringMapping (TermInfoStrings.KeyF11);
894                         AddStringMapping (TermInfoStrings.KeyF12);
895                         AddStringMapping (TermInfoStrings.KeyF13);
896                         AddStringMapping (TermInfoStrings.KeyF14);
897                         AddStringMapping (TermInfoStrings.KeyF15);
898                         AddStringMapping (TermInfoStrings.KeyF16);
899                         AddStringMapping (TermInfoStrings.KeyF17);
900                         AddStringMapping (TermInfoStrings.KeyF18);
901                         AddStringMapping (TermInfoStrings.KeyF19);
902                         AddStringMapping (TermInfoStrings.KeyF20);
903                         AddStringMapping (TermInfoStrings.KeyF21);
904                         AddStringMapping (TermInfoStrings.KeyF22);
905                         AddStringMapping (TermInfoStrings.KeyF23);
906                         AddStringMapping (TermInfoStrings.KeyF24);
907                         rootmap.Sort ();
908                         initKeys = true;
909                 }
910
911                 void AddStringMapping (TermInfoStrings s)
912                 {
913                         byte [] bytes = reader.GetStringBytes (s);
914                         if (bytes == null)
915                                 return;
916
917                         rootmap.AddMapping (s, bytes);
918                 }
919         }
920
921         class ByteMatcher {
922                 Hashtable map = new Hashtable ();
923                 Hashtable starts = new Hashtable ();
924
925                 public void AddMapping (TermInfoStrings key, byte [] val)
926                 {
927                         if (val.Length == 0)
928                                 return;
929
930                         map [val] = key;
931                         starts [(int) val [0]] = true;
932                 }
933
934                 public void Sort ()
935                 {
936                 }
937
938                 public bool StartsWith (int c)
939                 {
940                         return (starts [c] != null);
941                 }
942
943                 public TermInfoStrings Match (byte [] buffer, int offset, int length, out int used)
944                 {
945                         foreach (byte [] bytes in map.Keys) {
946                                 for (int i = 0; i < bytes.Length && i < length; i++) {
947                                         if (bytes [i] != buffer [offset + i])
948                                                 break;
949
950                                         if (bytes.Length - 1 == i) {
951                                                 used = bytes.Length;
952                                                 return (TermInfoStrings) map [bytes];
953                                         }
954                                 }
955                         }
956
957                         used = 0;
958                         return (TermInfoStrings) (-1);
959                 }
960         }
961 }
962 #endif
963