1 /*
2  * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
3  *
4  * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved.
5  *
6  * Please visit http://javatelnet.org/ for updates and contact.
7  *
8  * --LICENSE NOTICE--
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  * --LICENSE NOTICE--
23  *
24  */
25 
26 package de.mud.terminal;
27 
28 import java.util.Properties;
29 
30 /**
31  * Implementation of a VT terminal emulation plus ANSI compatible.
32  * <P>
33  * <B>Maintainer:</B> Marcus Meißner
34  *
35  * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
36  * @author Matthias L. Jugel, Marcus Meißner
37  */
38 @SuppressWarnings("unused")
39 public abstract class vt320 extends VDUBuffer implements VDUInput {
40 
41   /**
42    * The current version id tag.
43    * <P>
44    * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
45    *
46    */
47   public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $";
48 
49   /** the debug level */
50   private final static int debug = 0;
51   private StringBuilder debugStr;
52 
debug(String notice)53   public abstract void debug(String notice);
54 
55   /**
56    * Write an answer back to the remote host. This is needed to be able to send terminal answers
57    * requests like status and type information.
58    *
59    * @param b
60    *          the array of bytes to be sent
61    */
write(byte[] b)62   public abstract void write(byte[] b);
63 
64   /**
65    * Write an answer back to the remote host. This is needed to be able to send terminal answers
66    * requests like status and type information.
67    *
68    * @param b
69    *          the array of bytes to be sent
70    */
write(int b)71   public abstract void write(int b);
72 
73   /**
74    * Play the beep sound ...
75    */
beep()76   public void beep() { /* do nothing by default */
77   }
78 
79   /**
80    * Convenience function for putString(char[], int, int)
81    */
putString(String s)82   public void putString(String s) {
83     int len = s.length();
84     char[] tmp = new char[len];
85     s.getChars(0, len, tmp, 0);
86     putString(tmp, null, 0, len);
87   }
88 
89   /**
90    * Put string at current cursor position. Moves cursor according to the String. Does NOT wrap.
91    *
92    * @param s
93    *          character array
94    * @param start
95    *          place to start in array
96    * @param len
97    *          number of characters to process
98    */
putString(char[] s, byte[] fullwidths, int start, int len)99   public void putString(char[] s, byte[] fullwidths, int start, int len) {
100     if (len > 0) {
101       // markLine(R, 1);
102       int lastChar = -1;
103       char c;
104       boolean isWide = false;
105 
106       for (int i = 0; i < len; i++) {
107         c = s[start + i];
108         // Shortcut for my favorite ASCII
109         if (c <= 0x7F) {
110           if (lastChar != -1) {
111             putChar((char) lastChar, isWide, false);
112           }
113           lastChar = c;
114           isWide = false;
115         } else if (!Character.isLowSurrogate(c) && !Character.isHighSurrogate(c)) {
116           if (Character.getType(c) == Character.NON_SPACING_MARK) {
117             if (lastChar != -1) {
118               char nc = Precomposer.precompose((char) lastChar, c);
119               putChar(nc, isWide, false);
120               lastChar = -1;
121             }
122           } else {
123             if (lastChar != -1) {
124               putChar((char) lastChar, isWide, false);
125             }
126             lastChar = c;
127             if (fullwidths != null) {
128               isWide = fullwidths[i] == 1;
129             }
130           }
131         }
132       }
133 
134       if (lastChar != -1) {
135         putChar((char) lastChar, isWide, false);
136       }
137 
138       setCursorPosition(C, R);
139       redraw();
140     }
141   }
142 
sendTelnetCommand(byte cmd)143   protected void sendTelnetCommand(byte cmd) {
144 
145   }
146 
147   /**
148    * Sent the changed window size from the terminal to all listeners.
149    */
setWindowSize(int c, int r)150   protected void setWindowSize(int c, int r) {
151     /* To be overridden by Terminal.java */
152   }
153 
154   @Override
setScreenSize(int c, int r, boolean broadcast)155   public void setScreenSize(int c, int r, boolean broadcast) {
156     // int oldrows = height;
157 
158     if (debug > 2) {
159       if (debugStr == null) {
160         debugStr = new StringBuilder();
161       }
162 
163       debugStr.append("setscreensize (").append(c).append(',').append(r).append(',')
164           .append(broadcast).append(')');
165       debug(debugStr.toString());
166       debugStr.setLength(0);
167     }
168 
169     super.setScreenSize(c, r, false);
170 
171     boolean cursorChanged = false;
172 
173     // Don't let the cursor go off the screen.
174     if (C >= c) {
175       C = c - 1;
176       cursorChanged = true;
177     }
178 
179     if (R >= r) {
180       R = r - 1;
181       cursorChanged = true;
182     }
183 
184     if (cursorChanged) {
185       setCursorPosition(C, R);
186       redraw();
187     }
188 
189     if (broadcast) {
190       setWindowSize(c, r); /* broadcast up */
191     }
192   }
193 
194   /**
195    * Create a new vt320 terminal and intialize it with useful settings.
196    */
vt320(int width, int height)197   public vt320(int width, int height) {
198     super(width, height);
199 
200     debugStr = new StringBuilder();
201 
202     setVMS(false);
203     setIBMCharset(false);
204     setTerminalID("vt320");
205     setBufferSize(100);
206     // setBorder(2, false);
207 
208     gx = new char[4];
209     reset();
210 
211     /* top row of numpad */
212     PF1 = "\u001bOP";
213     PF2 = "\u001bOQ";
214     PF3 = "\u001bOR";
215     PF4 = "\u001bOS";
216 
217     /* the 3x2 keyblock on PC keyboards */
218     Insert = new String[4];
219     Remove = new String[4];
220     KeyHome = new String[4];
221     KeyEnd = new String[4];
222     NextScn = new String[4];
223     PrevScn = new String[4];
224     Escape = new String[4];
225     BackSpace = new String[4];
226     TabKey = new String[4];
227     Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
228     Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
229     PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
230     NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
231     KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
232     KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
233     Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b";
234     if (vms) {
235       BackSpace[1] = "" + (char) 10; // VMS shift deletes word back
236       BackSpace[2] = "\u0018"; // VMS control deletes line back
237       BackSpace[0] = BackSpace[3] = "\u007f"; // VMS other is delete
238     } else {
239       // BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b";
240       // ConnectBot modifications.
241       BackSpace[0] = "\b";
242       BackSpace[1] = "\u007f";
243       BackSpace[2] = "\u001b[3~";
244       BackSpace[3] = "\u001b[2~";
245     }
246 
247     /* some more VT100 keys */
248     Find = "\u001b[1~";
249     Select = "\u001b[4~";
250     Help = "\u001b[28~";
251     Do = "\u001b[29~";
252 
253     FunctionKey = new String[21];
254     FunctionKey[0] = "";
255     FunctionKey[1] = PF1;
256     FunctionKey[2] = PF2;
257     FunctionKey[3] = PF3;
258     FunctionKey[4] = PF4;
259     /* following are defined differently for vt220 / vt132 ... */
260     FunctionKey[5] = "\u001b[15~";
261     FunctionKey[6] = "\u001b[17~";
262     FunctionKey[7] = "\u001b[18~";
263     FunctionKey[8] = "\u001b[19~";
264     FunctionKey[9] = "\u001b[20~";
265     FunctionKey[10] = "\u001b[21~";
266     FunctionKey[11] = "\u001b[23~";
267     FunctionKey[12] = "\u001b[24~";
268     FunctionKey[13] = "\u001b[25~";
269     FunctionKey[14] = "\u001b[26~";
270     FunctionKey[15] = Help;
271     FunctionKey[16] = Do;
272     FunctionKey[17] = "\u001b[31~";
273     FunctionKey[18] = "\u001b[32~";
274     FunctionKey[19] = "\u001b[33~";
275     FunctionKey[20] = "\u001b[34~";
276 
277     FunctionKeyShift = new String[21];
278     FunctionKeyAlt = new String[21];
279     FunctionKeyCtrl = new String[21];
280 
281     for (int i = 0; i < 20; i++) {
282       FunctionKeyShift[i] = "";
283       FunctionKeyAlt[i] = "";
284       FunctionKeyCtrl[i] = "";
285     }
286     FunctionKeyShift[15] = Find;
287     FunctionKeyShift[16] = Select;
288 
289     TabKey[0] = "\u0009";
290     TabKey[1] = "\u001bOP\u0009";
291     TabKey[2] = TabKey[3] = "";
292 
293     KeyUp = new String[4];
294     KeyUp[0] = "\u001b[A";
295     KeyDown = new String[4];
296     KeyDown[0] = "\u001b[B";
297     KeyRight = new String[4];
298     KeyRight[0] = "\u001b[C";
299     KeyLeft = new String[4];
300     KeyLeft[0] = "\u001b[D";
301     Numpad = new String[10];
302     Numpad[0] = "\u001bOp";
303     Numpad[1] = "\u001bOq";
304     Numpad[2] = "\u001bOr";
305     Numpad[3] = "\u001bOs";
306     Numpad[4] = "\u001bOt";
307     Numpad[5] = "\u001bOu";
308     Numpad[6] = "\u001bOv";
309     Numpad[7] = "\u001bOw";
310     Numpad[8] = "\u001bOx";
311     Numpad[9] = "\u001bOy";
312     KPMinus = PF4;
313     KPComma = "\u001bOl";
314     KPPeriod = "\u001bOn";
315     KPEnter = "\u001bOM";
316 
317     NUMPlus = new String[4];
318     NUMPlus[0] = "+";
319     NUMDot = new String[4];
320     NUMDot[0] = ".";
321   }
322 
setBackspace(int type)323   public void setBackspace(int type) {
324     switch (type) {
325     case DELETE_IS_DEL:
326       BackSpace[0] = "\u007f";
327       BackSpace[1] = "\b";
328       break;
329     case DELETE_IS_BACKSPACE:
330       BackSpace[0] = "\b";
331       BackSpace[1] = "\u007f";
332       break;
333     }
334   }
335 
336   /**
337    * Create a default vt320 terminal with 80 columns and 24 lines.
338    */
vt320()339   public vt320() {
340     this(80, 24);
341   }
342 
343   /**
344    * Terminal is mouse-aware and requires (x,y) coordinates of on the terminal (character
345    * coordinates) and the button clicked.
346    *
347    * @param x
348    * @param y
349    * @param modifiers
350    */
mousePressed(int x, int y, int modifiers)351   public void mousePressed(int x, int y, int modifiers) {
352     if (mouserpt == 0) {
353       return;
354     }
355 
356     int mods = modifiers;
357     mousebut = 3;
358     if ((mods & 16) == 16) {
359       mousebut = 0;
360     }
361     if ((mods & 8) == 8) {
362       mousebut = 1;
363     }
364     if ((mods & 4) == 4) {
365       mousebut = 2;
366     }
367 
368     int mousecode;
369     if (mouserpt == 9) {
370       mousecode = 0x20 | mousebut;
371     } else {
372       mousecode = mousebut | 0x20 | ((mods & 7) << 2);
373     }
374 
375     byte b[] = new byte[6];
376 
377     b[0] = 27;
378     b[1] = (byte) '[';
379     b[2] = (byte) 'M';
380     b[3] = (byte) mousecode;
381     b[4] = (byte) (0x20 + x + 1);
382     b[5] = (byte) (0x20 + y + 1);
383 
384     write(b); // FIXME: writeSpecial here
385   }
386 
387   /**
388    * Terminal is mouse-aware and requires the coordinates and button of the release.
389    *
390    * @param x
391    * @param y
392    * @param modifiers
393    */
mouseReleased(int x, int y, int modifiers)394   public void mouseReleased(int x, int y, int modifiers) {
395     if (mouserpt == 0) {
396       return;
397     }
398 
399     /*
400      * problem is tht modifiers still have the released button set in them. int mods = modifiers;
401      * mousebut = 3; if ((mods & 16)==16) mousebut=0; if ((mods & 8)==8 ) mousebut=1; if ((mods &
402      * 4)==4 ) mousebut=2;
403      */
404 
405     int mousecode;
406     if (mouserpt == 9) {
407       mousecode = 0x20 + mousebut; /* same as press? appears so. */
408     } else {
409       mousecode = '#';
410     }
411 
412     byte b[] = new byte[6];
413     b[0] = 27;
414     b[1] = (byte) '[';
415     b[2] = (byte) 'M';
416     b[3] = (byte) mousecode;
417     b[4] = (byte) (0x20 + x + 1);
418     b[5] = (byte) (0x20 + y + 1);
419     write(b); // FIXME: writeSpecial here
420     mousebut = 0;
421   }
422 
423   /** we should do localecho (passed from other modules). false is default */
424   private boolean localecho = false;
425 
426   /**
427    * Enable or disable the local echo property of the terminal.
428    *
429    * @param echo
430    *          true if the terminal should echo locally
431    */
setLocalEcho(boolean echo)432   public void setLocalEcho(boolean echo) {
433     localecho = echo;
434   }
435 
436   /**
437    * Enable the VMS mode of the terminal to handle some things differently for VMS hosts.
438    *
439    * @param vms
440    *          true for vms mode, false for normal mode
441    */
setVMS(boolean vms)442   public void setVMS(boolean vms) {
443     this.vms = vms;
444   }
445 
446   /**
447    * Enable the usage of the IBM character set used by some BBS's. Special graphical character are
448    * available in this mode.
449    *
450    * @param ibm
451    *          true to use the ibm character set
452    */
setIBMCharset(boolean ibm)453   public void setIBMCharset(boolean ibm) {
454     useibmcharset = ibm;
455   }
456 
457   /**
458    * Override the standard key codes used by the terminal emulation.
459    *
460    * @param codes
461    *          a properties object containing key code definitions
462    */
setKeyCodes(Properties codes)463   public void setKeyCodes(Properties codes) {
464     String res, prefixes[] = { "", "S", "C", "A" };
465     int i;
466 
467     for (i = 0; i < 10; i++) {
468       res = codes.getProperty("NUMPAD" + i);
469       if (res != null) {
470         Numpad[i] = unEscape(res);
471       }
472     }
473     for (i = 1; i < 20; i++) {
474       res = codes.getProperty("F" + i);
475       if (res != null) {
476         FunctionKey[i] = unEscape(res);
477       }
478       res = codes.getProperty("SF" + i);
479       if (res != null) {
480         FunctionKeyShift[i] = unEscape(res);
481       }
482       res = codes.getProperty("CF" + i);
483       if (res != null) {
484         FunctionKeyCtrl[i] = unEscape(res);
485       }
486       res = codes.getProperty("AF" + i);
487       if (res != null) {
488         FunctionKeyAlt[i] = unEscape(res);
489       }
490     }
491     for (i = 0; i < 4; i++) {
492       res = codes.getProperty(prefixes[i] + "PGUP");
493       if (res != null) {
494         PrevScn[i] = unEscape(res);
495       }
496       res = codes.getProperty(prefixes[i] + "PGDOWN");
497       if (res != null) {
498         NextScn[i] = unEscape(res);
499       }
500       res = codes.getProperty(prefixes[i] + "END");
501       if (res != null) {
502         KeyEnd[i] = unEscape(res);
503       }
504       res = codes.getProperty(prefixes[i] + "HOME");
505       if (res != null) {
506         KeyHome[i] = unEscape(res);
507       }
508       res = codes.getProperty(prefixes[i] + "INSERT");
509       if (res != null) {
510         Insert[i] = unEscape(res);
511       }
512       res = codes.getProperty(prefixes[i] + "REMOVE");
513       if (res != null) {
514         Remove[i] = unEscape(res);
515       }
516       res = codes.getProperty(prefixes[i] + "UP");
517       if (res != null) {
518         KeyUp[i] = unEscape(res);
519       }
520       res = codes.getProperty(prefixes[i] + "DOWN");
521       if (res != null) {
522         KeyDown[i] = unEscape(res);
523       }
524       res = codes.getProperty(prefixes[i] + "LEFT");
525       if (res != null) {
526         KeyLeft[i] = unEscape(res);
527       }
528       res = codes.getProperty(prefixes[i] + "RIGHT");
529       if (res != null) {
530         KeyRight[i] = unEscape(res);
531       }
532       res = codes.getProperty(prefixes[i] + "ESCAPE");
533       if (res != null) {
534         Escape[i] = unEscape(res);
535       }
536       res = codes.getProperty(prefixes[i] + "BACKSPACE");
537       if (res != null) {
538         BackSpace[i] = unEscape(res);
539       }
540       res = codes.getProperty(prefixes[i] + "TAB");
541       if (res != null) {
542         TabKey[i] = unEscape(res);
543       }
544       res = codes.getProperty(prefixes[i] + "NUMPLUS");
545       if (res != null) {
546         NUMPlus[i] = unEscape(res);
547       }
548       res = codes.getProperty(prefixes[i] + "NUMDECIMAL");
549       if (res != null) {
550         NUMDot[i] = unEscape(res);
551       }
552     }
553   }
554 
555   /**
556    * Set the terminal id used to identify this terminal.
557    *
558    * @param terminalID
559    *          the id string
560    */
setTerminalID(String terminalID)561   public void setTerminalID(String terminalID) {
562     this.terminalID = terminalID;
563 
564     if (terminalID.equals("scoansi")) {
565       FunctionKey[1] = "\u001b[M";
566       FunctionKey[2] = "\u001b[N";
567       FunctionKey[3] = "\u001b[O";
568       FunctionKey[4] = "\u001b[P";
569       FunctionKey[5] = "\u001b[Q";
570       FunctionKey[6] = "\u001b[R";
571       FunctionKey[7] = "\u001b[S";
572       FunctionKey[8] = "\u001b[T";
573       FunctionKey[9] = "\u001b[U";
574       FunctionKey[10] = "\u001b[V";
575       FunctionKey[11] = "\u001b[W";
576       FunctionKey[12] = "\u001b[X";
577       FunctionKey[13] = "\u001b[Y";
578       FunctionKey[14] = "?";
579       FunctionKey[15] = "\u001b[a";
580       FunctionKey[16] = "\u001b[b";
581       FunctionKey[17] = "\u001b[c";
582       FunctionKey[18] = "\u001b[d";
583       FunctionKey[19] = "\u001b[e";
584       FunctionKey[20] = "\u001b[f";
585       PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I";
586       NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G";
587       // more theoretically.
588     }
589   }
590 
setAnswerBack(String ab)591   public void setAnswerBack(String ab) {
592     answerBack = unEscape(ab);
593   }
594 
595   /**
596    * Get the terminal id used to identify this terminal.
597    */
getTerminalID()598   public String getTerminalID() {
599     return terminalID;
600   }
601 
602   /**
603    * A small conveniance method thar converts the string to a byte array for sending.
604    *
605    * @param s
606    *          the string to be sent
607    */
write(String s, boolean doecho)608   private boolean write(String s, boolean doecho) {
609     if (debug > 2) {
610       debugStr.append("write(|").append(s).append("|,").append(doecho);
611       debug(debugStr.toString());
612       debugStr.setLength(0);
613     }
614     if (s == null) {
615       return true;
616       /*
617        * NOTE: getBytes() honours some locale, it *CONVERTS* the string. However, we output only
618        * 7bit stuff towards the target, and *some* 8 bit control codes. We must not mess up the
619        * latter, so we do hand by hand copy.
620        */
621     }
622 
623     byte arr[] = new byte[s.length()];
624     for (int i = 0; i < s.length(); i++) {
625       arr[i] = (byte) s.charAt(i);
626     }
627     write(arr);
628 
629     if (doecho) {
630       putString(s);
631     }
632     return true;
633   }
634 
write(int s, boolean doecho)635   private boolean write(int s, boolean doecho) {
636     if (debug > 2) {
637       debugStr.append("write(|").append(s).append("|,").append(doecho);
638       debug(debugStr.toString());
639       debugStr.setLength(0);
640     }
641 
642     write(s);
643 
644     // TODO check if character is wide
645     if (doecho) {
646       putChar((char) s, false, false);
647     }
648     return true;
649   }
650 
write(String s)651   private boolean write(String s) {
652     return write(s, localecho);
653   }
654 
655   // ===================================================================
656   // the actual terminal emulation code comes here:
657   // ===================================================================
658 
659   private String terminalID = "vt320";
660   private String answerBack = "Use Terminal.answerback to set ...\n";
661 
662   // X - COLUMNS, Y - ROWS
663   int R, C;
664   int attributes = 0;
665 
666   int Sc, Sr, Sa, Stm, Sbm;
667   char Sgr, Sgl;
668   char Sgx[];
669 
670   int insertmode = 0;
671   int statusmode = 0;
672   boolean vt52mode = false;
673   boolean keypadmode = false; /* false - numeric, true - application */
674   boolean output8bit = false;
675   int normalcursor = 0;
676   boolean moveoutsidemargins = true;
677   boolean wraparound = true;
678   boolean sendcrlf = true;
679   boolean capslock = false;
680   boolean numlock = false;
681   int mouserpt = 0;
682   byte mousebut = 0;
683 
684   boolean useibmcharset = false;
685 
686   int lastwaslf = 0;
687   boolean usedcharsets = false;
688 
689   private final static char ESC = 27;
690   private final static char IND = 132;
691   private final static char NEL = 133;
692   private final static char RI = 141;
693   private final static char SS2 = 142;
694   private final static char SS3 = 143;
695   private final static char DCS = 144;
696   private final static char HTS = 136;
697   private final static char CSI = 155;
698   private final static char OSC = 157;
699   private final static int TSTATE_DATA = 0;
700   private final static int TSTATE_ESC = 1; /* ESC */
701   private final static int TSTATE_CSI = 2; /* ESC [ */
702   private final static int TSTATE_DCS = 3; /* ESC P */
703   private final static int TSTATE_DCEQ = 4; /* ESC [? */
704   private final static int TSTATE_ESCSQUARE = 5; /* ESC # */
705   private final static int TSTATE_OSC = 6; /* ESC ] */
706   private final static int TSTATE_SETG0 = 7; /* ESC (? */
707   private final static int TSTATE_SETG1 = 8; /* ESC )? */
708   private final static int TSTATE_SETG2 = 9; /* ESC *? */
709   private final static int TSTATE_SETG3 = 10; /* ESC +? */
710   private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */
711   private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */
712   private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */
713   private final static int TSTATE_VT52X = 14;
714   private final static int TSTATE_VT52Y = 15;
715   private final static int TSTATE_CSI_TICKS = 16;
716   private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */
717   private final static int TSTATE_TITLE = 18; /* xterm title */
718 
719   /* Keys we support */
720   public final static int KEY_PAUSE = 1;
721   public final static int KEY_F1 = 2;
722   public final static int KEY_F2 = 3;
723   public final static int KEY_F3 = 4;
724   public final static int KEY_F4 = 5;
725   public final static int KEY_F5 = 6;
726   public final static int KEY_F6 = 7;
727   public final static int KEY_F7 = 8;
728   public final static int KEY_F8 = 9;
729   public final static int KEY_F9 = 10;
730   public final static int KEY_F10 = 11;
731   public final static int KEY_F11 = 12;
732   public final static int KEY_F12 = 13;
733   public final static int KEY_UP = 14;
734   public final static int KEY_DOWN = 15;
735   public final static int KEY_LEFT = 16;
736   public final static int KEY_RIGHT = 17;
737   public final static int KEY_PAGE_DOWN = 18;
738   public final static int KEY_PAGE_UP = 19;
739   public final static int KEY_INSERT = 20;
740   public final static int KEY_DELETE = 21;
741   public final static int KEY_BACK_SPACE = 22;
742   public final static int KEY_HOME = 23;
743   public final static int KEY_END = 24;
744   public final static int KEY_NUM_LOCK = 25;
745   public final static int KEY_CAPS_LOCK = 26;
746   public final static int KEY_SHIFT = 27;
747   public final static int KEY_CONTROL = 28;
748   public final static int KEY_ALT = 29;
749   public final static int KEY_ENTER = 30;
750   public final static int KEY_NUMPAD0 = 31;
751   public final static int KEY_NUMPAD1 = 32;
752   public final static int KEY_NUMPAD2 = 33;
753   public final static int KEY_NUMPAD3 = 34;
754   public final static int KEY_NUMPAD4 = 35;
755   public final static int KEY_NUMPAD5 = 36;
756   public final static int KEY_NUMPAD6 = 37;
757   public final static int KEY_NUMPAD7 = 38;
758   public final static int KEY_NUMPAD8 = 39;
759   public final static int KEY_NUMPAD9 = 40;
760   public final static int KEY_DECIMAL = 41;
761   public final static int KEY_ADD = 42;
762   public final static int KEY_ESCAPE = 43;
763 
764   public final static int DELETE_IS_DEL = 0;
765   public final static int DELETE_IS_BACKSPACE = 1;
766 
767   /*
768    * The graphics charsets B - default ASCII A - ISO Latin 1 0 - DEC SPECIAL < - User defined ....
769    */
770   char gx[];
771   char gl; // GL (left charset)
772   char gr; // GR (right charset)
773   int onegl; // single shift override for GL.
774 
775   // Map from scoansi linedrawing to DEC _and_ unicode (for the stuff which
776   // is not in linedrawing). Got from experimenting with scoadmin.
777   private final static String scoansi_acs =
778       "Tm7k3x4u?kZl@mYjEnB\u2566DqCtAvM\u2550:\u2551N\u2557I\u2554;\u2557H\u255a0a<\u255d";
779   // array to store DEC Special -> Unicode mapping
780   // Unicode DEC Unicode name (DEC name)
781   private static char DECSPECIAL[] = { '\u0040', // 5f blank
782     '\u2666', // 60 black diamond
783     '\u2592', // 61 grey square
784     '\u2409', // 62 Horizontal tab (ht) pict. for control
785     '\u240c', // 63 Form Feed (ff) pict. for control
786     '\u240d', // 64 Carriage Return (cr) pict. for control
787     '\u240a', // 65 Line Feed (lf) pict. for control
788     '\u00ba', // 66 Masculine ordinal indicator
789     '\u00b1', // 67 Plus or minus sign
790     '\u2424', // 68 New Line (nl) pict. for control
791     '\u240b', // 69 Vertical Tab (vt) pict. for control
792     '\u2518', // 6a Forms light up and left
793     '\u2510', // 6b Forms light down and left
794     '\u250c', // 6c Forms light down and right
795     '\u2514', // 6d Forms light up and right
796     '\u253c', // 6e Forms light vertical and horizontal
797     '\u2594', // 6f Upper 1/8 block (Scan 1)
798     '\u2580', // 70 Upper 1/2 block (Scan 3)
799     '\u2500', // 71 Forms light horizontal or ?em dash? (Scan 5)
800     '\u25ac', // 72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7)
801     '\u005f', // 73 \u005f underscore or \u2581 lower 1/8 (Scan 9)
802     '\u251c', // 74 Forms light vertical and right
803     '\u2524', // 75 Forms light vertical and left
804     '\u2534', // 76 Forms light up and horizontal
805     '\u252c', // 77 Forms light down and horizontal
806     '\u2502', // 78 vertical bar
807     '\u2264', // 79 less than or equal
808     '\u2265', // 7a greater than or equal
809     '\u00b6', // 7b paragraph
810     '\u2260', // 7c not equal
811     '\u00a3', // 7d Pound Sign (british)
812     '\u00b7' // 7e Middle Dot
813       };
814 
815   /** Strings to send on function key pressing */
816   private String Numpad[];
817   private String FunctionKey[];
818   private String FunctionKeyShift[];
819   private String FunctionKeyCtrl[];
820   private String FunctionKeyAlt[];
821   private String TabKey[];
822   private String KeyUp[], KeyDown[], KeyLeft[], KeyRight[];
823   private String KPMinus, KPComma, KPPeriod, KPEnter;
824   private String PF1, PF2, PF3, PF4;
825   private String Help, Do, Find, Select;
826 
827   private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[];
828   private String Escape[], BackSpace[], NUMDot[], NUMPlus[];
829 
830   private String osc, dcs; /* to memorize OSC & DCS control sequence */
831 
832   /** vt320 state variable (internal) */
833   private int term_state = TSTATE_DATA;
834   /** in vms mode, set by Terminal.VMS property */
835   private boolean vms = false;
836   /** Tabulators */
837   private byte[] Tabs;
838   /** The list of integers as used by CSI */
839   private int[] DCEvars = new int[30];
840   private int DCEvar;
841 
842   /**
843    * Replace escape code characters (backslash + identifier) with their respective codes.
844    *
845    * @param tmp
846    *          the string to be parsed
847    * @return a unescaped string
848    */
unEscape(String tmp)849   static String unEscape(String tmp) {
850     int idx = 0, oldidx = 0;
851     String cmd;
852     // f.println("unescape("+tmp+")");
853     cmd = "";
854     while ((idx = tmp.indexOf('\\', oldidx)) >= 0 && ++idx <= tmp.length()) {
855       cmd += tmp.substring(oldidx, idx - 1);
856       if (idx == tmp.length()) {
857         return cmd;
858       }
859       switch (tmp.charAt(idx)) {
860       case 'b':
861         cmd += "\b";
862         break;
863       case 'e':
864         cmd += "\u001b";
865         break;
866       case 'n':
867         cmd += "\n";
868         break;
869       case 'r':
870         cmd += "\r";
871         break;
872       case 't':
873         cmd += "\t";
874         break;
875       case 'v':
876         cmd += "\u000b";
877         break;
878       case 'a':
879         cmd += "\u0012";
880         break;
881       default:
882         if ((tmp.charAt(idx) >= '0') && (tmp.charAt(idx) <= '9')) {
883           int i;
884           for (i = idx; i < tmp.length(); i++) {
885             if ((tmp.charAt(i) < '0') || (tmp.charAt(i) > '9')) {
886               break;
887             }
888           }
889           cmd += (char) Integer.parseInt(tmp.substring(idx, i));
890           idx = i - 1;
891         } else {
892           cmd += tmp.substring(idx, ++idx);
893         }
894         break;
895       }
896       oldidx = ++idx;
897     }
898     if (oldidx <= tmp.length()) {
899       cmd += tmp.substring(oldidx);
900     }
901     return cmd;
902   }
903 
904   /**
905    * A small conveniance method thar converts a 7bit string to the 8bit version depending on
906    * VT52/Output8Bit mode.
907    *
908    * @param s
909    *          the string to be sent
910    */
writeSpecial(String s)911   private boolean writeSpecial(String s) {
912     if (s == null) {
913       return true;
914     }
915     if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == 'O'))) {
916       if (vt52mode) {
917         if ((s.charAt(2) >= 'P') && (s.charAt(2) <= 'S')) {
918           s = "\u001b" + s.substring(2); /* ESC x */
919         } else {
920           s = "\u001b?" + s.substring(2); /* ESC ? x */
921         }
922       } else {
923         if (output8bit) {
924           s = "\u008f" + s.substring(2); /* SS3 x */
925         } /* else keep string as it is */
926       }
927     }
928     if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == '['))) {
929       if (output8bit) {
930         s = "\u009b" + s.substring(2); /* CSI ... */
931       } /* else keep */
932     }
933     return write(s, false);
934   }
935 
936   /**
937    * main keytyping event handler...
938    */
keyPressed(int keyCode, char keyChar, int modifiers)939   public void keyPressed(int keyCode, char keyChar, int modifiers) {
940     boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
941     boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
942     boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
943 
944     if (debug > 1) {
945       debugStr.append("keyPressed(").append(keyCode).append(", ").append((int) keyChar)
946           .append(", ").append(modifiers).append(')');
947       debug(debugStr.toString());
948       debugStr.setLength(0);
949     }
950 
951     int xind;
952     String fmap[];
953     xind = 0;
954     fmap = FunctionKey;
955     if (shift) {
956       fmap = FunctionKeyShift;
957       xind = 1;
958     }
959     if (control) {
960       fmap = FunctionKeyCtrl;
961       xind = 2;
962     }
963     if (alt) {
964       fmap = FunctionKeyAlt;
965       xind = 3;
966     }
967 
968     switch (keyCode) {
969     case KEY_PAUSE:
970       if (shift || control) {
971         sendTelnetCommand((byte) 243); // BREAK
972       }
973       break;
974     case KEY_F1:
975       writeSpecial(fmap[1]);
976       break;
977     case KEY_F2:
978       writeSpecial(fmap[2]);
979       break;
980     case KEY_F3:
981       writeSpecial(fmap[3]);
982       break;
983     case KEY_F4:
984       writeSpecial(fmap[4]);
985       break;
986     case KEY_F5:
987       writeSpecial(fmap[5]);
988       break;
989     case KEY_F6:
990       writeSpecial(fmap[6]);
991       break;
992     case KEY_F7:
993       writeSpecial(fmap[7]);
994       break;
995     case KEY_F8:
996       writeSpecial(fmap[8]);
997       break;
998     case KEY_F9:
999       writeSpecial(fmap[9]);
1000       break;
1001     case KEY_F10:
1002       writeSpecial(fmap[10]);
1003       break;
1004     case KEY_F11:
1005       writeSpecial(fmap[11]);
1006       break;
1007     case KEY_F12:
1008       writeSpecial(fmap[12]);
1009       break;
1010     case KEY_UP:
1011       writeSpecial(KeyUp[xind]);
1012       break;
1013     case KEY_DOWN:
1014       writeSpecial(KeyDown[xind]);
1015       break;
1016     case KEY_LEFT:
1017       writeSpecial(KeyLeft[xind]);
1018       break;
1019     case KEY_RIGHT:
1020       writeSpecial(KeyRight[xind]);
1021       break;
1022     case KEY_PAGE_DOWN:
1023       writeSpecial(NextScn[xind]);
1024       break;
1025     case KEY_PAGE_UP:
1026       writeSpecial(PrevScn[xind]);
1027       break;
1028     case KEY_INSERT:
1029       writeSpecial(Insert[xind]);
1030       break;
1031     case KEY_DELETE:
1032       writeSpecial(Remove[xind]);
1033       break;
1034     case KEY_BACK_SPACE:
1035       writeSpecial(BackSpace[xind]);
1036       if (localecho) {
1037         if (BackSpace[xind] == "\b") {
1038           putString("\b \b"); // make the last char 'deleted'
1039         } else {
1040           putString(BackSpace[xind]); // echo it
1041         }
1042       }
1043       break;
1044     case KEY_HOME:
1045       writeSpecial(KeyHome[xind]);
1046       break;
1047     case KEY_END:
1048       writeSpecial(KeyEnd[xind]);
1049       break;
1050     case KEY_NUM_LOCK:
1051       if (vms && control) {
1052         writeSpecial(PF1);
1053       }
1054       if (!control) {
1055         numlock = !numlock;
1056       }
1057       break;
1058     case KEY_CAPS_LOCK:
1059       capslock = !capslock;
1060       return;
1061     case KEY_SHIFT:
1062     case KEY_CONTROL:
1063     case KEY_ALT:
1064       return;
1065     default:
1066       break;
1067     }
1068   }
1069 
1070   /*
1071    * public void keyReleased(KeyEvent evt) { if (debug > 1) debug("keyReleased("+evt+")"); // ignore
1072    * }
1073    */
1074   /**
1075    * Handle key Typed events for the terminal, this will get all normal key types, but no
1076    * shift/alt/control/numlock.
1077    */
keyTyped(int keyCode, char keyChar, int modifiers)1078   public void keyTyped(int keyCode, char keyChar, int modifiers) {
1079     boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
1080     boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
1081     boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
1082 
1083     if (debug > 1) {
1084       debug("keyTyped(" + keyCode + ", " + (int) keyChar + ", " + modifiers + ")");
1085     }
1086 
1087     if (keyChar == '\t') {
1088       if (shift) {
1089         write(TabKey[1], false);
1090       } else {
1091         if (control) {
1092           write(TabKey[2], false);
1093         } else {
1094           if (alt) {
1095             write(TabKey[3], false);
1096           } else {
1097             write(TabKey[0], false);
1098           }
1099         }
1100       }
1101       return;
1102     }
1103     if (alt) {
1104       write(((char) (keyChar | 0x80)));
1105       return;
1106     }
1107 
1108     if (((keyCode == KEY_ENTER) || (keyChar == 10)) && !control) {
1109       write('\r');
1110       if (localecho) {
1111         putString("\r\n"); // bad hack
1112       }
1113       return;
1114     }
1115 
1116     if ((keyCode == 10) && !control) {
1117       debug("Sending \\r");
1118       write('\r');
1119       return;
1120     }
1121 
1122     // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @,
1123     // so we can't just use it here... will probably break some other VMS
1124     // codes. -Marcus
1125     // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ')
1126     // && control)
1127     if (((!vms && keyChar == '2') || keyChar == ' ') && control) {
1128       write(0);
1129     }
1130 
1131     if (vms) {
1132       if (keyChar == 127 && !control) {
1133         if (shift) {
1134           writeSpecial(Insert[0]); // VMS shift delete = insert
1135         } else {
1136           writeSpecial(Remove[0]); // VMS delete = remove
1137         }
1138         return;
1139       } else if (control) {
1140         switch (keyChar) {
1141         case '0':
1142           writeSpecial(Numpad[0]);
1143           return;
1144         case '1':
1145           writeSpecial(Numpad[1]);
1146           return;
1147         case '2':
1148           writeSpecial(Numpad[2]);
1149           return;
1150         case '3':
1151           writeSpecial(Numpad[3]);
1152           return;
1153         case '4':
1154           writeSpecial(Numpad[4]);
1155           return;
1156         case '5':
1157           writeSpecial(Numpad[5]);
1158           return;
1159         case '6':
1160           writeSpecial(Numpad[6]);
1161           return;
1162         case '7':
1163           writeSpecial(Numpad[7]);
1164           return;
1165         case '8':
1166           writeSpecial(Numpad[8]);
1167           return;
1168         case '9':
1169           writeSpecial(Numpad[9]);
1170           return;
1171         case '.':
1172           writeSpecial(KPPeriod);
1173           return;
1174         case '-':
1175         case 31:
1176           writeSpecial(KPMinus);
1177           return;
1178         case '+':
1179           writeSpecial(KPComma);
1180           return;
1181         case 10:
1182           writeSpecial(KPEnter);
1183           return;
1184         case '/':
1185           writeSpecial(PF2);
1186           return;
1187         case '*':
1188           writeSpecial(PF3);
1189           return;
1190           /* NUMLOCK handled in keyPressed */
1191         default:
1192           break;
1193         }
1194         /*
1195          * Now what does this do and how did it get here. -Marcus if (shift && keyChar < 32) {
1196          * write(PF1+(char)(keyChar + 64)); return; }
1197          */
1198       }
1199     }
1200 
1201     // FIXME: not used?
1202     // String fmap[];
1203     int xind;
1204     xind = 0;
1205     // fmap = FunctionKey;
1206     if (shift) {
1207       // fmap = FunctionKeyShift;
1208       xind = 1;
1209     }
1210     if (control) {
1211       // fmap = FunctionKeyCtrl;
1212       xind = 2;
1213     }
1214     if (alt) {
1215       // fmap = FunctionKeyAlt;
1216       xind = 3;
1217     }
1218 
1219     if (keyCode == KEY_ESCAPE) {
1220       writeSpecial(Escape[xind]);
1221       return;
1222     }
1223 
1224     if ((modifiers & VDUInput.KEY_ACTION) != 0) {
1225       switch (keyCode) {
1226       case KEY_NUMPAD0:
1227         writeSpecial(Numpad[0]);
1228         return;
1229       case KEY_NUMPAD1:
1230         writeSpecial(Numpad[1]);
1231         return;
1232       case KEY_NUMPAD2:
1233         writeSpecial(Numpad[2]);
1234         return;
1235       case KEY_NUMPAD3:
1236         writeSpecial(Numpad[3]);
1237         return;
1238       case KEY_NUMPAD4:
1239         writeSpecial(Numpad[4]);
1240         return;
1241       case KEY_NUMPAD5:
1242         writeSpecial(Numpad[5]);
1243         return;
1244       case KEY_NUMPAD6:
1245         writeSpecial(Numpad[6]);
1246         return;
1247       case KEY_NUMPAD7:
1248         writeSpecial(Numpad[7]);
1249         return;
1250       case KEY_NUMPAD8:
1251         writeSpecial(Numpad[8]);
1252         return;
1253       case KEY_NUMPAD9:
1254         writeSpecial(Numpad[9]);
1255         return;
1256       case KEY_DECIMAL:
1257         writeSpecial(NUMDot[xind]);
1258         return;
1259       case KEY_ADD:
1260         writeSpecial(NUMPlus[xind]);
1261         return;
1262       }
1263     }
1264 
1265     if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) {
1266       write(keyChar);
1267       return;
1268     }
1269   }
1270 
handle_dcs(String dcs)1271   private void handle_dcs(String dcs) {
1272     debugStr.append("DCS: ").append(dcs);
1273     debug(debugStr.toString());
1274     debugStr.setLength(0);
1275   }
1276 
handle_osc(String osc)1277   private void handle_osc(String osc) {
1278     if (osc.length() > 2 && osc.substring(0, 2).equals("4;")) {
1279       // Define color palette
1280       String[] colorData = osc.split(";");
1281 
1282       try {
1283         int colorIndex = Integer.parseInt(colorData[1]);
1284 
1285         if ("rgb:".equals(colorData[2].substring(0, 4))) {
1286           String[] rgb = colorData[2].substring(4).split("/");
1287 
1288           int red = Integer.parseInt(rgb[0].substring(0, 2), 16) & 0xFF;
1289           int green = Integer.parseInt(rgb[1].substring(0, 2), 16) & 0xFF;
1290           int blue = Integer.parseInt(rgb[2].substring(0, 2), 16) & 0xFF;
1291           display.setColor(colorIndex, red, green, blue);
1292         }
1293       } catch (Exception e) {
1294         debugStr.append("OSC: invalid color sequence encountered: ").append(osc);
1295         debug(debugStr.toString());
1296         debugStr.setLength(0);
1297       }
1298     } else {
1299       debug("OSC: " + osc);
1300     }
1301   }
1302 
1303   private final static char unimap[] = {
1304     // #
1305     // # Name: cp437_DOSLatinUS to Unicode table
1306     // # Unicode version: 1.1
1307     // # Table version: 1.1
1308     // # Table format: Format A
1309     // # Date: 03/31/95
1310     // # Authors: Michel Suignard <michelsu@microsoft.com>
1311     // # Lori Hoerth <lorih@microsoft.com>
1312     // # General notes: none
1313     // #
1314     // # Format: Three tab-separated columns
1315     // # Column #1 is the cp1255_WinHebrew code (in hex)
1316     // # Column #2 is the Unicode (in hex as 0xXXXX)
1317     // # Column #3 is the Unicode name (follows a comment sign, '#')
1318     // #
1319     // # The entries are in cp437_DOSLatinUS order
1320     // #
1321 
1322     0x0000, // #NULL
1323     0x0001, // #START OF HEADING
1324     0x0002, // #START OF TEXT
1325     0x0003, // #END OF TEXT
1326     0x0004, // #END OF TRANSMISSION
1327     0x0005, // #ENQUIRY
1328     0x0006, // #ACKNOWLEDGE
1329     0x0007, // #BELL
1330     0x0008, // #BACKSPACE
1331     0x0009, // #HORIZONTAL TABULATION
1332     0x000a, // #LINE FEED
1333     0x000b, // #VERTICAL TABULATION
1334     0x000c, // #FORM FEED
1335     0x000d, // #CARRIAGE RETURN
1336     0x000e, // #SHIFT OUT
1337     0x000f, // #SHIFT IN
1338     0x0010, // #DATA LINK ESCAPE
1339     0x0011, // #DEVICE CONTROL ONE
1340     0x0012, // #DEVICE CONTROL TWO
1341     0x0013, // #DEVICE CONTROL THREE
1342     0x0014, // #DEVICE CONTROL FOUR
1343     0x0015, // #NEGATIVE ACKNOWLEDGE
1344     0x0016, // #SYNCHRONOUS IDLE
1345     0x0017, // #END OF TRANSMISSION BLOCK
1346     0x0018, // #CANCEL
1347     0x0019, // #END OF MEDIUM
1348     0x001a, // #SUBSTITUTE
1349     0x001b, // #ESCAPE
1350     0x001c, // #FILE SEPARATOR
1351     0x001d, // #GROUP SEPARATOR
1352     0x001e, // #RECORD SEPARATOR
1353     0x001f, // #UNIT SEPARATOR
1354     0x0020, // #SPACE
1355     0x0021, // #EXCLAMATION MARK
1356     0x0022, // #QUOTATION MARK
1357     0x0023, // #NUMBER SIGN
1358     0x0024, // #DOLLAR SIGN
1359     0x0025, // #PERCENT SIGN
1360     0x0026, // #AMPERSAND
1361     0x0027, // #APOSTROPHE
1362     0x0028, // #LEFT PARENTHESIS
1363     0x0029, // #RIGHT PARENTHESIS
1364     0x002a, // #ASTERISK
1365     0x002b, // #PLUS SIGN
1366     0x002c, // #COMMA
1367     0x002d, // #HYPHEN-MINUS
1368     0x002e, // #FULL STOP
1369     0x002f, // #SOLIDUS
1370     0x0030, // #DIGIT ZERO
1371     0x0031, // #DIGIT ONE
1372     0x0032, // #DIGIT TWO
1373     0x0033, // #DIGIT THREE
1374     0x0034, // #DIGIT FOUR
1375     0x0035, // #DIGIT FIVE
1376     0x0036, // #DIGIT SIX
1377     0x0037, // #DIGIT SEVEN
1378     0x0038, // #DIGIT EIGHT
1379     0x0039, // #DIGIT NINE
1380     0x003a, // #COLON
1381     0x003b, // #SEMICOLON
1382     0x003c, // #LESS-THAN SIGN
1383     0x003d, // #EQUALS SIGN
1384     0x003e, // #GREATER-THAN SIGN
1385     0x003f, // #QUESTION MARK
1386     0x0040, // #COMMERCIAL AT
1387     0x0041, // #LATIN CAPITAL LETTER A
1388     0x0042, // #LATIN CAPITAL LETTER B
1389     0x0043, // #LATIN CAPITAL LETTER C
1390     0x0044, // #LATIN CAPITAL LETTER D
1391     0x0045, // #LATIN CAPITAL LETTER E
1392     0x0046, // #LATIN CAPITAL LETTER F
1393     0x0047, // #LATIN CAPITAL LETTER G
1394     0x0048, // #LATIN CAPITAL LETTER H
1395     0x0049, // #LATIN CAPITAL LETTER I
1396     0x004a, // #LATIN CAPITAL LETTER J
1397     0x004b, // #LATIN CAPITAL LETTER K
1398     0x004c, // #LATIN CAPITAL LETTER L
1399     0x004d, // #LATIN CAPITAL LETTER M
1400     0x004e, // #LATIN CAPITAL LETTER N
1401     0x004f, // #LATIN CAPITAL LETTER O
1402     0x0050, // #LATIN CAPITAL LETTER P
1403     0x0051, // #LATIN CAPITAL LETTER Q
1404     0x0052, // #LATIN CAPITAL LETTER R
1405     0x0053, // #LATIN CAPITAL LETTER S
1406     0x0054, // #LATIN CAPITAL LETTER T
1407     0x0055, // #LATIN CAPITAL LETTER U
1408     0x0056, // #LATIN CAPITAL LETTER V
1409     0x0057, // #LATIN CAPITAL LETTER W
1410     0x0058, // #LATIN CAPITAL LETTER X
1411     0x0059, // #LATIN CAPITAL LETTER Y
1412     0x005a, // #LATIN CAPITAL LETTER Z
1413     0x005b, // #LEFT SQUARE BRACKET
1414     0x005c, // #REVERSE SOLIDUS
1415     0x005d, // #RIGHT SQUARE BRACKET
1416     0x005e, // #CIRCUMFLEX ACCENT
1417     0x005f, // #LOW LINE
1418     0x0060, // #GRAVE ACCENT
1419     0x0061, // #LATIN SMALL LETTER A
1420     0x0062, // #LATIN SMALL LETTER B
1421     0x0063, // #LATIN SMALL LETTER C
1422     0x0064, // #LATIN SMALL LETTER D
1423     0x0065, // #LATIN SMALL LETTER E
1424     0x0066, // #LATIN SMALL LETTER F
1425     0x0067, // #LATIN SMALL LETTER G
1426     0x0068, // #LATIN SMALL LETTER H
1427     0x0069, // #LATIN SMALL LETTER I
1428     0x006a, // #LATIN SMALL LETTER J
1429     0x006b, // #LATIN SMALL LETTER K
1430     0x006c, // #LATIN SMALL LETTER L
1431     0x006d, // #LATIN SMALL LETTER M
1432     0x006e, // #LATIN SMALL LETTER N
1433     0x006f, // #LATIN SMALL LETTER O
1434     0x0070, // #LATIN SMALL LETTER P
1435     0x0071, // #LATIN SMALL LETTER Q
1436     0x0072, // #LATIN SMALL LETTER R
1437     0x0073, // #LATIN SMALL LETTER S
1438     0x0074, // #LATIN SMALL LETTER T
1439     0x0075, // #LATIN SMALL LETTER U
1440     0x0076, // #LATIN SMALL LETTER V
1441     0x0077, // #LATIN SMALL LETTER W
1442     0x0078, // #LATIN SMALL LETTER X
1443     0x0079, // #LATIN SMALL LETTER Y
1444     0x007a, // #LATIN SMALL LETTER Z
1445     0x007b, // #LEFT CURLY BRACKET
1446     0x007c, // #VERTICAL LINE
1447     0x007d, // #RIGHT CURLY BRACKET
1448     0x007e, // #TILDE
1449     0x007f, // #DELETE
1450     0x00c7, // #LATIN CAPITAL LETTER C WITH CEDILLA
1451     0x00fc, // #LATIN SMALL LETTER U WITH DIAERESIS
1452     0x00e9, // #LATIN SMALL LETTER E WITH ACUTE
1453     0x00e2, // #LATIN SMALL LETTER A WITH CIRCUMFLEX
1454     0x00e4, // #LATIN SMALL LETTER A WITH DIAERESIS
1455     0x00e0, // #LATIN SMALL LETTER A WITH GRAVE
1456     0x00e5, // #LATIN SMALL LETTER A WITH RING ABOVE
1457     0x00e7, // #LATIN SMALL LETTER C WITH CEDILLA
1458     0x00ea, // #LATIN SMALL LETTER E WITH CIRCUMFLEX
1459     0x00eb, // #LATIN SMALL LETTER E WITH DIAERESIS
1460     0x00e8, // #LATIN SMALL LETTER E WITH GRAVE
1461     0x00ef, // #LATIN SMALL LETTER I WITH DIAERESIS
1462     0x00ee, // #LATIN SMALL LETTER I WITH CIRCUMFLEX
1463     0x00ec, // #LATIN SMALL LETTER I WITH GRAVE
1464     0x00c4, // #LATIN CAPITAL LETTER A WITH DIAERESIS
1465     0x00c5, // #LATIN CAPITAL LETTER A WITH RING ABOVE
1466     0x00c9, // #LATIN CAPITAL LETTER E WITH ACUTE
1467     0x00e6, // #LATIN SMALL LIGATURE AE
1468     0x00c6, // #LATIN CAPITAL LIGATURE AE
1469     0x00f4, // #LATIN SMALL LETTER O WITH CIRCUMFLEX
1470     0x00f6, // #LATIN SMALL LETTER O WITH DIAERESIS
1471     0x00f2, // #LATIN SMALL LETTER O WITH GRAVE
1472     0x00fb, // #LATIN SMALL LETTER U WITH CIRCUMFLEX
1473     0x00f9, // #LATIN SMALL LETTER U WITH GRAVE
1474     0x00ff, // #LATIN SMALL LETTER Y WITH DIAERESIS
1475     0x00d6, // #LATIN CAPITAL LETTER O WITH DIAERESIS
1476     0x00dc, // #LATIN CAPITAL LETTER U WITH DIAERESIS
1477     0x00a2, // #CENT SIGN
1478     0x00a3, // #POUND SIGN
1479     0x00a5, // #YEN SIGN
1480     0x20a7, // #PESETA SIGN
1481     0x0192, // #LATIN SMALL LETTER F WITH HOOK
1482     0x00e1, // #LATIN SMALL LETTER A WITH ACUTE
1483     0x00ed, // #LATIN SMALL LETTER I WITH ACUTE
1484     0x00f3, // #LATIN SMALL LETTER O WITH ACUTE
1485     0x00fa, // #LATIN SMALL LETTER U WITH ACUTE
1486     0x00f1, // #LATIN SMALL LETTER N WITH TILDE
1487     0x00d1, // #LATIN CAPITAL LETTER N WITH TILDE
1488     0x00aa, // #FEMININE ORDINAL INDICATOR
1489     0x00ba, // #MASCULINE ORDINAL INDICATOR
1490     0x00bf, // #INVERTED QUESTION MARK
1491     0x2310, // #REVERSED NOT SIGN
1492     0x00ac, // #NOT SIGN
1493     0x00bd, // #VULGAR FRACTION ONE HALF
1494     0x00bc, // #VULGAR FRACTION ONE QUARTER
1495     0x00a1, // #INVERTED EXCLAMATION MARK
1496     0x00ab, // #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
1497     0x00bb, // #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
1498     0x2591, // #LIGHT SHADE
1499     0x2592, // #MEDIUM SHADE
1500     0x2593, // #DARK SHADE
1501     0x2502, // #BOX DRAWINGS LIGHT VERTICAL
1502     0x2524, // #BOX DRAWINGS LIGHT VERTICAL AND LEFT
1503     0x2561, // #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
1504     0x2562, // #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
1505     0x2556, // #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
1506     0x2555, // #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
1507     0x2563, // #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
1508     0x2551, // #BOX DRAWINGS DOUBLE VERTICAL
1509     0x2557, // #BOX DRAWINGS DOUBLE DOWN AND LEFT
1510     0x255d, // #BOX DRAWINGS DOUBLE UP AND LEFT
1511     0x255c, // #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
1512     0x255b, // #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
1513     0x2510, // #BOX DRAWINGS LIGHT DOWN AND LEFT
1514     0x2514, // #BOX DRAWINGS LIGHT UP AND RIGHT
1515     0x2534, // #BOX DRAWINGS LIGHT UP AND HORIZONTAL
1516     0x252c, // #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
1517     0x251c, // #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
1518     0x2500, // #BOX DRAWINGS LIGHT HORIZONTAL
1519     0x253c, // #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
1520     0x255e, // #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
1521     0x255f, // #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
1522     0x255a, // #BOX DRAWINGS DOUBLE UP AND RIGHT
1523     0x2554, // #BOX DRAWINGS DOUBLE DOWN AND RIGHT
1524     0x2569, // #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
1525     0x2566, // #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
1526     0x2560, // #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
1527     0x2550, // #BOX DRAWINGS DOUBLE HORIZONTAL
1528     0x256c, // #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
1529     0x2567, // #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
1530     0x2568, // #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
1531     0x2564, // #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
1532     0x2565, // #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
1533     0x2559, // #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
1534     0x2558, // #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
1535     0x2552, // #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
1536     0x2553, // #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
1537     0x256b, // #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
1538     0x256a, // #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
1539     0x2518, // #BOX DRAWINGS LIGHT UP AND LEFT
1540     0x250c, // #BOX DRAWINGS LIGHT DOWN AND RIGHT
1541     0x2588, // #FULL BLOCK
1542     0x2584, // #LOWER HALF BLOCK
1543     0x258c, // #LEFT HALF BLOCK
1544     0x2590, // #RIGHT HALF BLOCK
1545     0x2580, // #UPPER HALF BLOCK
1546     0x03b1, // #GREEK SMALL LETTER ALPHA
1547     0x00df, // #LATIN SMALL LETTER SHARP S
1548     0x0393, // #GREEK CAPITAL LETTER GAMMA
1549     0x03c0, // #GREEK SMALL LETTER PI
1550     0x03a3, // #GREEK CAPITAL LETTER SIGMA
1551     0x03c3, // #GREEK SMALL LETTER SIGMA
1552     0x00b5, // #MICRO SIGN
1553     0x03c4, // #GREEK SMALL LETTER TAU
1554     0x03a6, // #GREEK CAPITAL LETTER PHI
1555     0x0398, // #GREEK CAPITAL LETTER THETA
1556     0x03a9, // #GREEK CAPITAL LETTER OMEGA
1557     0x03b4, // #GREEK SMALL LETTER DELTA
1558     0x221e, // #INFINITY
1559     0x03c6, // #GREEK SMALL LETTER PHI
1560     0x03b5, // #GREEK SMALL LETTER EPSILON
1561     0x2229, // #INTERSECTION
1562     0x2261, // #IDENTICAL TO
1563     0x00b1, // #PLUS-MINUS SIGN
1564     0x2265, // #GREATER-THAN OR EQUAL TO
1565     0x2264, // #LESS-THAN OR EQUAL TO
1566     0x2320, // #TOP HALF INTEGRAL
1567     0x2321, // #BOTTOM HALF INTEGRAL
1568     0x00f7, // #DIVISION SIGN
1569     0x2248, // #ALMOST EQUAL TO
1570     0x00b0, // #DEGREE SIGN
1571     0x2219, // #BULLET OPERATOR
1572     0x00b7, // #MIDDLE DOT
1573     0x221a, // #SQUARE ROOT
1574     0x207f, // #SUPERSCRIPT LATIN SMALL LETTER N
1575     0x00b2, // #SUPERSCRIPT TWO
1576     0x25a0, // #BLACK SQUARE
1577     0x00a0, // #NO-BREAK SPACE
1578   };
1579 
map_cp850_unicode(char x)1580   public char map_cp850_unicode(char x) {
1581     if (x >= 0x100) {
1582       return x;
1583     }
1584     return unimap[x];
1585   }
1586 
_SetCursor(int row, int col)1587   private void _SetCursor(int row, int col) {
1588     int maxr = height - 1;
1589     int tm = getTopMargin();
1590 
1591     R = (row < 0) ? 0 : row;
1592     C = (col < 0) ? 0 : (col >= width) ? width - 1 : col;
1593 
1594     if (!moveoutsidemargins) {
1595       R += tm;
1596       maxr = getBottomMargin();
1597     }
1598     if (R > maxr) {
1599       R = maxr;
1600     }
1601   }
1602 
putChar(char c, boolean isWide, boolean doshowcursor)1603   private void putChar(char c, boolean isWide, boolean doshowcursor) {
1604     int rows = height; // statusline
1605     int columns = width;
1606     // byte msg[];
1607 
1608     // if (debug > 4) {
1609     // debugStr.append("putChar(")
1610     // .append(c)
1611     // .append(" [")
1612     // .append((int) c)
1613     // .append("]) at R=")
1614     // .append(R)
1615     // .append(" , C=")
1616     // .append(C)
1617     // .append(", columns=")
1618     // .append(columns)
1619     // .append(", rows=")
1620     // .append(rows);
1621     // debug(debugStr.toString());
1622     // debugStr.setLength(0);
1623     // }
1624     // markLine(R, 1);
1625     // if (c > 255) {
1626     // if (debug > 0)
1627     // debug("char > 255:" + (int) c);
1628     // //return;
1629     // }
1630 
1631     switch (term_state) {
1632     case TSTATE_DATA:
1633       /*
1634        * FIXME: we shouldn't use chars with bit 8 set if ibmcharset. probably... but some BBS do
1635        * anyway...
1636        */
1637       if (!useibmcharset) {
1638         boolean doneflag = true;
1639         switch (c) {
1640         case OSC:
1641           osc = "";
1642           term_state = TSTATE_OSC;
1643           break;
1644         case RI:
1645           if (R > getTopMargin()) {
1646             R--;
1647           } else {
1648             insertLine(R, 1, SCROLL_DOWN);
1649           }
1650           if (debug > 1) {
1651             debug("RI");
1652           }
1653           break;
1654         case IND:
1655           if (debug > 2) {
1656             debugStr.append("IND at ").append(R).append(", tm is ").append(getTopMargin())
1657                 .append(", bm is ").append(getBottomMargin());
1658             debug(debugStr.toString());
1659             debugStr.setLength(0);
1660           }
1661           if (R == getBottomMargin() || R == rows - 1) {
1662             insertLine(R, 1, SCROLL_UP);
1663           } else {
1664             R++;
1665           }
1666           if (debug > 1) {
1667             debug("IND (at " + R + " )");
1668           }
1669           break;
1670         case NEL:
1671           if (R == getBottomMargin() || R == rows - 1) {
1672             insertLine(R, 1, SCROLL_UP);
1673           } else {
1674             R++;
1675           }
1676           C = 0;
1677           if (debug > 1) {
1678             debug("NEL (at " + R + " )");
1679           }
1680           break;
1681         case HTS:
1682           Tabs[C] = 1;
1683           if (debug > 1) {
1684             debug("HTS");
1685           }
1686           break;
1687         case DCS:
1688           dcs = "";
1689           term_state = TSTATE_DCS;
1690           break;
1691         default:
1692           doneflag = false;
1693           break;
1694         }
1695         if (doneflag) {
1696           break;
1697         }
1698       }
1699       switch (c) {
1700       case SS3:
1701         onegl = 3;
1702         break;
1703       case SS2:
1704         onegl = 2;
1705         break;
1706       case CSI: // should be in the 8bit section, but some BBS use this
1707         DCEvar = 0;
1708         DCEvars[0] = 0;
1709         DCEvars[1] = 0;
1710         DCEvars[2] = 0;
1711         DCEvars[3] = 0;
1712         term_state = TSTATE_CSI;
1713         break;
1714       case ESC:
1715         term_state = TSTATE_ESC;
1716         lastwaslf = 0;
1717         break;
1718       case 5: /* ENQ */
1719         write(answerBack, false);
1720         break;
1721       case 12:
1722         /* FormFeed, Home for the BBS world */
1723         deleteArea(0, 0, columns, rows, attributes);
1724         C = R = 0;
1725         break;
1726       case '\b': /* 8 */
1727         C--;
1728         if (C < 0) {
1729           C = 0;
1730         }
1731         lastwaslf = 0;
1732         break;
1733       case '\t':
1734         do {
1735           // Don't overwrite or insert! TABS are not destructive, but movement!
1736           C++;
1737         } while (C < columns && (Tabs[C] == 0));
1738         lastwaslf = 0;
1739         break;
1740       case '\r': // 13 CR
1741         C = 0;
1742         break;
1743       case '\n': // 10 LF
1744         if (debug > 3) {
1745           debug("R= " + R + ", bm " + getBottomMargin() + ", tm=" + getTopMargin() + ", rows="
1746               + rows);
1747         }
1748         if (!vms) {
1749           if (lastwaslf != 0 && lastwaslf != c) {
1750             break;
1751           }
1752           lastwaslf = c;
1753           /* C = 0; */
1754         }
1755         if (R == getBottomMargin() || R >= rows - 1) {
1756           insertLine(R, 1, SCROLL_UP);
1757         } else {
1758           R++;
1759         }
1760         break;
1761       case 7:
1762         beep();
1763         break;
1764       case '\016': /* SMACS , as */
1765         /* ^N, Shift out - Put G1 into GL */
1766         gl = 1;
1767         usedcharsets = true;
1768         break;
1769       case '\017': /* RMACS , ae */
1770         /* ^O, Shift in - Put G0 into GL */
1771         gl = 0;
1772         usedcharsets = true;
1773         break;
1774       default: {
1775         int thisgl = gl;
1776 
1777         if (onegl >= 0) {
1778           thisgl = onegl;
1779           onegl = -1;
1780         }
1781         lastwaslf = 0;
1782         if (c < 32) {
1783           if (c != 0) {
1784             if (debug > 0) {
1785               debug("TSTATE_DATA char: " + ((int) c));
1786             }
1787           }
1788           /* break; some BBS really want those characters, like hearst etc. */
1789           if (c == 0) {
1790             break;
1791           }
1792         }
1793         if (C >= columns) {
1794           if (wraparound) {
1795             int bot = rows;
1796 
1797             // If we're in the scroll region, check against the bottom margin
1798             if (R <= getBottomMargin() && R >= getTopMargin()) {
1799               bot = getBottomMargin() + 1;
1800             }
1801 
1802             if (R < bot - 1) {
1803               R++;
1804             } else {
1805               if (debug > 3) {
1806                 debug("scrolling due to wrap at " + R);
1807               }
1808               insertLine(R, 1, SCROLL_UP);
1809             }
1810             C = 0;
1811           } else {
1812             // cursor stays on last character.
1813             C = columns - 1;
1814           }
1815         }
1816 
1817         boolean mapped = false;
1818 
1819         // Mapping if DEC Special is chosen charset
1820         if (usedcharsets) {
1821           if (c >= '\u0020' && c <= '\u007f') {
1822             switch (gx[thisgl]) {
1823             case '0':
1824               // Remap SCOANSI line drawing to VT100 line drawing chars
1825               // for our SCO using customers.
1826               if (terminalID.equals("scoansi") || terminalID.equals("ansi")) {
1827                 for (int i = 0; i < scoansi_acs.length(); i += 2) {
1828                   if (c == scoansi_acs.charAt(i)) {
1829                     c = scoansi_acs.charAt(i + 1);
1830                     break;
1831                   }
1832                 }
1833               }
1834               if (c >= '\u005f' && c <= '\u007e') {
1835                 c = DECSPECIAL[(short) c - 0x5f];
1836                 mapped = true;
1837               }
1838               break;
1839             case '<': // 'user preferred' is currently 'ISO Latin-1 suppl
1840               c = (char) ((c & 0x7f) | 0x80);
1841               mapped = true;
1842               break;
1843             case 'A':
1844             case 'B': // Latin-1 , ASCII -> fall through
1845               mapped = true;
1846               break;
1847             default:
1848               debug("Unsupported GL mapping: " + gx[thisgl]);
1849               break;
1850             }
1851           }
1852           if (!mapped && (c >= '\u0080' && c <= '\u00ff')) {
1853             switch (gx[gr]) {
1854             case '0':
1855               if (c >= '\u00df' && c <= '\u00fe') {
1856                 c = DECSPECIAL[c - '\u00df'];
1857                 mapped = true;
1858               }
1859               break;
1860             case '<':
1861             case 'A':
1862             case 'B':
1863               mapped = true;
1864               break;
1865             default:
1866               debug("Unsupported GR mapping: " + gx[gr]);
1867               break;
1868             }
1869           }
1870         }
1871         if (!mapped && useibmcharset) {
1872           c = map_cp850_unicode(c);
1873         }
1874 
1875         /* if(true || (statusmode == 0)) { */
1876         if (isWide) {
1877           if (C >= columns - 1) {
1878             if (wraparound) {
1879               int bot = rows;
1880 
1881               // If we're in the scroll region, check against the bottom margin
1882               if (R <= getBottomMargin() && R >= getTopMargin()) {
1883                 bot = getBottomMargin() + 1;
1884               }
1885 
1886               if (R < bot - 1) {
1887                 R++;
1888               } else {
1889                 if (debug > 3) {
1890                   debug("scrolling due to wrap at " + R);
1891                 }
1892                 insertLine(R, 1, SCROLL_UP);
1893               }
1894               C = 0;
1895             } else {
1896               // cursor stays on last wide character.
1897               C = columns - 2;
1898             }
1899           }
1900         }
1901 
1902         if (insertmode == 1) {
1903           if (isWide) {
1904             insertChar(C++, R, c, attributes | FULLWIDTH);
1905             insertChar(C, R, ' ', attributes | FULLWIDTH);
1906           } else {
1907             insertChar(C, R, c, attributes);
1908           }
1909         } else {
1910           if (isWide) {
1911             putChar(C++, R, c, attributes | FULLWIDTH);
1912             putChar(C, R, ' ', attributes | FULLWIDTH);
1913           } else {
1914             putChar(C, R, c, attributes);
1915           }
1916         }
1917 
1918         /*
1919          * } else { if (insertmode==1) { insertChar(C, rows, c, attributes); } else { putChar(C,
1920          * rows, c, attributes); } }
1921          */
1922         C++;
1923         break;
1924       }
1925       } /* switch(c) */
1926       break;
1927     case TSTATE_OSC:
1928       if ((c < 0x20) && (c != ESC)) {// NP - No printing character
1929         handle_osc(osc);
1930         term_state = TSTATE_DATA;
1931         break;
1932       }
1933       // but check for vt102 ESC \
1934       if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) {
1935         handle_osc(osc);
1936         term_state = TSTATE_DATA;
1937         break;
1938       }
1939       osc = osc + c;
1940       break;
1941     case TSTATE_ESCSPACE:
1942       term_state = TSTATE_DATA;
1943       switch (c) {
1944       case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */
1945         output8bit = false;
1946         break;
1947       case 'G': /* S8C1T, Enable output of 8-bit control codes */
1948         output8bit = true;
1949         break;
1950       default:
1951         debug("ESC <space> " + c + " unhandled.");
1952       }
1953       break;
1954     case TSTATE_ESC:
1955       term_state = TSTATE_DATA;
1956       switch (c) {
1957       case ' ':
1958         term_state = TSTATE_ESCSPACE;
1959         break;
1960       case '#':
1961         term_state = TSTATE_ESCSQUARE;
1962         break;
1963       case 'c':
1964         /* Hard terminal reset */
1965         reset();
1966         break;
1967       case '[':
1968         DCEvar = 0;
1969         DCEvars[0] = 0;
1970         DCEvars[1] = 0;
1971         DCEvars[2] = 0;
1972         DCEvars[3] = 0;
1973         term_state = TSTATE_CSI;
1974         break;
1975       case ']':
1976         osc = "";
1977         term_state = TSTATE_OSC;
1978         break;
1979       case 'P':
1980         dcs = "";
1981         term_state = TSTATE_DCS;
1982         break;
1983       case 'A': /* CUU */
1984         R--;
1985         if (R < 0) {
1986           R = 0;
1987         }
1988         break;
1989       case 'B': /* CUD */
1990         R++;
1991         if (R >= rows) {
1992           R = rows - 1;
1993         }
1994         break;
1995       case 'C':
1996         C++;
1997         if (C >= columns) {
1998           C = columns - 1;
1999         }
2000         break;
2001       case 'I': // RI
2002         insertLine(R, 1, SCROLL_DOWN);
2003         break;
2004       case 'E': /* NEL */
2005         if (R == getBottomMargin() || R == rows - 1) {
2006           insertLine(R, 1, SCROLL_UP);
2007         } else {
2008           R++;
2009         }
2010         C = 0;
2011         if (debug > 1) {
2012           debug("ESC E (at " + R + ")");
2013         }
2014         break;
2015       case 'D': /* IND */
2016         if (R == getBottomMargin() || R == rows - 1) {
2017           insertLine(R, 1, SCROLL_UP);
2018         } else {
2019           R++;
2020         }
2021         if (debug > 1) {
2022           debug("ESC D (at " + R + " )");
2023         }
2024         break;
2025       case 'J': /* erase to end of screen */
2026         if (R < rows - 1) {
2027           deleteArea(0, R + 1, columns, rows - R - 1, attributes);
2028         }
2029         if (C < columns - 1) {
2030           deleteArea(C, R, columns - C, 1, attributes);
2031         }
2032         break;
2033       case 'K':
2034         if (C < columns - 1) {
2035           deleteArea(C, R, columns - C, 1, attributes);
2036         }
2037         break;
2038       case 'M': // RI
2039         debug("ESC M : R is " + R + ", tm is " + getTopMargin() + ", bm is " + getBottomMargin());
2040         if (R > getTopMargin()) { // just go up 1 line.
2041           R--;
2042         } else { // scroll down
2043           insertLine(R, 1, SCROLL_DOWN);
2044         }
2045         /* else do nothing ; */
2046         if (debug > 2) {
2047           debug("ESC M ");
2048         }
2049         break;
2050       case 'H':
2051         if (debug > 1) {
2052           debug("ESC H at " + C);
2053         }
2054         /* right border probably ... */
2055         if (C >= columns) {
2056           C = columns - 1;
2057         }
2058         Tabs[C] = 1;
2059         break;
2060       case 'N': // SS2
2061         onegl = 2;
2062         break;
2063       case 'O': // SS3
2064         onegl = 3;
2065         break;
2066       case '=':
2067         /* application keypad */
2068         if (debug > 0) {
2069           debug("ESC =");
2070         }
2071         keypadmode = true;
2072         break;
2073       case '<': /* vt52 mode off */
2074         vt52mode = false;
2075         break;
2076       case '>': /* normal keypad */
2077         if (debug > 0) {
2078           debug("ESC >");
2079         }
2080         keypadmode = false;
2081         break;
2082       case '7': /* DECSC: save cursor, attributes */
2083         Sc = C;
2084         Sr = R;
2085         Sgl = gl;
2086         Sgr = gr;
2087         Sa = attributes;
2088         Sgx = new char[4];
2089         for (int i = 0; i < 4; i++) {
2090           Sgx[i] = gx[i];
2091         }
2092         if (debug > 1) {
2093           debug("ESC 7");
2094         }
2095         break;
2096       case '8': /* DECRC: restore cursor, attributes */
2097         C = Sc;
2098         R = Sr;
2099         gl = Sgl;
2100         gr = Sgr;
2101         if (Sgx != null) {
2102           for (int i = 0; i < 4; i++) {
2103             gx[i] = Sgx[i];
2104           }
2105         }
2106         attributes = Sa;
2107         if (debug > 1) {
2108           debug("ESC 8");
2109         }
2110         break;
2111       case '(': /* Designate G0 Character set (ISO 2022) */
2112         term_state = TSTATE_SETG0;
2113         usedcharsets = true;
2114         break;
2115       case ')': /* Designate G1 character set (ISO 2022) */
2116         term_state = TSTATE_SETG1;
2117         usedcharsets = true;
2118         break;
2119       case '*': /* Designate G2 Character set (ISO 2022) */
2120         term_state = TSTATE_SETG2;
2121         usedcharsets = true;
2122         break;
2123       case '+': /* Designate G3 Character set (ISO 2022) */
2124         term_state = TSTATE_SETG3;
2125         usedcharsets = true;
2126         break;
2127       case '~': /* Locking Shift 1, right */
2128         gr = 1;
2129         usedcharsets = true;
2130         break;
2131       case 'n': /* Locking Shift 2 */
2132         gl = 2;
2133         usedcharsets = true;
2134         break;
2135       case '}': /* Locking Shift 2, right */
2136         gr = 2;
2137         usedcharsets = true;
2138         break;
2139       case 'o': /* Locking Shift 3 */
2140         gl = 3;
2141         usedcharsets = true;
2142         break;
2143       case '|': /* Locking Shift 3, right */
2144         gr = 3;
2145         usedcharsets = true;
2146         break;
2147       case 'Y': /* vt52 cursor address mode , next chars are x,y */
2148         term_state = TSTATE_VT52Y;
2149         break;
2150       case '_':
2151         term_state = TSTATE_TITLE;
2152         break;
2153       case '\\':
2154         // TODO save title
2155         term_state = TSTATE_DATA;
2156         break;
2157       default:
2158         debug("ESC unknown letter: " + c + " (" + ((int) c) + ")");
2159         break;
2160       }
2161       break;
2162     case TSTATE_VT52X:
2163       C = c - 37;
2164       if (C < 0) {
2165         C = 0;
2166       } else if (C >= width) {
2167         C = width - 1;
2168       }
2169       term_state = TSTATE_VT52Y;
2170       break;
2171     case TSTATE_VT52Y:
2172       R = c - 37;
2173       if (R < 0) {
2174         R = 0;
2175       } else if (R >= height) {
2176         R = height - 1;
2177       }
2178       term_state = TSTATE_DATA;
2179       break;
2180     case TSTATE_SETG0:
2181       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2182         debug("ESC ( " + c + ": G0 char set?  (" + ((int) c) + ")");
2183       } else {
2184         if (debug > 2) {
2185           debug("ESC ( : G0 char set  (" + c + " " + ((int) c) + ")");
2186         }
2187         gx[0] = c;
2188       }
2189       term_state = TSTATE_DATA;
2190       break;
2191     case TSTATE_SETG1:
2192       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2193         debug("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?");
2194       } else {
2195         if (debug > 2) {
2196           debug("ESC ) :G1 char set  (" + c + " " + ((int) c) + ")");
2197         }
2198         gx[1] = c;
2199       }
2200       term_state = TSTATE_DATA;
2201       break;
2202     case TSTATE_SETG2:
2203       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2204         debug("ESC*:G2 char set?  (" + ((int) c) + ")");
2205       } else {
2206         if (debug > 2) {
2207           debug("ESC*:G2 char set  (" + c + " " + ((int) c) + ")");
2208         }
2209         gx[2] = c;
2210       }
2211       term_state = TSTATE_DATA;
2212       break;
2213     case TSTATE_SETG3:
2214       if (c != '0' && c != 'A' && c != 'B' && c != '<') {
2215         debug("ESC+:G3 char set?  (" + ((int) c) + ")");
2216       } else {
2217         if (debug > 2) {
2218           debug("ESC+:G3 char set  (" + c + " " + ((int) c) + ")");
2219         }
2220         gx[3] = c;
2221       }
2222       term_state = TSTATE_DATA;
2223       break;
2224     case TSTATE_ESCSQUARE:
2225       switch (c) {
2226       case '8':
2227         for (int i = 0; i < columns; i++) {
2228           for (int j = 0; j < rows; j++) {
2229             putChar(i, j, 'E', 0);
2230           }
2231         }
2232         break;
2233       default:
2234         debug("ESC # " + c + " not supported.");
2235         break;
2236       }
2237       term_state = TSTATE_DATA;
2238       break;
2239     case TSTATE_DCS:
2240       if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) {
2241         handle_dcs(dcs);
2242         term_state = TSTATE_DATA;
2243         break;
2244       }
2245       dcs = dcs + c;
2246       break;
2247 
2248     case TSTATE_DCEQ:
2249       term_state = TSTATE_DATA;
2250       switch (c) {
2251       case '0':
2252       case '1':
2253       case '2':
2254       case '3':
2255       case '4':
2256       case '5':
2257       case '6':
2258       case '7':
2259       case '8':
2260       case '9':
2261         DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2262         term_state = TSTATE_DCEQ;
2263         break;
2264       case ';':
2265         DCEvar++;
2266         DCEvars[DCEvar] = 0;
2267         term_state = TSTATE_DCEQ;
2268         break;
2269       case 's': // XTERM_SAVE missing!
2270         if (true || debug > 1) {
2271           debug("ESC [ ? " + DCEvars[0] + " s unimplemented!");
2272         }
2273         break;
2274       case 'r': // XTERM_RESTORE
2275         if (true || debug > 1) {
2276           debug("ESC [ ? " + DCEvars[0] + " r");
2277         }
2278         /* DEC Mode reset */
2279         for (int i = 0; i <= DCEvar; i++) {
2280           switch (DCEvars[i]) {
2281           case 3: /* 80 columns */
2282             setScreenSize(80, height, true);
2283             break;
2284           case 4: /* scrolling mode, smooth */
2285             break;
2286           case 5: /* light background */
2287             break;
2288           case 6: /* DECOM (Origin Mode) move inside margins. */
2289             moveoutsidemargins = true;
2290             break;
2291           case 7: /* DECAWM: Autowrap Mode */
2292             wraparound = false;
2293             break;
2294           case 12:/* local echo off */
2295             break;
2296           case 9: /* X10 mouse */
2297           case 1000: /* xterm style mouse report on */
2298           case 1001:
2299           case 1002:
2300           case 1003:
2301             mouserpt = DCEvars[i];
2302             break;
2303           default:
2304             debug("ESC [ ? " + DCEvars[0] + " r, unimplemented!");
2305           }
2306         }
2307         break;
2308       case 'h': // DECSET
2309         if (debug > 0) {
2310           debug("ESC [ ? " + DCEvars[0] + " h");
2311         }
2312         /* DEC Mode set */
2313         for (int i = 0; i <= DCEvar; i++) {
2314           switch (DCEvars[i]) {
2315           case 1: /* Application cursor keys */
2316             KeyUp[0] = "\u001bOA";
2317             KeyDown[0] = "\u001bOB";
2318             KeyRight[0] = "\u001bOC";
2319             KeyLeft[0] = "\u001bOD";
2320             break;
2321           case 2: /* DECANM */
2322             vt52mode = false;
2323             break;
2324           case 3: /* 132 columns */
2325             setScreenSize(132, height, true);
2326             break;
2327           case 6: /* DECOM: move inside margins. */
2328             moveoutsidemargins = false;
2329             break;
2330           case 7: /* DECAWM: Autowrap Mode */
2331             wraparound = true;
2332             break;
2333           case 25: /* turn cursor on */
2334             showCursor(true);
2335             break;
2336           case 9: /* X10 mouse */
2337           case 1000: /* xterm style mouse report on */
2338           case 1001:
2339           case 1002:
2340           case 1003:
2341             mouserpt = DCEvars[i];
2342             break;
2343 
2344           /* unimplemented stuff, fall through */
2345           /* 4 - scrolling mode, smooth */
2346           /* 5 - light background */
2347           /* 12 - local echo off */
2348           /* 18 - DECPFF - Printer Form Feed Mode -> On */
2349           /* 19 - DECPEX - Printer Extent Mode -> Screen */
2350           default:
2351             debug("ESC [ ? " + DCEvars[0] + " h, unsupported.");
2352             break;
2353           }
2354         }
2355         break;
2356       case 'i': // DEC Printer Control, autoprint, echo screenchars to printer
2357         // This is different to CSI i!
2358         // Also: "Autoprint prints a final display line only when the
2359         // cursor is moved off the line by an autowrap or LF, FF, or
2360         // VT (otherwise do not print the line)."
2361         switch (DCEvars[0]) {
2362         case 1:
2363           if (debug > 1) {
2364             debug("CSI ? 1 i : Print line containing cursor");
2365           }
2366           break;
2367         case 4:
2368           if (debug > 1) {
2369             debug("CSI ? 4 i : Start passthrough printing");
2370           }
2371           break;
2372         case 5:
2373           if (debug > 1) {
2374             debug("CSI ? 4 i : Stop passthrough printing");
2375           }
2376           break;
2377         }
2378         break;
2379       case 'l': // DECRST
2380         /* DEC Mode reset */
2381         if (debug > 0) {
2382           debug("ESC [ ? " + DCEvars[0] + " l");
2383         }
2384         for (int i = 0; i <= DCEvar; i++) {
2385           switch (DCEvars[i]) {
2386           case 1: /* Application cursor keys */
2387             KeyUp[0] = "\u001b[A";
2388             KeyDown[0] = "\u001b[B";
2389             KeyRight[0] = "\u001b[C";
2390             KeyLeft[0] = "\u001b[D";
2391             break;
2392           case 2: /* DECANM */
2393             vt52mode = true;
2394             break;
2395           case 3: /* 80 columns */
2396             setScreenSize(80, height, true);
2397             break;
2398           case 6: /* DECOM: move outside margins. */
2399             moveoutsidemargins = true;
2400             break;
2401           case 7: /* DECAWM: Autowrap Mode OFF */
2402             wraparound = false;
2403             break;
2404           case 25: /* turn cursor off */
2405             showCursor(false);
2406             break;
2407           /* Unimplemented stuff: */
2408           /* 4 - scrolling mode, jump */
2409           /* 5 - dark background */
2410           /* 7 - DECAWM - no wrap around mode */
2411           /* 12 - local echo on */
2412           /* 18 - DECPFF - Printer Form Feed Mode -> Off */
2413           /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */
2414           case 9: /* X10 mouse */
2415           case 1000: /* xterm style mouse report OFF */
2416           case 1001:
2417           case 1002:
2418           case 1003:
2419             mouserpt = 0;
2420             break;
2421           default:
2422             debug("ESC [ ? " + DCEvars[0] + " l, unsupported.");
2423             break;
2424           }
2425         }
2426         break;
2427       case 'n':
2428         if (debug > 0) {
2429           debug("ESC [ ? " + DCEvars[0] + " n");
2430         }
2431         switch (DCEvars[0]) {
2432         case 15:
2433           /* printer? no printer. */
2434           write((ESC) + "[?13n", false);
2435           debug("ESC[5n");
2436           break;
2437         default:
2438           debug("ESC [ ? " + DCEvars[0] + " n, unsupported.");
2439           break;
2440         }
2441         break;
2442       default:
2443         debug("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported.");
2444         break;
2445       }
2446       break;
2447     case TSTATE_CSI_EX:
2448       term_state = TSTATE_DATA;
2449       switch (c) {
2450       case ESC:
2451         term_state = TSTATE_ESC;
2452         break;
2453       default:
2454         debug("Unknown character ESC[! character is " + (int) c);
2455         break;
2456       }
2457       break;
2458     case TSTATE_CSI_TICKS:
2459       term_state = TSTATE_DATA;
2460       switch (c) {
2461       case 'p':
2462         debug("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]);
2463         if (DCEvars[0] == 61) {
2464           output8bit = false;
2465           break;
2466         }
2467         if (DCEvars[1] == 1) {
2468           output8bit = false;
2469         } else {
2470           output8bit = true; /* 0 or 2 */
2471         }
2472         break;
2473       default:
2474         debug("Unknown ESC [...  \"" + c);
2475         break;
2476       }
2477       break;
2478     case TSTATE_CSI_EQUAL:
2479       term_state = TSTATE_DATA;
2480       switch (c) {
2481       case '0':
2482       case '1':
2483       case '2':
2484       case '3':
2485       case '4':
2486       case '5':
2487       case '6':
2488       case '7':
2489       case '8':
2490       case '9':
2491         DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2492         term_state = TSTATE_CSI_EQUAL;
2493         break;
2494       case ';':
2495         DCEvar++;
2496         DCEvars[DCEvar] = 0;
2497         term_state = TSTATE_CSI_EQUAL;
2498         break;
2499 
2500       case 'F': /* SCO ANSI foreground */
2501       {
2502         int newcolor;
2503 
2504         debug("ESC [ = " + DCEvars[0] + " F");
2505 
2506         attributes &= ~COLOR_FG;
2507         newcolor = ((DCEvars[0] & 1) << 2) | (DCEvars[0] & 2) | ((DCEvars[0] & 4) >> 2);
2508         attributes |= (newcolor + 1) << COLOR_FG_SHIFT;
2509 
2510         break;
2511       }
2512       case 'G': /* SCO ANSI background */
2513       {
2514         int newcolor;
2515 
2516         debug("ESC [ = " + DCEvars[0] + " G");
2517 
2518         attributes &= ~COLOR_BG;
2519         newcolor = ((DCEvars[0] & 1) << 2) | (DCEvars[0] & 2) | ((DCEvars[0] & 4) >> 2);
2520         attributes |= (newcolor + 1) << COLOR_BG_SHIFT;
2521         break;
2522       }
2523 
2524       default:
2525         debugStr.append("Unknown ESC [ = ");
2526         for (int i = 0; i <= DCEvar; i++) {
2527           debugStr.append(DCEvars[i]).append(',');
2528         }
2529         debugStr.append(c);
2530         debug(debugStr.toString());
2531         debugStr.setLength(0);
2532         break;
2533       }
2534       break;
2535     case TSTATE_CSI_DOLLAR:
2536       term_state = TSTATE_DATA;
2537       switch (c) {
2538       case '}':
2539         debug("Active Status Display now " + DCEvars[0]);
2540         statusmode = DCEvars[0];
2541         break;
2542       /*
2543        * bad documentation? case '-': debug("Set Status Display now "+DCEvars[0]); break;
2544        */
2545       case '~':
2546         debug("Status Line mode now " + DCEvars[0]);
2547         break;
2548       default:
2549         debug("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]);
2550         break;
2551       }
2552       break;
2553     case TSTATE_CSI:
2554       term_state = TSTATE_DATA;
2555       switch (c) {
2556       case '"':
2557         term_state = TSTATE_CSI_TICKS;
2558         break;
2559       case '$':
2560         term_state = TSTATE_CSI_DOLLAR;
2561         break;
2562       case '=':
2563         term_state = TSTATE_CSI_EQUAL;
2564         break;
2565       case '!':
2566         term_state = TSTATE_CSI_EX;
2567         break;
2568       case '?':
2569         DCEvar = 0;
2570         DCEvars[0] = 0;
2571         term_state = TSTATE_DCEQ;
2572         break;
2573       case '0':
2574       case '1':
2575       case '2':
2576       case '3':
2577       case '4':
2578       case '5':
2579       case '6':
2580       case '7':
2581       case '8':
2582       case '9':
2583         DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
2584         term_state = TSTATE_CSI;
2585         break;
2586       case ';':
2587         DCEvar++;
2588         DCEvars[DCEvar] = 0;
2589         term_state = TSTATE_CSI;
2590         break;
2591       case 'c':/* send primary device attributes */
2592         /* send (ESC[?61c) */
2593 
2594         String subcode = "";
2595         if (terminalID.equals("vt320")) {
2596           subcode = "63;";
2597         }
2598         if (terminalID.equals("vt220")) {
2599           subcode = "62;";
2600         }
2601         if (terminalID.equals("vt100")) {
2602           subcode = "61;";
2603         }
2604         write((ESC) + "[?" + subcode + "1;2c", false);
2605         if (debug > 1) {
2606           debug("ESC [ " + DCEvars[0] + " c");
2607         }
2608         break;
2609       case 'q':
2610         if (debug > 1) {
2611           debug("ESC [ " + DCEvars[0] + " q");
2612         }
2613         break;
2614       case 'g':
2615         /* used for tabsets */
2616         switch (DCEvars[0]) {
2617         case 3:/* clear them */
2618           Tabs = new byte[width];
2619           break;
2620         case 0:
2621           Tabs[C] = 0;
2622           break;
2623         }
2624         if (debug > 1) {
2625           debug("ESC [ " + DCEvars[0] + " g");
2626         }
2627         break;
2628       case 'h':
2629         switch (DCEvars[0]) {
2630         case 4:
2631           insertmode = 1;
2632           break;
2633         case 20:
2634           debug("Setting CRLF to TRUE");
2635           sendcrlf = true;
2636           break;
2637         default:
2638           debug("unsupported: ESC [ " + DCEvars[0] + " h");
2639           break;
2640         }
2641         if (debug > 1) {
2642           debug("ESC [ " + DCEvars[0] + " h");
2643         }
2644         break;
2645       case 'i': // Printer Controller mode.
2646         // "Transparent printing sends all output, except the CSI 4 i
2647         // termination string, to the printer and not the screen,
2648         // uses an 8-bit channel if no parity so NUL and DEL will be
2649         // seen by the printer and by the termination recognizer code,
2650         // and all translation and character set selections are
2651         // bypassed."
2652         switch (DCEvars[0]) {
2653         case 0:
2654           if (debug > 1) {
2655             debug("CSI 0 i:  Print Screen, not implemented.");
2656           }
2657           break;
2658         case 4:
2659           if (debug > 1) {
2660             debug("CSI 4 i:  Enable Transparent Printing, not implemented.");
2661           }
2662           break;
2663         case 5:
2664           if (debug > 1) {
2665             debug("CSI 4/5 i:  Disable Transparent Printing, not implemented.");
2666           }
2667           break;
2668         default:
2669           debug("ESC [ " + DCEvars[0] + " i, unimplemented!");
2670         }
2671         break;
2672       case 'l':
2673         switch (DCEvars[0]) {
2674         case 4:
2675           insertmode = 0;
2676           break;
2677         case 20:
2678           debug("Setting CRLF to FALSE");
2679           sendcrlf = false;
2680           break;
2681         default:
2682           debug("ESC [ " + DCEvars[0] + " l, unimplemented!");
2683           break;
2684         }
2685         break;
2686       case 'A': // CUU
2687       {
2688         int limit;
2689         /* FIXME: xterm only cares about 0 and topmargin */
2690         if (R >= getTopMargin()) {
2691           limit = getTopMargin();
2692         } else {
2693           limit = 0;
2694         }
2695         if (DCEvars[0] == 0) {
2696           R--;
2697         } else {
2698           R -= DCEvars[0];
2699         }
2700         if (R < limit) {
2701           R = limit;
2702         }
2703         if (debug > 1) {
2704           debug("ESC [ " + DCEvars[0] + " A");
2705         }
2706         break;
2707       }
2708       case 'B': // CUD
2709         /* cursor down n (1) times */
2710       {
2711         int limit;
2712         if (R <= getBottomMargin()) {
2713           limit = getBottomMargin();
2714         } else {
2715           limit = rows - 1;
2716         }
2717         if (DCEvars[0] == 0) {
2718           R++;
2719         } else {
2720           R += DCEvars[0];
2721         }
2722         if (R > limit) {
2723           R = limit;
2724         } else {
2725           if (debug > 2) {
2726             debug("Not limited.");
2727           }
2728         }
2729         if (debug > 2) {
2730           debug("to: " + R);
2731         }
2732         if (debug > 1) {
2733           debug("ESC [ " + DCEvars[0] + " B (at C=" + C + ")");
2734         }
2735         break;
2736       }
2737       case 'C':
2738         if (DCEvars[0] == 0) {
2739           DCEvars[0] = 1;
2740         }
2741         while (DCEvars[0]-- > 0) {
2742           C++;
2743         }
2744         if (C >= columns) {
2745           C = columns - 1;
2746         }
2747         if (debug > 1) {
2748           debug("ESC [ " + DCEvars[0] + " C");
2749         }
2750         break;
2751       case 'd': // CVA
2752         R = DCEvars[0];
2753         if (R < 0) {
2754           R = 0;
2755         } else if (R >= height) {
2756           R = height - 1;
2757         }
2758         if (debug > 1) {
2759           debug("ESC [ " + DCEvars[0] + " d");
2760         }
2761         break;
2762       case 'D':
2763         if (DCEvars[0] == 0) {
2764           DCEvars[0] = 1;
2765         }
2766         while (DCEvars[0]-- > 0) {
2767           C--;
2768         }
2769         if (C < 0) {
2770           C = 0;
2771         }
2772         if (debug > 1) {
2773           debug("ESC [ " + DCEvars[0] + " D");
2774         }
2775         break;
2776       case 'r': // DECSTBM
2777         if (DCEvar > 0) // Ray: Any argument is optional
2778         {
2779           R = DCEvars[1] - 1;
2780           if (R < 0) {
2781             R = rows - 1;
2782           } else if (R >= rows) {
2783             R = rows - 1;
2784           }
2785         } else {
2786           R = rows - 1;
2787         }
2788         int bot = R;
2789         if (R >= DCEvars[0]) {
2790           R = DCEvars[0] - 1;
2791           if (R < 0) {
2792             R = 0;
2793           }
2794         }
2795         setMargins(R, bot);
2796         _SetCursor(0, 0);
2797         if (debug > 1) {
2798           debug("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r");
2799         }
2800         break;
2801       case 'G': /* CUP / cursor absolute column */
2802         C = DCEvars[0];
2803         if (C < 0) {
2804           C = 0;
2805         } else if (C >= width) {
2806           C = width - 1;
2807         }
2808         if (debug > 1) {
2809           debug("ESC [ " + DCEvars[0] + " G");
2810         }
2811         break;
2812       case 'H': /* CUP / cursor position */
2813         /* gets 2 arguments */
2814         _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1);
2815         if (debug > 2) {
2816           debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins "
2817               + moveoutsidemargins);
2818           debug("	-> R now " + R + ", C now " + C);
2819         }
2820         break;
2821       case 'f': /* move cursor 2 */
2822         /* gets 2 arguments */
2823         R = DCEvars[0] - 1;
2824         C = DCEvars[1] - 1;
2825         if (C < 0) {
2826           C = 0;
2827         } else if (C >= width) {
2828           C = width - 1;
2829         }
2830         if (R < 0) {
2831           R = 0;
2832         } else if (R >= height) {
2833           R = height - 1;
2834         }
2835         if (debug > 2) {
2836           debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f");
2837         }
2838         break;
2839       case 'S': /* ind aka 'scroll forward' */
2840         if (DCEvars[0] == 0) {
2841           insertLine(rows - 1, SCROLL_UP);
2842         } else {
2843           insertLine(rows - 1, DCEvars[0], SCROLL_UP);
2844         }
2845         break;
2846       case 'L':
2847         /* insert n lines */
2848         if (DCEvars[0] == 0) {
2849           insertLine(R, SCROLL_DOWN);
2850         } else {
2851           insertLine(R, DCEvars[0], SCROLL_DOWN);
2852         }
2853         if (debug > 1) {
2854           debug("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")");
2855         }
2856         break;
2857       case 'T': /* 'ri' aka scroll backward */
2858         if (DCEvars[0] == 0) {
2859           insertLine(0, SCROLL_DOWN);
2860         } else {
2861           insertLine(0, DCEvars[0], SCROLL_DOWN);
2862         }
2863         break;
2864       case 'M':
2865         if (debug > 1) {
2866           debug("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R);
2867         }
2868         if (DCEvars[0] == 0) {
2869           deleteLine(R);
2870         } else {
2871           for (int i = 0; i < DCEvars[0]; i++) {
2872             deleteLine(R);
2873           }
2874         }
2875         break;
2876       case 'K':
2877         if (debug > 1) {
2878           debug("ESC [ " + DCEvars[0] + " K");
2879         }
2880         /* clear in line */
2881         switch (DCEvars[0]) {
2882         case 6: /* 97801 uses ESC[6K for delete to end of line */
2883         case 0:/* clear to right */
2884           if (C < columns - 1) {
2885             deleteArea(C, R, columns - C, 1, attributes);
2886           }
2887           break;
2888         case 1:/* clear to the left, including this */
2889           if (C > 0) {
2890             deleteArea(0, R, C + 1, 1, attributes);
2891           }
2892           break;
2893         case 2:/* clear whole line */
2894           deleteArea(0, R, columns, 1, attributes);
2895           break;
2896         }
2897         break;
2898       case 'J':
2899         /* clear below current line */
2900         switch (DCEvars[0]) {
2901         case 0:
2902           if (R < rows - 1) {
2903             deleteArea(0, R + 1, columns, rows - R - 1, attributes);
2904           }
2905           if (C < columns - 1) {
2906             deleteArea(C, R, columns - C, 1, attributes);
2907           }
2908           break;
2909         case 1:
2910           if (R > 0) {
2911             deleteArea(0, 0, columns, R, attributes);
2912           }
2913           if (C > 0) {
2914             deleteArea(0, R, C + 1, 1, attributes);// include up to and including current
2915           }
2916           break;
2917         case 2:
2918           deleteArea(0, 0, columns, rows, attributes);
2919           break;
2920         }
2921         if (debug > 1) {
2922           debug("ESC [ " + DCEvars[0] + " J");
2923         }
2924         break;
2925       case '@':
2926         if (debug > 1) {
2927           debug("ESC [ " + DCEvars[0] + " @");
2928         }
2929         for (int i = 0; i < DCEvars[0]; i++) {
2930           insertChar(C, R, ' ', attributes);
2931         }
2932         break;
2933       case 'X': {
2934         int toerase = DCEvars[0];
2935         if (debug > 1) {
2936           debug("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R);
2937         }
2938         if (toerase == 0) {
2939           toerase = 1;
2940         }
2941         if (toerase + C > columns) {
2942           toerase = columns - C;
2943         }
2944         deleteArea(C, R, toerase, 1, attributes);
2945         // does not change cursor position
2946         break;
2947       }
2948       case 'P':
2949         if (debug > 1) {
2950           debug("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R);
2951         }
2952         if (DCEvars[0] == 0) {
2953           DCEvars[0] = 1;
2954         }
2955         for (int i = 0; i < DCEvars[0]; i++) {
2956           deleteChar(C, R);
2957         }
2958         break;
2959       case 'n':
2960         switch (DCEvars[0]) {
2961         case 5: /* malfunction? No malfunction. */
2962           writeSpecial((ESC) + "[0n");
2963           if (debug > 1) {
2964             debug("ESC[5n");
2965           }
2966           break;
2967         case 6:
2968           // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize
2969           // FIXME check again.
2970           // FIXME: but vttest thinks different???
2971           writeSpecial((ESC) + "[" + R + ";" + C + "R");
2972           if (debug > 1) {
2973             debug("ESC[6n");
2974           }
2975           break;
2976         default:
2977           if (debug > 0) {
2978             debug("ESC [ " + DCEvars[0] + " n??");
2979           }
2980           break;
2981         }
2982         break;
2983       case 's': /* DECSC - save cursor */
2984         Sc = C;
2985         Sr = R;
2986         Sa = attributes;
2987         if (debug > 3) {
2988           debug("ESC[s");
2989         }
2990         break;
2991       case 'u': /* DECRC - restore cursor */
2992         C = Sc;
2993         R = Sr;
2994         attributes = Sa;
2995         if (debug > 3) {
2996           debug("ESC[u");
2997         }
2998         break;
2999       case 'm': /* attributes as color, bold , blink, */
3000         if (debug > 3) {
3001           debug("ESC [ ");
3002         }
3003         if (DCEvar == 0 && DCEvars[0] == 0) {
3004           attributes = 0;
3005         }
3006         for (int i = 0; i <= DCEvar; i++) {
3007           switch (DCEvars[i]) {
3008           case 0:
3009             if (DCEvar > 0) {
3010               if (terminalID.equals("scoansi")) {
3011                 attributes &= COLOR; /* Keeps color. Strange but true. */
3012               } else {
3013                 attributes = 0;
3014               }
3015             }
3016             break;
3017           case 1:
3018             attributes |= BOLD;
3019             attributes &= ~LOW;
3020             break;
3021           case 2:
3022             /* SCO color hack mode */
3023             if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) {
3024               int ncolor;
3025               attributes &= ~(COLOR | BOLD);
3026 
3027               ncolor = DCEvars[i + 1];
3028               if ((ncolor & 8) == 8) {
3029                 attributes |= BOLD;
3030               }
3031               ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
3032               attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT;
3033               ncolor = DCEvars[i + 2];
3034               ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
3035               attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT;
3036               i += 2;
3037             } else {
3038               attributes |= LOW;
3039             }
3040             break;
3041           case 3: /* italics */
3042             attributes |= INVERT;
3043             break;
3044           case 4:
3045             attributes |= UNDERLINE;
3046             break;
3047           case 7:
3048             attributes |= INVERT;
3049             break;
3050           case 8:
3051             attributes |= INVISIBLE;
3052             break;
3053           case 5: /* blink on */
3054             break;
3055           /*
3056            * 10 - ANSI X3.64-1979, select primary font, don't display control chars, don't set bit 8
3057            * on output
3058            */
3059           case 10:
3060             gl = 0;
3061             usedcharsets = true;
3062             break;
3063           /*
3064            * 11 - ANSI X3.64-1979, select second alt. font, display control chars, set bit 8 on
3065            * output
3066            */
3067           case 11: /* SMACS , as */
3068           case 12:
3069             gl = 1;
3070             usedcharsets = true;
3071             break;
3072           case 21: /* normal intensity */
3073             attributes &= ~(LOW | BOLD);
3074             break;
3075           case 23: /* italics off */
3076             attributes &= ~INVERT;
3077             break;
3078           case 25: /* blinking off */
3079             break;
3080           case 27:
3081             attributes &= ~INVERT;
3082             break;
3083           case 28:
3084             attributes &= ~INVISIBLE;
3085             break;
3086           case 24:
3087             attributes &= ~UNDERLINE;
3088             break;
3089           case 22:
3090             attributes &= ~BOLD;
3091             break;
3092           case 30:
3093           case 31:
3094           case 32:
3095           case 33:
3096           case 34:
3097           case 35:
3098           case 36:
3099           case 37:
3100             attributes &= ~COLOR_FG;
3101             attributes |= ((DCEvars[i] - 30) + 1) << COLOR_FG_SHIFT;
3102             break;
3103           case 38:
3104             if (DCEvars[i + 1] == 5) {
3105               attributes &= ~COLOR_FG;
3106               attributes |= ((DCEvars[i + 2]) + 1) << COLOR_FG_SHIFT;
3107               i += 2;
3108             }
3109             break;
3110           case 39:
3111             attributes &= ~COLOR_FG;
3112             break;
3113           case 40:
3114           case 41:
3115           case 42:
3116           case 43:
3117           case 44:
3118           case 45:
3119           case 46:
3120           case 47:
3121             attributes &= ~COLOR_BG;
3122             attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT;
3123             break;
3124           case 48:
3125             if (DCEvars[i + 1] == 5) {
3126               attributes &= ~COLOR_BG;
3127               attributes |= (DCEvars[i + 2] + 1) << COLOR_BG_SHIFT;
3128               i += 2;
3129             }
3130             break;
3131           case 49:
3132             attributes &= ~COLOR_BG;
3133             break;
3134           case 90:
3135           case 91:
3136           case 92:
3137           case 93:
3138           case 94:
3139           case 95:
3140           case 96:
3141           case 97:
3142             attributes &= ~COLOR_FG;
3143             attributes |= ((DCEvars[i] - 82) + 1) << COLOR_FG_SHIFT;
3144             break;
3145           case 100:
3146           case 101:
3147           case 102:
3148           case 103:
3149           case 104:
3150           case 105:
3151           case 106:
3152           case 107:
3153             attributes &= ~COLOR_BG;
3154             attributes |= ((DCEvars[i] - 92) + 1) << COLOR_BG_SHIFT;
3155             break;
3156 
3157           default:
3158             debugStr.append("ESC [ ").append(DCEvars[i]).append(" m unknown...");
3159             debug(debugStr.toString());
3160             debugStr.setLength(0);
3161             break;
3162           }
3163           if (debug > 3) {
3164             debugStr.append(DCEvars[i]).append(';');
3165             debug(debugStr.toString());
3166             debugStr.setLength(0);
3167           }
3168         }
3169         if (debug > 3) {
3170           debugStr.append(" (attributes = ").append(attributes).append(")m");
3171           debug(debugStr.toString());
3172           debugStr.setLength(0);
3173         }
3174         break;
3175       default:
3176         debugStr.append("ESC [ unknown letter: ").append(c).append(" (").append((int) c)
3177             .append(')');
3178         debug(debugStr.toString());
3179         debugStr.setLength(0);
3180         break;
3181       }
3182       break;
3183     case TSTATE_TITLE:
3184       switch (c) {
3185       case ESC:
3186         term_state = TSTATE_ESC;
3187         break;
3188       default:
3189         // TODO save title
3190         break;
3191       }
3192       break;
3193     default:
3194       term_state = TSTATE_DATA;
3195       break;
3196     }
3197 
3198     setCursorPosition(C, R);
3199   }
3200 
3201   /* hard reset the terminal */
reset()3202   public void reset() {
3203     gx[0] = 'B';
3204     gx[1] = 'B';
3205     gx[2] = 'B';
3206     gx[3] = 'B';
3207 
3208     gl = 0; // default GL to G0
3209     gr = 2; // default GR to G2
3210 
3211     onegl = -1; // Single shift override
3212 
3213     /* reset tabs */
3214     int nw = width;
3215     if (nw < 132) {
3216       nw = 132;
3217     }
3218     Tabs = new byte[nw];
3219     for (int i = 0; i < nw; i += 8) {
3220       Tabs[i] = 1;
3221     }
3222 
3223     deleteArea(0, 0, width, height, attributes);
3224     setMargins(0, height);
3225     C = R = 0;
3226     _SetCursor(0, 0);
3227 
3228     if (display != null) {
3229       display.resetColors();
3230     }
3231 
3232     showCursor(true);
3233     /* FIXME: */
3234     term_state = TSTATE_DATA;
3235   }
3236 }
3237