Home | History | Annotate | Download | only in terminal
      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 Meiner
     34  *
     35  * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
     36  * @author Matthias L. Jugel, Marcus Meiner
     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 
     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    */
     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    */
     71   public abstract void write(int b);
     72 
     73   /**
     74    * Play the beep sound ...
     75    */
     76   public void beep() { /* do nothing by default */
     77   }
     78 
     79   /**
     80    * Convenience function for putString(char[], int, int)
     81    */
     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    */
     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 
    143   protected void sendTelnetCommand(byte cmd) {
    144 
    145   }
    146 
    147   /**
    148    * Sent the changed window size from the terminal to all listeners.
    149    */
    150   protected void setWindowSize(int c, int r) {
    151     /* To be overridden by Terminal.java */
    152   }
    153 
    154   @Override
    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    */
    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 
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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 
    591   public void setAnswerBack(String ab) {
    592     answerBack = unEscape(ab);
    593   }
    594 
    595   /**
    596    * Get the terminal id used to identify this terminal.
    597    */
    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    */
    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 
    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 
    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    */
    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    */
    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    */
    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    */
   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 
   1271   private void handle_dcs(String dcs) {
   1272     debugStr.append("DCS: ").append(dcs);
   1273     debug(debugStr.toString());
   1274     debugStr.setLength(0);
   1275   }
   1276 
   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 (at) microsoft.com>
   1311     // # Lori Hoerth <lorih (at) 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 
   1580   public char map_cp850_unicode(char x) {
   1581     if (x >= 0x100) {
   1582       return x;
   1583     }
   1584     return unimap[x];
   1585   }
   1586 
   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 
   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 */
   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