diff app/src/main/java/de/mud/terminal/vt320.java @ 438:d29cce60f393

migrate from Eclipse to Android Studio
author Carl Byington <carl@five-ten-sg.com>
date Thu, 03 Dec 2015 11:23:55 -0800
parents src/de/mud/terminal/vt320.java@2a7199ad90be
children f698820bffdf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/src/main/java/de/mud/terminal/vt320.java	Thu Dec 03 11:23:55 2015 -0800
@@ -0,0 +1,3423 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+
+package de.mud.terminal;
+
+import android.text.AndroidCharacter;
+
+import java.util.Properties;
+
+/**
+ * Implementation of a VT terminal emulation plus ANSI compatible.
+ * <P>
+ * <B>Maintainer:</B> Marcus Meißner
+ *
+ * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
+ * @author  Matthias L. Jugel, Marcus Meißner
+ */
+public abstract class vt320 extends VDUBuffer implements VDUInput {
+
+    /** the debug level */
+    private final static int debug = 0;
+    private StringBuilder debugStr;
+    public abstract void debug(String notice);
+
+    /**
+     * Write an answer back to the remote host. This is needed to be able to
+     * send terminal answers requests like status and type information.
+     * @param b the array of bytes to be sent
+     */
+    public abstract void write(byte[] b);
+
+    /**
+     * Write an answer back to the remote host. This is needed to be able to
+     * send terminal answers requests like status and type information.
+     * @param b the byte to be sent
+     */
+    public abstract void write(int b);
+
+    /**
+     * No more bytes to read from the transport, hook here to test screen changes
+     */
+    public void testChanged() {
+        /* do nothing by default */
+    }
+
+    /**
+     * inject field contents as if typed
+     */
+    public void setField(int l, int c, char [] d) {
+        // ignore line and column, just send the bytes to the host.
+        int n = d.length;
+        byte [] b = new byte [n];
+
+        for (int i = 0; i < n; i++) b[i] = (byte)(d[i] & 0x00ff);
+
+        write(b);
+    }
+
+    public void monitorKey(boolean down) {
+        // do nothing
+    }
+
+    public void keyDepressed(int keyCode, char keyChar, int modifiers) {
+        keyPressed(keyCode, keyChar, modifiers);
+    }
+
+    /**
+     * Play the beep sound ...
+     */
+    public void beep() {
+        /* do nothing by default */
+    }
+
+    public void redrawPassthru() {
+        redraw();   // VDUBuffer.redraw is protected
+    }
+
+    /**
+     * Convenience function for putString(char[], int, int)
+     */
+    public void putString(String s) {
+        int len = s.length();
+        char[] tmp = new char[len];
+        s.getChars(0, len, tmp, 0);
+        putString(tmp, null, 0, len);
+    }
+
+    /**
+     * Put string at current cursor position. Moves cursor
+     * according to the String. Does NOT wrap.
+     * @param s character array
+     * @param start place to start in array
+     * @param len number of characters to process
+     */
+    public void putString(char[] s, byte[] fullwidths, int start, int len) {
+        if (len > 0) {
+            //markLine(R, 1);
+            int lastChar = -1;
+            char c;
+            boolean isWide = false;
+
+            for (int i = 0; i < len; i++) {
+                c = s[start + i];
+
+                // Shortcut for my favorite ASCII
+                if (c <= 0x7F) {
+                    if (lastChar != -1)
+                        putChar((char) lastChar, isWide, false);
+
+                    lastChar = c;
+                    isWide = false;
+                }
+                else if (!Character.isLowSurrogate(c) && !Character.isHighSurrogate(c)) {
+                    if (Character.getType(c) == Character.NON_SPACING_MARK) {
+                        if (lastChar != -1) {
+                            char nc = Precomposer.precompose((char) lastChar, c);
+                            putChar(nc, isWide, false);
+                            lastChar = -1;
+                        }
+                    }
+                    else {
+                        if (lastChar != -1)
+                            putChar((char) lastChar, isWide, false);
+
+                        lastChar = c;
+
+                        if (fullwidths != null) {
+                            final byte width = fullwidths[i];
+                            isWide = (width == AndroidCharacter.EAST_ASIAN_WIDTH_WIDE)
+                                     || (width == AndroidCharacter.EAST_ASIAN_WIDTH_FULL_WIDTH);
+                        }
+                    }
+                }
+            }
+
+            if (lastChar != -1)
+                putChar((char) lastChar, isWide, false);
+
+            setCursorPosition(C, R);
+            redraw();
+        }
+    }
+
+    protected void sendTelnetCommand(byte cmd) {
+        /* do nothing by default */
+    }
+
+    /**
+     * Sent the changed window size from the terminal to all listeners.
+     */
+    protected void setWindowSize(int c, int r) {
+        /* To be overridden by Terminal.java */
+    }
+
+    @Override
+    public void setScreenSize(int c, int r, boolean broadcast) {
+        int oldrows = height;
+
+        if (debug > 2) {
+            if (debugStr == null)
+                debugStr = new StringBuilder();
+
+            debugStr.append("setscreensize (")
+            .append(c)
+            .append(',')
+            .append(r)
+            .append(',')
+            .append(broadcast)
+            .append(')');
+            debug(debugStr.toString());
+            debugStr.setLength(0);
+        }
+
+        super.setScreenSize(c, r, false);
+        boolean cursorChanged = false;
+
+        // Don't let the cursor go off the screen.
+        if (C >= c) {
+            C = c - 1;
+            cursorChanged = true;
+        }
+
+        if (R >= r) {
+            R = r - 1;
+            cursorChanged = true;
+        }
+
+        if (cursorChanged) {
+            setCursorPosition(C, R);
+            redraw();
+        }
+
+        if (broadcast) {
+            setWindowSize(c, r);  /* broadcast up */
+        }
+    }
+
+
+    /**
+     * Create a new vt320 terminal and intialize it with useful settings.
+     */
+    public vt320(int width, int height) {
+        super(width, height);
+        debugStr = new StringBuilder();
+        setVMS(false);
+        setIBMCharset(false);
+        setTerminalID("vt320");
+        setBufferSize(100);
+        //setBorder(2, false);
+        gx = new char[4];
+        reset();
+        /* top row of numpad */
+        PF1 = "\u001bOP";
+        PF2 = "\u001bOQ";
+        PF3 = "\u001bOR";
+        PF4 = "\u001bOS";
+        /* the 3x2 keyblock on PC keyboards */
+        Insert = new String[4];
+        Remove = new String[4];
+        KeyHome = new String[4];
+        KeyEnd = new String[4];
+        NextScn = new String[4];
+        PrevScn = new String[4];
+        Escape = new String[4];
+        BackSpace = new String[4];
+        TabKey = new String[4];
+        Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
+        Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
+        PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
+        NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
+        KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
+        KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
+        Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b";
+
+        if (vms) {
+            BackSpace[1] = "" + (char) 10;    //  VMS shift deletes word back
+            BackSpace[2] = "\u0018";  //  VMS control deletes line back
+            BackSpace[0] = BackSpace[3] = "\u007f";   //  VMS other is delete
+        }
+        else {
+            //BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b";
+            // ConnectBot modifications.
+            BackSpace[0] = "\b";
+            BackSpace[1] = "\u007f";
+            BackSpace[2] = "\u001b[3~";
+            BackSpace[3] = "\u001b[2~";
+        }
+
+        /* some more VT100 keys */
+        Find = "\u001b[1~";
+        Select = "\u001b[4~";
+        Help = "\u001b[28~";
+        Do = "\u001b[29~";
+        FunctionKey = new String[21];
+        FunctionKey[0] = "";
+        FunctionKey[1] = PF1;
+        FunctionKey[2] = PF2;
+        FunctionKey[3] = PF3;
+        FunctionKey[4] = PF4;
+        /* following are defined differently for vt220 / vt132 ... */
+        FunctionKey[5] = "\u001b[15~";
+        FunctionKey[6] = "\u001b[17~";
+        FunctionKey[7] = "\u001b[18~";
+        FunctionKey[8] = "\u001b[19~";
+        FunctionKey[9] = "\u001b[20~";
+        FunctionKey[10] = "\u001b[21~";
+        FunctionKey[11] = "\u001b[23~";
+        FunctionKey[12] = "\u001b[24~";
+        FunctionKey[13] = "\u001b[25~";
+        FunctionKey[14] = "\u001b[26~";
+        FunctionKey[15] = Help;
+        FunctionKey[16] = Do;
+        FunctionKey[17] = "\u001b[31~";
+        FunctionKey[18] = "\u001b[32~";
+        FunctionKey[19] = "\u001b[33~";
+        FunctionKey[20] = "\u001b[34~";
+        FunctionKeyShift = new String[21];
+        FunctionKeyAlt = new String[21];
+        FunctionKeyCtrl = new String[21];
+
+        for (int i = 0; i < 20; i++) {
+            FunctionKeyShift[i] = "";
+            FunctionKeyAlt[i] = "";
+            FunctionKeyCtrl[i] = "";
+        }
+
+        FunctionKeyShift[15] = Find;
+        FunctionKeyShift[16] = Select;
+        TabKey[0] = "\u0009";
+        TabKey[1] = "\u001bOP\u0009";
+        TabKey[2] = TabKey[3] = "";
+        KeyUp = new String[4];
+        KeyUp[0] = "\u001b[A";
+        KeyDown = new String[4];
+        KeyDown[0] = "\u001b[B";
+        KeyRight = new String[4];
+        KeyRight[0] = "\u001b[C";
+        KeyLeft = new String[4];
+        KeyLeft[0] = "\u001b[D";
+        Numpad = new String[10];
+        Numpad[0] = "\u001bOp";
+        Numpad[1] = "\u001bOq";
+        Numpad[2] = "\u001bOr";
+        Numpad[3] = "\u001bOs";
+        Numpad[4] = "\u001bOt";
+        Numpad[5] = "\u001bOu";
+        Numpad[6] = "\u001bOv";
+        Numpad[7] = "\u001bOw";
+        Numpad[8] = "\u001bOx";
+        Numpad[9] = "\u001bOy";
+        KPMinus = PF4;
+        KPComma = "\u001bOl";
+        KPPeriod = "\u001bOn";
+        KPEnter = "\u001bOM";
+        NUMPlus = new String[4];
+        NUMPlus[0] = "+";
+        NUMDot = new String[4];
+        NUMDot[0] = ".";
+    }
+
+    public void setBackspace(int type) {
+        switch (type) {
+            case DELETE_IS_DEL:
+                BackSpace[0] = "\u007f";
+                BackSpace[1] = "\b";
+                break;
+
+            case DELETE_IS_BACKSPACE:
+                BackSpace[0] = "\b";
+                BackSpace[1] = "\u007f";
+                break;
+        }
+    }
+
+    /**
+     * Create a default vt320 terminal with 80 columns and 24 lines.
+     */
+    public vt320() {
+        this(80, 24);
+    }
+
+    /**
+     * Terminal is mouse-aware and requires (x,y) coordinates of
+     * on the terminal (character coordinates) and the button clicked.
+     * @param x
+     * @param y
+     * @param modifiers
+     */
+    public void mousePressed(int x, int y, int modifiers) {
+        if (mouserpt == 0)
+            return;
+
+        int mods = modifiers;
+        mousebut = 3;
+
+        if ((mods & 16) == 16) mousebut = 0;
+
+        if ((mods & 8) == 8) mousebut = 1;
+
+        if ((mods & 4) == 4) mousebut = 2;
+
+        int mousecode;
+
+        if (mouserpt == 9)  /* X10 Mouse */
+            mousecode = 0x20 | mousebut;
+        else            /* normal xterm mouse reporting */
+            mousecode = mousebut | 0x20 | ((mods & 7) << 2);
+
+        byte b[] = new byte[6];
+        b[0] = 27;
+        b[1] = (byte) '[';
+        b[2] = (byte) 'M';
+        b[3] = (byte) mousecode;
+        b[4] = (byte)(0x20 + x + 1);
+        b[5] = (byte)(0x20 + y + 1);
+        write(b);  // FIXME: writeSpecial here
+    }
+
+    /**
+     * Terminal is mouse-aware and requires the coordinates and button
+     * of the release.
+     * @param x
+     * @param y
+     * @param modifiers
+     */
+    public void mouseReleased(int x, int y, int modifiers) {
+        if (mouserpt == 0)
+            return;
+
+        /* problem is tht modifiers still have the released button set in them.
+        int mods = modifiers;
+        mousebut = 3;
+        if ((mods & 16)==16) mousebut=0;
+        if ((mods &  8)==8 ) mousebut=1;
+        if ((mods &  4)==4 ) mousebut=2;
+        */
+        int mousecode;
+
+        if (mouserpt == 9)
+            mousecode = 0x20 + mousebut;  /* same as press? appears so. */
+        else
+            mousecode = '#';
+
+        byte b[] = new byte[6];
+        b[0] = 27;
+        b[1] = (byte) '[';
+        b[2] = (byte) 'M';
+        b[3] = (byte) mousecode;
+        b[4] = (byte)(0x20 + x + 1);
+        b[5] = (byte)(0x20 + y + 1);
+        write(b);  // FIXME: writeSpecial here
+        mousebut = 0;
+    }
+
+
+    /** we should do localecho (passed from other modules). false is default */
+    private boolean localecho = false;
+
+    /**
+     * Enable or disable the local echo property of the terminal.
+     * @param echo true if the terminal should echo locally
+     */
+    public void setLocalEcho(boolean echo) {
+        localecho = echo;
+    }
+
+    /**
+     * Enable the VMS mode of the terminal to handle some things differently
+     * for VMS hosts.
+     * @param vms true for vms mode, false for normal mode
+     */
+    public void setVMS(boolean vms) {
+        this.vms = vms;
+    }
+
+    /**
+     * Enable the usage of the IBM character set used by some BBS's. Special
+     * graphical character are available in this mode.
+     * @param ibm true to use the ibm character set
+     */
+    public void setIBMCharset(boolean ibm) {
+        useibmcharset = ibm;
+    }
+
+    /**
+     * Override the standard key codes used by the terminal emulation.
+     * @param codes a properties object containing key code definitions
+     */
+    public void setKeyCodes(Properties codes) {
+        String res, prefixes[] = {"", "S", "C", "A"};
+        int i;
+
+        for (i = 0; i < 10; i++) {
+            res = codes.getProperty("NUMPAD" + i);
+
+            if (res != null) Numpad[i] = unEscape(res);
+        }
+
+        for (i = 1; i < 20; i++) {
+            res = codes.getProperty("F" + i);
+
+            if (res != null) FunctionKey[i] = unEscape(res);
+
+            res = codes.getProperty("SF" + i);
+
+            if (res != null) FunctionKeyShift[i] = unEscape(res);
+
+            res = codes.getProperty("CF" + i);
+
+            if (res != null) FunctionKeyCtrl[i] = unEscape(res);
+
+            res = codes.getProperty("AF" + i);
+
+            if (res != null) FunctionKeyAlt[i] = unEscape(res);
+        }
+
+        for (i = 0; i < 4; i++) {
+            res = codes.getProperty(prefixes[i] + "PGUP");
+
+            if (res != null) PrevScn[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "PGDOWN");
+
+            if (res != null) NextScn[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "END");
+
+            if (res != null) KeyEnd[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "HOME");
+
+            if (res != null) KeyHome[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "INSERT");
+
+            if (res != null) Insert[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "REMOVE");
+
+            if (res != null) Remove[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "UP");
+
+            if (res != null) KeyUp[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "DOWN");
+
+            if (res != null) KeyDown[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "LEFT");
+
+            if (res != null) KeyLeft[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "RIGHT");
+
+            if (res != null) KeyRight[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "ESCAPE");
+
+            if (res != null) Escape[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "BACKSPACE");
+
+            if (res != null) BackSpace[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "TAB");
+
+            if (res != null) TabKey[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "NUMPLUS");
+
+            if (res != null) NUMPlus[i] = unEscape(res);
+
+            res = codes.getProperty(prefixes[i] + "NUMDECIMAL");
+
+            if (res != null) NUMDot[i] = unEscape(res);
+        }
+    }
+
+    /**
+     * Set the terminal id used to identify this terminal.
+     * @param terminalID the id string
+     */
+    public void setTerminalID(String terminalID) {
+        this.terminalID = terminalID;
+
+        if (terminalID.equals("scoansi")) {
+            FunctionKey[1] = "\u001b[M";  FunctionKey[2] = "\u001b[N";
+            FunctionKey[3] = "\u001b[O";  FunctionKey[4] = "\u001b[P";
+            FunctionKey[5] = "\u001b[Q";  FunctionKey[6] = "\u001b[R";
+            FunctionKey[7] = "\u001b[S";  FunctionKey[8] = "\u001b[T";
+            FunctionKey[9] = "\u001b[U";  FunctionKey[10] = "\u001b[V";
+            FunctionKey[11] = "\u001b[W"; FunctionKey[12] = "\u001b[X";
+            FunctionKey[13] = "\u001b[Y"; FunctionKey[14] = "?";
+            FunctionKey[15] = "\u001b[a"; FunctionKey[16] = "\u001b[b";
+            FunctionKey[17] = "\u001b[c"; FunctionKey[18] = "\u001b[d";
+            FunctionKey[19] = "\u001b[e"; FunctionKey[20] = "\u001b[f";
+            PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I";
+            NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G";
+            // more theoretically.
+        }
+    }
+
+    public void setAnswerBack(String ab) {
+        this.answerBack = unEscape(ab);
+    }
+
+    /**
+     * Get the terminal id used to identify this terminal.
+     */
+    public String getTerminalID() {
+        return terminalID;
+    }
+
+    /**
+     * A small conveniance method thar converts the string to a byte array
+     * for sending.
+     * @param s the string to be sent
+     */
+    private boolean write(String s, boolean doecho) {
+        if (debug > 2) {
+            debugStr.append("write(|")
+            .append(s)
+            .append("|,")
+            .append(doecho);
+            debug(debugStr.toString());
+            debugStr.setLength(0);
+        }
+
+        if (s == null) // aka the empty string.
+            return true;
+
+        /* NOTE: getBytes() honours some locale, it *CONVERTS* the string.
+         * However, we output only 7bit stuff towards the target, and *some*
+         * 8 bit control codes. We must not mess up the latter, so we do hand
+         * by hand copy.
+         */
+        byte arr[] = new byte[s.length()];
+
+        for (int i = 0; i < s.length(); i++) {
+            arr[i] = (byte) s.charAt(i);
+        }
+
+        write(arr);
+
+        if (doecho)
+            putString(s);
+
+        return true;
+    }
+
+    private boolean write(int s, boolean doecho) {
+        if (debug > 2) {
+            debugStr.append("write(|")
+            .append(s)
+            .append("|,")
+            .append(doecho);
+            debug(debugStr.toString());
+            debugStr.setLength(0);
+        }
+
+        write(s);
+
+        // TODO check if character is wide
+        if (doecho)
+            putChar((char)s, false, false);
+
+        return true;
+    }
+
+    private boolean write(String s) {
+        return write(s, localecho);
+    }
+
+    // ===================================================================
+    // the actual terminal emulation code comes here:
+    // ===================================================================
+
+    private String terminalID = "vt320";
+    private String answerBack = "Use Terminal.answerback to set ...\n";
+
+    // X - COLUMNS, Y - ROWS
+    int R, C;
+    int attributes = 0;
+
+    int Sc, Sr, Sa, Stm, Sbm;
+    char Sgr, Sgl;
+    char Sgx[];
+
+    int insertmode = 0;
+    int statusmode = 0;
+    boolean vt52mode = false;
+    boolean keypadmode = false; /* false - numeric, true - application */
+    boolean output8bit = false;
+    int normalcursor = 0;
+    boolean moveoutsidemargins = true;
+    boolean wraparound = true;
+    boolean sendcrlf = true;
+    boolean capslock = false;
+    boolean numlock = false;
+    int mouserpt = 0;
+    byte mousebut = 0;
+
+    boolean useibmcharset = false;
+
+    int lastwaslf = 0;
+    boolean usedcharsets = false;
+
+    private final static char ESC = 27;
+    private final static char IND = 132;
+    private final static char NEL = 133;
+    private final static char RI = 141;
+    private final static char SS2 = 142;
+    private final static char SS3 = 143;
+    private final static char DCS = 144;
+    private final static char HTS = 136;
+    private final static char CSI = 155;
+    private final static char OSC = 157;
+    private final static int TSTATE_DATA = 0;
+    private final static int TSTATE_ESC = 1; /* ESC */
+    private final static int TSTATE_CSI = 2; /* ESC [ */
+    private final static int TSTATE_DCS = 3; /* ESC P */
+    private final static int TSTATE_DCEQ = 4; /* ESC [? */
+    private final static int TSTATE_ESCSQUARE = 5; /* ESC # */
+    private final static int TSTATE_OSC = 6;       /* ESC ] */
+    private final static int TSTATE_SETG0 = 7;     /* ESC (? */
+    private final static int TSTATE_SETG1 = 8;     /* ESC )? */
+    private final static int TSTATE_SETG2 = 9;     /* ESC *? */
+    private final static int TSTATE_SETG3 = 10;    /* ESC +? */
+    private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */
+    private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */
+    private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */
+    private final static int TSTATE_VT52X = 14;
+    private final static int TSTATE_VT52Y = 15;
+    private final static int TSTATE_CSI_TICKS = 16;
+    private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */
+    private final static int TSTATE_TITLE = 18; /* xterm title */
+
+    /* Keys we support */
+    public final static int KEY_PAUSE      = 1;
+    public final static int KEY_F1         = 2;
+    public final static int KEY_F2         = 3;
+    public final static int KEY_F3         = 4;
+    public final static int KEY_F4         = 5;
+    public final static int KEY_F5         = 6;
+    public final static int KEY_F6         = 7;
+    public final static int KEY_F7         = 8;
+    public final static int KEY_F8         = 9;
+    public final static int KEY_F9         = 10;
+    public final static int KEY_F10        = 11;
+    public final static int KEY_F11        = 12;
+    public final static int KEY_F12        = 13;
+    public final static int KEY_F13        = 14;    // only used by tn5250
+    public final static int KEY_F14        = 15;    // only used by tn5250
+    public final static int KEY_F15        = 16;    // only used by tn5250
+    public final static int KEY_F16        = 17;    // only used by tn5250
+    public final static int KEY_F17        = 18;    // only used by tn5250
+    public final static int KEY_F18        = 19;    // only used by tn5250
+    public final static int KEY_F19        = 20;    // only used by tn5250
+    public final static int KEY_F20        = 21;    // only used by tn5250
+    public final static int KEY_F21        = 22;    // only used by tn5250
+    public final static int KEY_F22        = 23;    // only used by tn5250
+    public final static int KEY_F23        = 24;    // only used by tn5250
+    public final static int KEY_F24        = 25;    // only used by tn5250
+    public final static int KEY_UP         = 26;
+    public final static int KEY_DOWN       = 27;
+    public final static int KEY_LEFT       = 28;
+    public final static int KEY_RIGHT      = 29;
+    public final static int KEY_PAGE_DOWN  = 30;
+    public final static int KEY_PAGE_UP    = 31;
+    public final static int KEY_INSERT     = 32;
+    public final static int KEY_DELETE     = 33;
+    public final static int KEY_BACK_SPACE = 34;
+    public final static int KEY_HOME       = 35;
+    public final static int KEY_END        = 36;
+    public final static int KEY_NUM_LOCK   = 37;
+    public final static int KEY_CAPS_LOCK  = 38;
+    public final static int KEY_SHIFT      = 39;
+    public final static int KEY_CONTROL    = 40;
+    public final static int KEY_ALT        = 41;
+    public final static int KEY_ENTER      = 42;
+    public final static int KEY_NUMPAD0    = 43;
+    public final static int KEY_NUMPAD1    = 44;
+    public final static int KEY_NUMPAD2    = 45;
+    public final static int KEY_NUMPAD3    = 46;
+    public final static int KEY_NUMPAD4    = 47;
+    public final static int KEY_NUMPAD5    = 48;
+    public final static int KEY_NUMPAD6    = 49;
+    public final static int KEY_NUMPAD7    = 50;
+    public final static int KEY_NUMPAD8    = 51;
+    public final static int KEY_NUMPAD9    = 52;
+    public final static int KEY_DECIMAL    = 53;
+    public final static int KEY_ADD        = 54;
+    public final static int KEY_ESCAPE     = 55;
+    public final static int KEY_TAB        = 56;
+    public final static int KEY_SYSREQ     = 57;    // only used by tn5250
+
+    public final static int DELETE_IS_DEL = 0;
+    public final static int DELETE_IS_BACKSPACE = 1;
+
+    /* The graphics charsets
+     * B - default ASCII
+     * A - ISO Latin 1
+     * 0 - DEC SPECIAL
+     * < - User defined
+     * ....
+     */
+    char gx[];
+    char gl;      // GL (left charset)
+    char gr;      // GR (right charset)
+    int onegl;    // single shift override for GL.
+
+    // Map from scoansi linedrawing to DEC _and_ unicode (for the stuff which
+    // is not in linedrawing). Got from experimenting with scoadmin.
+    private final static String scoansi_acs = "Tm7k3x4u?kZl@mYjEnB\u2566DqCtAvM\u2550:\u2551N\u2557I\u2554;\u2557H\u255a0a<\u255d";
+    // array to store DEC Special -> Unicode mapping
+    //  Unicode   DEC  Unicode name    (DEC name)
+    private static char DECSPECIAL[] = {
+        '\u0040', //5f blank
+        '\u2666', //60 black diamond
+        '\u2592', //61 grey square
+        '\u2409', //62 Horizontal tab  (ht) pict. for control
+        '\u240c', //63 Form Feed       (ff) pict. for control
+        '\u240d', //64 Carriage Return (cr) pict. for control
+        '\u240a', //65 Line Feed       (lf) pict. for control
+        '\u00ba', //66 Masculine ordinal indicator
+        '\u00b1', //67 Plus or minus sign
+        '\u2424', //68 New Line        (nl) pict. for control
+        '\u240b', //69 Vertical Tab    (vt) pict. for control
+        '\u2518', //6a Forms light up   and left
+        '\u2510', //6b Forms light down and left
+        '\u250c', //6c Forms light down and right
+        '\u2514', //6d Forms light up   and right
+        '\u253c', //6e Forms light vertical and horizontal
+        '\u2594', //6f Upper 1/8 block                        (Scan 1)
+        '\u2580', //70 Upper 1/2 block                        (Scan 3)
+        '\u2500', //71 Forms light horizontal or ?em dash?    (Scan 5)
+        '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7)
+        '\u005f', //73 \u005f underscore  or \u2581 lower 1/8 (Scan 9)
+        '\u251c', //74 Forms light vertical and right
+        '\u2524', //75 Forms light vertical and left
+        '\u2534', //76 Forms light up   and horizontal
+        '\u252c', //77 Forms light down and horizontal
+        '\u2502', //78 vertical bar
+        '\u2264', //79 less than or equal
+        '\u2265', //7a greater than or equal
+        '\u00b6', //7b paragraph
+        '\u2260', //7c not equal
+        '\u00a3', //7d Pound Sign (british)
+        '\u00b7'  //7e Middle Dot
+    };
+
+    /** Strings to send on function key pressing */
+    private String Numpad[];
+    private String FunctionKey[];
+    private String FunctionKeyShift[];
+    private String FunctionKeyCtrl[];
+    private String FunctionKeyAlt[];
+    private String TabKey[];
+    private String KeyUp[], KeyDown[], KeyLeft[], KeyRight[];
+    private String KPMinus, KPComma, KPPeriod, KPEnter;
+    private String PF1, PF2, PF3, PF4;
+    private String Help, Do, Find, Select;
+
+    private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[];
+    private String Escape[], BackSpace[], NUMDot[], NUMPlus[];
+
+    private String osc, dcs; /* to memorize OSC & DCS control sequence */
+
+    /** vt320 state variable (internal) */
+    private int term_state = TSTATE_DATA;
+    /** in vms mode, set by Terminal.VMS property */
+    private boolean vms = false;
+    /** Tabulators */
+    private byte[] Tabs;
+    /** The list of integers as used by CSI */
+    private int[] DCEvars = new int[30];
+    private int DCEvar;
+
+    /**
+     * Replace escape code characters (backslash + identifier) with their
+     * respective codes.
+     * @param tmp the string to be parsed
+     * @return a unescaped string
+     */
+    static String unEscape(String tmp) {
+        int idx = 0, oldidx = 0;
+        String cmd;
+        // f.println("unescape("+tmp+")");
+        cmd = "";
+
+        while ((idx = tmp.indexOf('\\', oldidx)) >= 0 &&
+                ++idx <= tmp.length()) {
+            cmd += tmp.substring(oldidx, idx - 1);
+
+            if (idx == tmp.length()) return cmd;
+
+            switch (tmp.charAt(idx)) {
+                case 'b':
+                    cmd += "\b";
+                    break;
+
+                case 'e':
+                    cmd += "\u001b";
+                    break;
+
+                case 'n':
+                    cmd += "\n";
+                    break;
+
+                case 'r':
+                    cmd += "\r";
+                    break;
+
+                case 't':
+                    cmd += "\t";
+                    break;
+
+                case 'v':
+                    cmd += "\u000b";
+                    break;
+
+                case 'a':
+                    cmd += "\u0012";
+                    break;
+
+                default :
+                    if ((tmp.charAt(idx) >= '0') && (tmp.charAt(idx) <= '9')) {
+                        int i;
+
+                        for (i = idx; i < tmp.length(); i++)
+                            if ((tmp.charAt(i) < '0') || (tmp.charAt(i) > '9'))
+                                break;
+
+                        cmd += (char) Integer.parseInt(tmp.substring(idx, i));
+                        idx = i - 1;
+                    }
+                    else
+                        cmd += tmp.substring(idx, ++idx);
+
+                    break;
+            }
+
+            oldidx = ++idx;
+        }
+
+        if (oldidx <= tmp.length()) cmd += tmp.substring(oldidx);
+
+        return cmd;
+    }
+
+    /**
+     * A small conveniance method thar converts a 7bit string to the 8bit
+     * version depending on VT52/Output8Bit mode.
+     *
+     * @param s the string to be sent
+     */
+    private boolean writeSpecial(String s) {
+        if (s == null)
+            return true;
+
+        if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == 'O'))) {
+            if (vt52mode) {
+                if ((s.charAt(2) >= 'P') && (s.charAt(2) <= 'S')) {
+                    s = "\u001b" + s.substring(2);  /* ESC x */
+                }
+                else {
+                    s = "\u001b?" + s.substring(2);  /* ESC ? x */
+                }
+            }
+            else {
+                if (output8bit) {
+                    s = "\u008f" + s.substring(2);  /* SS3 x */
+                } /* else keep string as it is */
+            }
+        }
+
+        if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == '['))) {
+            if (output8bit) {
+                s = "\u009b" + s.substring(2);  /* CSI ... */
+            } /* else keep */
+        }
+
+        return write(s, false);
+    }
+
+    /**
+     * main keytyping event handler for all the special function and modifier keys
+     * the normal keys are processed by write(byte b);
+     */
+    public void keyPressed(int keyCode, char keyChar, int modifiers) {
+        boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0;
+        boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0;
+        boolean alt = (modifiers & VDUInput.KEY_ALT) != 0;
+
+        if (debug > 1) {
+            debugStr.append("keyPressed(")
+            .append(keyCode)
+            .append(", ")
+            .append((int)keyChar)
+            .append(", ")
+            .append(modifiers)
+            .append(')');
+            debug(debugStr.toString());
+            debugStr.setLength(0);
+        }
+
+        int xind;
+        String fmap[];
+        xind = 0;
+        fmap = FunctionKey;
+
+        if (shift) {
+            fmap = FunctionKeyShift;
+            xind = 1;
+        }
+
+        if (control) {
+            fmap = FunctionKeyCtrl;
+            xind = 2;
+        }
+
+        if (alt) {
+            fmap = FunctionKeyAlt;
+            xind = 3;
+        }
+
+        switch (keyCode) {
+            case KEY_PAUSE:
+                if (shift || control)
+                    sendTelnetCommand((byte) 243);  // BREAK
+
+                break;
+
+            case KEY_F1:
+                writeSpecial(fmap[1]);
+                break;
+
+            case KEY_F2:
+                writeSpecial(fmap[2]);
+                break;
+
+            case KEY_F3:
+                writeSpecial(fmap[3]);
+                break;
+
+            case KEY_F4:
+                writeSpecial(fmap[4]);
+                break;
+
+            case KEY_F5:
+                writeSpecial(fmap[5]);
+                break;
+
+            case KEY_F6:
+                writeSpecial(fmap[6]);
+                break;
+
+            case KEY_F7:
+                writeSpecial(fmap[7]);
+                break;
+
+            case KEY_F8:
+                writeSpecial(fmap[8]);
+                break;
+
+            case KEY_F9:
+                writeSpecial(fmap[9]);
+                break;
+
+            case KEY_F10:
+                writeSpecial(fmap[10]);
+                break;
+
+            case KEY_F11:
+                writeSpecial(fmap[11]);
+                break;
+
+            case KEY_F12:
+                writeSpecial(fmap[12]);
+                break;
+
+            case KEY_F13:
+            case KEY_F14:
+            case KEY_F15:
+            case KEY_F16:
+            case KEY_F17:
+            case KEY_F18:
+            case KEY_F19:
+            case KEY_F20:
+            case KEY_F21:
+            case KEY_F22:
+            case KEY_F23:
+            case KEY_F24:
+                break;
+
+            case KEY_UP:
+                writeSpecial(KeyUp[xind]);
+                break;
+
+            case KEY_DOWN:
+                writeSpecial(KeyDown[xind]);
+                break;
+
+            case KEY_LEFT:
+                writeSpecial(KeyLeft[xind]);
+                break;
+
+            case KEY_RIGHT:
+                writeSpecial(KeyRight[xind]);
+                break;
+
+            case KEY_PAGE_DOWN:
+                writeSpecial(NextScn[xind]);
+                break;
+
+            case KEY_PAGE_UP:
+                writeSpecial(PrevScn[xind]);
+                break;
+
+            case KEY_INSERT:
+                writeSpecial(Insert[xind]);
+                break;
+
+            case KEY_DELETE:
+                writeSpecial(Remove[xind]);
+                break;
+
+            case KEY_BACK_SPACE:
+                writeSpecial(BackSpace[xind]);
+
+                if (localecho) {
+                    if (BackSpace[xind] == "\b") {
+                        putString("\b \b");  // make the last char 'deleted'
+                    }
+                    else {
+                        putString(BackSpace[xind]);  // echo it
+                    }
+                }
+
+                break;
+
+            case KEY_HOME:
+                writeSpecial(KeyHome[xind]);
+                break;
+
+            case KEY_END:
+                writeSpecial(KeyEnd[xind]);
+                break;
+
+            case KEY_NUM_LOCK:
+                if (vms && control) {
+                    writeSpecial(PF1);
+                }
+
+                if (!control)
+                    numlock = !numlock;
+
+                break;
+
+            case KEY_CAPS_LOCK:
+                capslock = !capslock;
+                break;
+
+            case KEY_SHIFT:
+            case KEY_CONTROL:
+            case KEY_ALT:
+                break;
+
+            case KEY_ESCAPE:
+                writeSpecial(Escape[xind]);
+                break;
+
+            case KEY_ENTER:
+                write(0x0d);
+                break;
+
+            case KEY_TAB:
+                writeSpecial(TabKey[xind]);
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    private void handle_dcs(String dcs) {
+        debugStr.append("DCS: ")
+        .append(dcs);
+        debug(debugStr.toString());
+        debugStr.setLength(0);
+    }
+
+    private void handle_osc(String osc) {
+        if (osc.length() > 2 && osc.substring(0, 2).equals("4;")) {
+            // Define color palette
+            String[] colorData = osc.split(";");
+
+            try {
+                int colorIndex = Integer.parseInt(colorData[1]);
+
+                if ("rgb:".equals(colorData[2].substring(0, 4))) {
+                    String[] rgb = colorData[2].substring(4).split("/");
+                    int red = Integer.parseInt(rgb[0].substring(0, 2), 16) & 0xFF;
+                    int green = Integer.parseInt(rgb[1].substring(0, 2), 16) & 0xFF;
+                    int blue = Integer.parseInt(rgb[2].substring(0, 2), 16) & 0xFF;
+                    display.setColor(colorIndex, red, green, blue);
+                }
+            }
+            catch (Exception e) {
+                debugStr.append("OSC: invalid color sequence encountered: ")
+                .append(osc);
+                debug(debugStr.toString());
+                debugStr.setLength(0);
+            }
+        }
+        else
+            debug("OSC: " + osc);
+    }
+
+    private final static char unimap[] = {
+        //#
+        //#    Name:     cp437_DOSLatinUS to Unicode table
+        //#    Unicode version: 1.1
+        //#    Table version: 1.1
+        //#    Table format:  Format A
+        //#    Date:          03/31/95
+        //#    Authors:       Michel Suignard <michelsu@microsoft.com>
+        //#                   Lori Hoerth <lorih@microsoft.com>
+        //#    General notes: none
+        //#
+        //#    Format: Three tab-separated columns
+        //#        Column #1 is the cp1255_WinHebrew code (in hex)
+        //#        Column #2 is the Unicode (in hex as 0xXXXX)
+        //#        Column #3 is the Unicode name (follows a comment sign, '#')
+        //#
+        //#    The entries are in cp437_DOSLatinUS order
+        //#
+
+        0x0000, // #NULL
+        0x0001, // #START OF HEADING
+        0x0002, // #START OF TEXT
+        0x0003, // #END OF TEXT
+        0x0004, // #END OF TRANSMISSION
+        0x0005, // #ENQUIRY
+        0x0006, // #ACKNOWLEDGE
+        0x0007, // #BELL
+        0x0008, // #BACKSPACE
+        0x0009, // #HORIZONTAL TABULATION
+        0x000a, // #LINE FEED
+        0x000b, // #VERTICAL TABULATION
+        0x000c, // #FORM FEED
+        0x000d, // #CARRIAGE RETURN
+        0x000e, // #SHIFT OUT
+        0x000f, // #SHIFT IN
+        0x0010, // #DATA LINK ESCAPE
+        0x0011, // #DEVICE CONTROL ONE
+        0x0012, // #DEVICE CONTROL TWO
+        0x0013, // #DEVICE CONTROL THREE
+        0x0014, // #DEVICE CONTROL FOUR
+        0x0015, // #NEGATIVE ACKNOWLEDGE
+        0x0016, // #SYNCHRONOUS IDLE
+        0x0017, // #END OF TRANSMISSION BLOCK
+        0x0018, // #CANCEL
+        0x0019, // #END OF MEDIUM
+        0x001a, // #SUBSTITUTE
+        0x001b, // #ESCAPE
+        0x001c, // #FILE SEPARATOR
+        0x001d, // #GROUP SEPARATOR
+        0x001e, // #RECORD SEPARATOR
+        0x001f, // #UNIT SEPARATOR
+        0x0020, // #SPACE
+        0x0021, // #EXCLAMATION MARK
+        0x0022, // #QUOTATION MARK
+        0x0023, // #NUMBER SIGN
+        0x0024, // #DOLLAR SIGN
+        0x0025, // #PERCENT SIGN
+        0x0026, // #AMPERSAND
+        0x0027, // #APOSTROPHE
+        0x0028, // #LEFT PARENTHESIS
+        0x0029, // #RIGHT PARENTHESIS
+        0x002a, // #ASTERISK
+        0x002b, // #PLUS SIGN
+        0x002c, // #COMMA
+        0x002d, // #HYPHEN-MINUS
+        0x002e, // #FULL STOP
+        0x002f, // #SOLIDUS
+        0x0030, // #DIGIT ZERO
+        0x0031, // #DIGIT ONE
+        0x0032, // #DIGIT TWO
+        0x0033, // #DIGIT THREE
+        0x0034, // #DIGIT FOUR
+        0x0035, // #DIGIT FIVE
+        0x0036, // #DIGIT SIX
+        0x0037, // #DIGIT SEVEN
+        0x0038, // #DIGIT EIGHT
+        0x0039, // #DIGIT NINE
+        0x003a, // #COLON
+        0x003b, // #SEMICOLON
+        0x003c, // #LESS-THAN SIGN
+        0x003d, // #EQUALS SIGN
+        0x003e, // #GREATER-THAN SIGN
+        0x003f, // #QUESTION MARK
+        0x0040, // #COMMERCIAL AT
+        0x0041, // #LATIN CAPITAL LETTER A
+        0x0042, // #LATIN CAPITAL LETTER B
+        0x0043, // #LATIN CAPITAL LETTER C
+        0x0044, // #LATIN CAPITAL LETTER D
+        0x0045, // #LATIN CAPITAL LETTER E
+        0x0046, // #LATIN CAPITAL LETTER F
+        0x0047, // #LATIN CAPITAL LETTER G
+        0x0048, // #LATIN CAPITAL LETTER H
+        0x0049, // #LATIN CAPITAL LETTER I
+        0x004a, // #LATIN CAPITAL LETTER J
+        0x004b, // #LATIN CAPITAL LETTER K
+        0x004c, // #LATIN CAPITAL LETTER L
+        0x004d, // #LATIN CAPITAL LETTER M
+        0x004e, // #LATIN CAPITAL LETTER N
+        0x004f, // #LATIN CAPITAL LETTER O
+        0x0050, // #LATIN CAPITAL LETTER P
+        0x0051, // #LATIN CAPITAL LETTER Q
+        0x0052, // #LATIN CAPITAL LETTER R
+        0x0053, // #LATIN CAPITAL LETTER S
+        0x0054, // #LATIN CAPITAL LETTER T
+        0x0055, // #LATIN CAPITAL LETTER U
+        0x0056, // #LATIN CAPITAL LETTER V
+        0x0057, // #LATIN CAPITAL LETTER W
+        0x0058, // #LATIN CAPITAL LETTER X
+        0x0059, // #LATIN CAPITAL LETTER Y
+        0x005a, // #LATIN CAPITAL LETTER Z
+        0x005b, // #LEFT SQUARE BRACKET
+        0x005c, // #REVERSE SOLIDUS
+        0x005d, // #RIGHT SQUARE BRACKET
+        0x005e, // #CIRCUMFLEX ACCENT
+        0x005f, // #LOW LINE
+        0x0060, // #GRAVE ACCENT
+        0x0061, // #LATIN SMALL LETTER A
+        0x0062, // #LATIN SMALL LETTER B
+        0x0063, // #LATIN SMALL LETTER C
+        0x0064, // #LATIN SMALL LETTER D
+        0x0065, // #LATIN SMALL LETTER E
+        0x0066, // #LATIN SMALL LETTER F
+        0x0067, // #LATIN SMALL LETTER G
+        0x0068, // #LATIN SMALL LETTER H
+        0x0069, // #LATIN SMALL LETTER I
+        0x006a, // #LATIN SMALL LETTER J
+        0x006b, // #LATIN SMALL LETTER K
+        0x006c, // #LATIN SMALL LETTER L
+        0x006d, // #LATIN SMALL LETTER M
+        0x006e, // #LATIN SMALL LETTER N
+        0x006f, // #LATIN SMALL LETTER O
+        0x0070, // #LATIN SMALL LETTER P
+        0x0071, // #LATIN SMALL LETTER Q
+        0x0072, // #LATIN SMALL LETTER R
+        0x0073, // #LATIN SMALL LETTER S
+        0x0074, // #LATIN SMALL LETTER T
+        0x0075, // #LATIN SMALL LETTER U
+        0x0076, // #LATIN SMALL LETTER V
+        0x0077, // #LATIN SMALL LETTER W
+        0x0078, // #LATIN SMALL LETTER X
+        0x0079, // #LATIN SMALL LETTER Y
+        0x007a, // #LATIN SMALL LETTER Z
+        0x007b, // #LEFT CURLY BRACKET
+        0x007c, // #VERTICAL LINE
+        0x007d, // #RIGHT CURLY BRACKET
+        0x007e, // #TILDE
+        0x007f, // #DELETE
+        0x00c7, // #LATIN CAPITAL LETTER C WITH CEDILLA
+        0x00fc, // #LATIN SMALL LETTER U WITH DIAERESIS
+        0x00e9, // #LATIN SMALL LETTER E WITH ACUTE
+        0x00e2, // #LATIN SMALL LETTER A WITH CIRCUMFLEX
+        0x00e4, // #LATIN SMALL LETTER A WITH DIAERESIS
+        0x00e0, // #LATIN SMALL LETTER A WITH GRAVE
+        0x00e5, // #LATIN SMALL LETTER A WITH RING ABOVE
+        0x00e7, // #LATIN SMALL LETTER C WITH CEDILLA
+        0x00ea, // #LATIN SMALL LETTER E WITH CIRCUMFLEX
+        0x00eb, // #LATIN SMALL LETTER E WITH DIAERESIS
+        0x00e8, // #LATIN SMALL LETTER E WITH GRAVE
+        0x00ef, // #LATIN SMALL LETTER I WITH DIAERESIS
+        0x00ee, // #LATIN SMALL LETTER I WITH CIRCUMFLEX
+        0x00ec, // #LATIN SMALL LETTER I WITH GRAVE
+        0x00c4, // #LATIN CAPITAL LETTER A WITH DIAERESIS
+        0x00c5, // #LATIN CAPITAL LETTER A WITH RING ABOVE
+        0x00c9, // #LATIN CAPITAL LETTER E WITH ACUTE
+        0x00e6, // #LATIN SMALL LIGATURE AE
+        0x00c6, // #LATIN CAPITAL LIGATURE AE
+        0x00f4, // #LATIN SMALL LETTER O WITH CIRCUMFLEX
+        0x00f6, // #LATIN SMALL LETTER O WITH DIAERESIS
+        0x00f2, // #LATIN SMALL LETTER O WITH GRAVE
+        0x00fb, // #LATIN SMALL LETTER U WITH CIRCUMFLEX
+        0x00f9, // #LATIN SMALL LETTER U WITH GRAVE
+        0x00ff, // #LATIN SMALL LETTER Y WITH DIAERESIS
+        0x00d6, // #LATIN CAPITAL LETTER O WITH DIAERESIS
+        0x00dc, // #LATIN CAPITAL LETTER U WITH DIAERESIS
+        0x00a2, // #CENT SIGN
+        0x00a3, // #POUND SIGN
+        0x00a5, // #YEN SIGN
+        0x20a7, // #PESETA SIGN
+        0x0192, // #LATIN SMALL LETTER F WITH HOOK
+        0x00e1, // #LATIN SMALL LETTER A WITH ACUTE
+        0x00ed, // #LATIN SMALL LETTER I WITH ACUTE
+        0x00f3, // #LATIN SMALL LETTER O WITH ACUTE
+        0x00fa, // #LATIN SMALL LETTER U WITH ACUTE
+        0x00f1, // #LATIN SMALL LETTER N WITH TILDE
+        0x00d1, // #LATIN CAPITAL LETTER N WITH TILDE
+        0x00aa, // #FEMININE ORDINAL INDICATOR
+        0x00ba, // #MASCULINE ORDINAL INDICATOR
+        0x00bf, // #INVERTED QUESTION MARK
+        0x2310, // #REVERSED NOT SIGN
+        0x00ac, // #NOT SIGN
+        0x00bd, // #VULGAR FRACTION ONE HALF
+        0x00bc, // #VULGAR FRACTION ONE QUARTER
+        0x00a1, // #INVERTED EXCLAMATION MARK
+        0x00ab, // #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+        0x00bb, // #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+        0x2591, // #LIGHT SHADE
+        0x2592, // #MEDIUM SHADE
+        0x2593, // #DARK SHADE
+        0x2502, // #BOX DRAWINGS LIGHT VERTICAL
+        0x2524, // #BOX DRAWINGS LIGHT VERTICAL AND LEFT
+        0x2561, // #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+        0x2562, // #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+        0x2556, // #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+        0x2555, // #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+        0x2563, // #BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+        0x2551, // #BOX DRAWINGS DOUBLE VERTICAL
+        0x2557, // #BOX DRAWINGS DOUBLE DOWN AND LEFT
+        0x255d, // #BOX DRAWINGS DOUBLE UP AND LEFT
+        0x255c, // #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+        0x255b, // #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+        0x2510, // #BOX DRAWINGS LIGHT DOWN AND LEFT
+        0x2514, // #BOX DRAWINGS LIGHT UP AND RIGHT
+        0x2534, // #BOX DRAWINGS LIGHT UP AND HORIZONTAL
+        0x252c, // #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+        0x251c, // #BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+        0x2500, // #BOX DRAWINGS LIGHT HORIZONTAL
+        0x253c, // #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+        0x255e, // #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+        0x255f, // #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+        0x255a, // #BOX DRAWINGS DOUBLE UP AND RIGHT
+        0x2554, // #BOX DRAWINGS DOUBLE DOWN AND RIGHT
+        0x2569, // #BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+        0x2566, // #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+        0x2560, // #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+        0x2550, // #BOX DRAWINGS DOUBLE HORIZONTAL
+        0x256c, // #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+        0x2567, // #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+        0x2568, // #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+        0x2564, // #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+        0x2565, // #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+        0x2559, // #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+        0x2558, // #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+        0x2552, // #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+        0x2553, // #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+        0x256b, // #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+        0x256a, // #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+        0x2518, // #BOX DRAWINGS LIGHT UP AND LEFT
+        0x250c, // #BOX DRAWINGS LIGHT DOWN AND RIGHT
+        0x2588, // #FULL BLOCK
+        0x2584, // #LOWER HALF BLOCK
+        0x258c, // #LEFT HALF BLOCK
+        0x2590, // #RIGHT HALF BLOCK
+        0x2580, // #UPPER HALF BLOCK
+        0x03b1, // #GREEK SMALL LETTER ALPHA
+        0x00df, // #LATIN SMALL LETTER SHARP S
+        0x0393, // #GREEK CAPITAL LETTER GAMMA
+        0x03c0, // #GREEK SMALL LETTER PI
+        0x03a3, // #GREEK CAPITAL LETTER SIGMA
+        0x03c3, // #GREEK SMALL LETTER SIGMA
+        0x00b5, // #MICRO SIGN
+        0x03c4, // #GREEK SMALL LETTER TAU
+        0x03a6, // #GREEK CAPITAL LETTER PHI
+        0x0398, // #GREEK CAPITAL LETTER THETA
+        0x03a9, // #GREEK CAPITAL LETTER OMEGA
+        0x03b4, // #GREEK SMALL LETTER DELTA
+        0x221e, // #INFINITY
+        0x03c6, // #GREEK SMALL LETTER PHI
+        0x03b5, // #GREEK SMALL LETTER EPSILON
+        0x2229, // #INTERSECTION
+        0x2261, // #IDENTICAL TO
+        0x00b1, // #PLUS-MINUS SIGN
+        0x2265, // #GREATER-THAN OR EQUAL TO
+        0x2264, // #LESS-THAN OR EQUAL TO
+        0x2320, // #TOP HALF INTEGRAL
+        0x2321, // #BOTTOM HALF INTEGRAL
+        0x00f7, // #DIVISION SIGN
+        0x2248, // #ALMOST EQUAL TO
+        0x00b0, // #DEGREE SIGN
+        0x2219, // #BULLET OPERATOR
+        0x00b7, // #MIDDLE DOT
+        0x221a, // #SQUARE ROOT
+        0x207f, // #SUPERSCRIPT LATIN SMALL LETTER N
+        0x00b2, // #SUPERSCRIPT TWO
+        0x25a0, // #BLACK SQUARE
+        0x00a0, // #NO-BREAK SPACE
+    };
+
+    public char map_cp850_unicode(char x) {
+        if (x >= 0x100)
+            return x;
+
+        return unimap[x];
+    }
+
+    private void _SetCursor(int row, int col) {
+        int maxr = height - 1;
+        int tm = getTopMargin();
+        R = (row < 0) ? 0 : row;
+        C = (col < 0) ? 0 : (col >= width) ? width - 1 : col;
+
+        if (!moveoutsidemargins) {
+            R += tm;
+            maxr = getBottomMargin();
+        }
+
+        if (R > maxr) R = maxr;
+    }
+
+    private void putChar(char c, boolean isWide, boolean doshowcursor) {
+        int rows = this.height; //statusline
+        int columns = this.width;
+
+        // byte msg[];
+//    if (debug > 4) {
+//      debugStr.append("putChar(")
+//        .append(c)
+//        .append(" [")
+//        .append((int) c)
+//        .append("]) at R=")
+//        .append(R)
+//        .append(" , C=")
+//        .append(C)
+//        .append(", columns=")
+//        .append(columns)
+//        .append(", rows=")
+//        .append(rows);
+//      debug(debugStr.toString());
+//      debugStr.setLength(0);
+//    }
+//    markLine(R, 1);
+//    if (c > 255) {
+//      if (debug > 0)
+//        debug("char > 255:" + (int) c);
+//      //return;
+//    }
+        switch (term_state) {
+            case TSTATE_DATA:
+
+                /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset.
+                 * probably... but some BBS do anyway...
+                 */
+                if (!useibmcharset) {
+                    boolean doneflag = true;
+
+                    switch (c) {
+                        case OSC:
+                            osc = "";
+                            term_state = TSTATE_OSC;
+                            break;
+
+                        case RI:
+                            if (R > getTopMargin())
+                                R--;
+                            else
+                                insertLine(R, 1, SCROLL_DOWN);
+
+                            if (debug > 1)
+                                debug("RI");
+
+                            break;
+
+                        case IND:
+                            if (debug > 2) {
+                                debugStr.append("IND at ")
+                                .append(R)
+                                .append(", tm is ")
+                                .append(getTopMargin())
+                                .append(", bm is ")
+                                .append(getBottomMargin());
+                                debug(debugStr.toString());
+                                debugStr.setLength(0);
+                            }
+
+                            if (R == getBottomMargin() || R == rows - 1)
+                                insertLine(R, 1, SCROLL_UP);
+                            else
+                                R++;
+
+                            if (debug > 1)
+                                debug("IND (at " + R + " )");
+
+                            break;
+
+                        case NEL:
+                            if (R == getBottomMargin() || R == rows - 1)
+                                insertLine(R, 1, SCROLL_UP);
+                            else
+                                R++;
+
+                            C = 0;
+
+                            if (debug > 1)
+                                debug("NEL (at " + R + " )");
+
+                            break;
+
+                        case HTS:
+                            Tabs[C] = 1;
+
+                            if (debug > 1)
+                                debug("HTS");
+
+                            break;
+
+                        case DCS:
+                            dcs = "";
+                            term_state = TSTATE_DCS;
+                            break;
+
+                        default:
+                            doneflag = false;
+                            break;
+                    }
+
+                    if (doneflag) break;
+                }
+
+                switch (c) {
+                    case SS3:
+                        onegl = 3;
+                        break;
+
+                    case SS2:
+                        onegl = 2;
+                        break;
+
+                    case CSI: // should be in the 8bit section, but some BBS use this
+                        DCEvar = 0;
+                        DCEvars[0] = 0;
+                        DCEvars[1] = 0;
+                        DCEvars[2] = 0;
+                        DCEvars[3] = 0;
+                        term_state = TSTATE_CSI;
+                        break;
+
+                    case ESC:
+                        term_state = TSTATE_ESC;
+                        lastwaslf = 0;
+                        break;
+
+                    case 5: /* ENQ */
+                        write(answerBack, false);
+                        break;
+
+                    case 12:
+                        /* FormFeed, Home for the BBS world */
+                        deleteArea(0, 0, columns, rows, attributes);
+                        C = R = 0;
+                        break;
+
+                    case '\b': /* 8 */
+                        C--;
+
+                        if (C < 0)
+                            C = 0;
+
+                        lastwaslf = 0;
+                        break;
+
+                    case '\t':
+                        do {
+                            // Don't overwrite or insert! TABS are not destructive, but movement!
+                            C++;
+                        }
+                        while (C < columns && (Tabs[C] == 0));
+
+                        lastwaslf = 0;
+                        break;
+
+                    case '\r': // 13 CR
+                        C = 0;
+                        break;
+
+                    case '\n': // 10 LF
+                        if (debug > 3)
+                            debug("R= " + R + ", bm " + getBottomMargin() + ", tm=" + getTopMargin() + ", rows=" + rows);
+
+                        if (!vms) {
+                            if (lastwaslf != 0 && lastwaslf != c)   //  Ray: I do not understand this logic.
+                                break;
+
+                            lastwaslf = c;
+                            /*C = 0;*/
+                        }
+
+                        if (R == getBottomMargin() || R >= rows - 1)
+                            insertLine(R, 1, SCROLL_UP);
+                        else
+                            R++;
+
+                        break;
+
+                    case 7:
+                        beep();
+                        break;
+
+                    case '\016': /* SMACS , as */
+                        /* ^N, Shift out - Put G1 into GL */
+                        gl = 1;
+                        usedcharsets = true;
+                        break;
+
+                    case '\017': /* RMACS , ae */
+                        /* ^O, Shift in - Put G0 into GL */
+                        gl = 0;
+                        usedcharsets = true;
+                        break;
+
+                    default: {
+                            int thisgl = gl;
+
+                            if (onegl >= 0) {
+                                thisgl = onegl;
+                                onegl = -1;
+                            }
+
+                            lastwaslf = 0;
+
+                            if (c < 32) {
+                                if (c != 0)
+                                    if (debug > 0)
+                                        debug("TSTATE_DATA char: " + ((int) c));
+
+                                /*break; some BBS really want those characters, like hearst etc. */
+                                if (c == 0) /* print 0 ... you bet */
+                                    break;
+                            }
+
+                            if (C >= columns) {
+                                if (wraparound) {
+                                    int bot = rows;
+
+                                    // If we're in the scroll region, check against the bottom margin
+                                    if (R <= getBottomMargin() && R >= getTopMargin())
+                                        bot = getBottomMargin() + 1;
+
+                                    if (R < bot - 1)
+                                        R++;
+                                    else {
+                                        if (debug > 3) debug("scrolling due to wrap at " + R);
+
+                                        insertLine(R, 1, SCROLL_UP);
+                                    }
+
+                                    C = 0;
+                                }
+                                else {
+                                    // cursor stays on last character.
+                                    C = columns - 1;
+                                }
+                            }
+
+                            boolean mapped = false;
+
+                            // Mapping if DEC Special is chosen charset
+                            if (usedcharsets) {
+                                if (c >= '\u0020' && c <= '\u007f') {
+                                    switch (gx[thisgl]) {
+                                        case '0':
+
+                                            // Remap SCOANSI line drawing to VT100 line drawing chars
+                                            // for our SCO using customers.
+                                            if (terminalID.equals("scoansi") || terminalID.equals("ansi")) {
+                                                for (int i = 0; i < scoansi_acs.length(); i += 2) {
+                                                    if (c == scoansi_acs.charAt(i)) {
+                                                        c = scoansi_acs.charAt(i + 1);
+                                                        break;
+                                                    }
+                                                }
+                                            }
+
+                                            if (c >= '\u005f' && c <= '\u007e') {
+                                                c = DECSPECIAL[(short) c - 0x5f];
+                                                mapped = true;
+                                            }
+
+                                            break;
+
+                                        case '<': // 'user preferred' is currently 'ISO Latin-1 suppl
+                                            c = (char)((c & 0x7f) | 0x80);
+                                            mapped = true;
+                                            break;
+
+                                        case 'A':
+                                        case 'B': // Latin-1 , ASCII -> fall through
+                                            mapped = true;
+                                            break;
+
+                                        default:
+                                            debug("Unsupported GL mapping: " + gx[thisgl]);
+                                            break;
+                                    }
+                                }
+
+                                if (!mapped && (c >= '\u0080' && c <= '\u00ff')) {
+                                    switch (gx[gr]) {
+                                        case '0':
+                                            if (c >= '\u00df' && c <= '\u00fe') {
+                                                c = DECSPECIAL[c - '\u00df'];
+                                                mapped = true;
+                                            }
+
+                                            break;
+
+                                        case '<':
+                                        case 'A':
+                                        case 'B':
+                                            mapped = true;
+                                            break;
+
+                                        default:
+                                            debug("Unsupported GR mapping: " + gx[gr]);
+                                            break;
+                                    }
+                                }
+                            }
+
+                            if (!mapped && useibmcharset)
+                                c = map_cp850_unicode(c);
+
+                            /*if(true || (statusmode == 0)) { */
+                            if (isWide) {
+                                if (C >= columns - 1) {
+                                    if (wraparound) {
+                                        int bot = rows;
+
+                                        // If we're in the scroll region, check against the bottom margin
+                                        if (R <= getBottomMargin() && R >= getTopMargin())
+                                            bot = getBottomMargin() + 1;
+
+                                        if (R < bot - 1)
+                                            R++;
+                                        else {
+                                            if (debug > 3) debug("scrolling due to wrap at " + R);
+
+                                            insertLine(R, 1, SCROLL_UP);
+                                        }
+
+                                        C = 0;
+                                    }
+                                    else {
+                                        // cursor stays on last wide character.
+                                        C = columns - 2;
+                                    }
+                                }
+                            }
+
+                            if (insertmode == 1) {
+                                if (isWide) {
+                                    insertChar(C++, R, c, attributes | FULLWIDTH);
+                                    insertChar(C, R, ' ', attributes | FULLWIDTH);
+                                }
+                                else
+                                    insertChar(C, R, c, attributes);
+                            }
+                            else {
+                                if (isWide) {
+                                    putChar(C++, R, c, attributes | FULLWIDTH);
+                                    putChar(C, R, ' ', attributes | FULLWIDTH);
+                                }
+                                else
+                                    putChar(C, R, c, attributes);
+                            }
+
+                            /*
+                              } else {
+                              if (insertmode==1) {
+                              insertChar(C, rows, c, attributes);
+                              } else {
+                              putChar(C, rows, c, attributes);
+                              }
+                              }
+                            */
+                            C++;
+                            break;
+                        }
+                } /* switch(c) */
+
+                break;
+
+            case TSTATE_OSC:
+                if ((c < 0x20) && (c != ESC)) {// NP - No printing character
+                    handle_osc(osc);
+                    term_state = TSTATE_DATA;
+                    break;
+                }
+
+                //but check for vt102 ESC \
+                if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) {
+                    handle_osc(osc);
+                    term_state = TSTATE_DATA;
+                    break;
+                }
+
+                osc = osc + c;
+                break;
+
+            case TSTATE_ESCSPACE:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */
+                        output8bit = false;
+                        break;
+
+                    case 'G': /* S8C1T, Enable output of 8-bit control codes*/
+                        output8bit = true;
+                        break;
+
+                    default:
+                        debug("ESC <space> " + c + " unhandled.");
+                }
+
+                break;
+
+            case TSTATE_ESC:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case ' ':
+                        term_state = TSTATE_ESCSPACE;
+                        break;
+
+                    case '#':
+                        term_state = TSTATE_ESCSQUARE;
+                        break;
+
+                    case 'c':
+                        /* Hard terminal reset */
+                        reset();
+                        break;
+
+                    case '[':
+                        DCEvar = 0;
+                        DCEvars[0] = 0;
+                        DCEvars[1] = 0;
+                        DCEvars[2] = 0;
+                        DCEvars[3] = 0;
+                        term_state = TSTATE_CSI;
+                        break;
+
+                    case ']':
+                        osc = "";
+                        term_state = TSTATE_OSC;
+                        break;
+
+                    case 'P':
+                        dcs = "";
+                        term_state = TSTATE_DCS;
+                        break;
+
+                    case 'A': /* CUU */
+                        R--;
+
+                        if (R < 0) R = 0;
+
+                        break;
+
+                    case 'B': /* CUD */
+                        R++;
+
+                        if (R >= rows) R = rows - 1;
+
+                        break;
+
+                    case 'C':
+                        C++;
+
+                        if (C >= columns) C = columns - 1;
+
+                        break;
+
+                    case 'I': // RI
+                        insertLine(R, 1, SCROLL_DOWN);
+                        break;
+
+                    case 'E': /* NEL */
+                        if (R == getBottomMargin() || R == rows - 1)
+                            insertLine(R, 1, SCROLL_UP);
+                        else
+                            R++;
+
+                        C = 0;
+
+                        if (debug > 1)
+                            debug("ESC E (at " + R + ")");
+
+                        break;
+
+                    case 'D': /* IND */
+                        if (R == getBottomMargin() || R == rows - 1)
+                            insertLine(R, 1, SCROLL_UP);
+                        else
+                            R++;
+
+                        if (debug > 1)
+                            debug("ESC D (at " + R + " )");
+
+                        break;
+
+                    case 'J': /* erase to end of screen */
+                        if (R < rows - 1)
+                            deleteArea(0, R + 1, columns, rows - R - 1, attributes);
+
+                        if (C < columns - 1)
+                            deleteArea(C, R, columns - C, 1, attributes);
+
+                        break;
+
+                    case 'K':
+                        if (C < columns - 1)
+                            deleteArea(C, R, columns - C, 1, attributes);
+
+                        break;
+
+                    case 'M': // RI
+                        debug("ESC M : R is " + R + ", tm is " + getTopMargin() + ", bm is " + getBottomMargin());
+
+                        if (R > getTopMargin()) { // just go up 1 line.
+                            R--;
+                        }
+                        else {   // scroll down
+                            insertLine(R, 1, SCROLL_DOWN);
+                        }
+
+                        /* else do nothing ; */
+                        if (debug > 2)
+                            debug("ESC M ");
+
+                        break;
+
+                    case 'H':
+                        if (debug > 1)
+                            debug("ESC H at " + C);
+
+                        /* right border probably ...*/
+                        if (C >= columns)
+                            C = columns - 1;
+
+                        Tabs[C] = 1;
+                        break;
+
+                    case 'N': // SS2
+                        onegl = 2;
+                        break;
+
+                    case 'O': // SS3
+                        onegl = 3;
+                        break;
+
+                    case '=':
+
+                        /*application keypad*/
+                        if (debug > 0)
+                            debug("ESC =");
+
+                        keypadmode = true;
+                        break;
+
+                    case '<': /* vt52 mode off */
+                        vt52mode = false;
+                        break;
+
+                    case '>': /*normal keypad*/
+                        if (debug > 0)
+                            debug("ESC >");
+
+                        keypadmode = false;
+                        break;
+
+                    case '7': /* DECSC: save cursor, attributes */
+                        Sc = C;
+                        Sr = R;
+                        Sgl = gl;
+                        Sgr = gr;
+                        Sa = attributes;
+                        Sgx = new char[4];
+
+                        for (int i = 0; i < 4; i++) Sgx[i] = gx[i];
+
+                        if (debug > 1)
+                            debug("ESC 7");
+
+                        break;
+
+                    case '8': /* DECRC: restore cursor, attributes */
+                        C = Sc;
+                        R = Sr;
+                        gl = Sgl;
+                        gr = Sgr;
+
+                        if (Sgx != null)
+                            for (int i = 0; i < 4; i++) gx[i] = Sgx[i];
+
+                        attributes = Sa;
+
+                        if (debug > 1)
+                            debug("ESC 8");
+
+                        break;
+
+                    case '(': /* Designate G0 Character set (ISO 2022) */
+                        term_state = TSTATE_SETG0;
+                        usedcharsets = true;
+                        break;
+
+                    case ')': /* Designate G1 character set (ISO 2022) */
+                        term_state = TSTATE_SETG1;
+                        usedcharsets = true;
+                        break;
+
+                    case '*': /* Designate G2 Character set (ISO 2022) */
+                        term_state = TSTATE_SETG2;
+                        usedcharsets = true;
+                        break;
+
+                    case '+': /* Designate G3 Character set (ISO 2022) */
+                        term_state = TSTATE_SETG3;
+                        usedcharsets = true;
+                        break;
+
+                    case '~': /* Locking Shift 1, right */
+                        gr = 1;
+                        usedcharsets = true;
+                        break;
+
+                    case 'n': /* Locking Shift 2 */
+                        gl = 2;
+                        usedcharsets = true;
+                        break;
+
+                    case '}': /* Locking Shift 2, right */
+                        gr = 2;
+                        usedcharsets = true;
+                        break;
+
+                    case 'o': /* Locking Shift 3 */
+                        gl = 3;
+                        usedcharsets = true;
+                        break;
+
+                    case '|': /* Locking Shift 3, right */
+                        gr = 3;
+                        usedcharsets = true;
+                        break;
+
+                    case 'Y': /* vt52 cursor address mode , next chars are x,y */
+                        term_state = TSTATE_VT52Y;
+                        break;
+
+                    case '_':
+                        term_state = TSTATE_TITLE;
+                        break;
+
+                    case '\\':
+                        // TODO save title
+                        term_state = TSTATE_DATA;
+                        break;
+
+                    default:
+                        debug("ESC unknown letter: " + c + " (" + ((int) c) + ")");
+                        break;
+                }
+
+                break;
+
+            case TSTATE_VT52X:
+                C = c - 37;
+
+                if (C < 0)
+                    C = 0;
+                else if (C >= width)
+                    C = width - 1;
+
+                term_state = TSTATE_VT52Y;
+                break;
+
+            case TSTATE_VT52Y:
+                R = c - 37;
+
+                if (R < 0)
+                    R = 0;
+                else if (R >= height)
+                    R = height - 1;
+
+                term_state = TSTATE_DATA;
+                break;
+
+            case TSTATE_SETG0:
+                if (c != '0' && c != 'A' && c != 'B' && c != '<')
+                    debug("ESC ( " + c + ": G0 char set?  (" + ((int) c) + ")");
+                else {
+                    if (debug > 2) debug("ESC ( : G0 char set  (" + c + " " + ((int) c) + ")");
+
+                    gx[0] = c;
+                }
+
+                term_state = TSTATE_DATA;
+                break;
+
+            case TSTATE_SETG1:
+                if (c != '0' && c != 'A' && c != 'B' && c != '<') {
+                    debug("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?");
+                }
+                else {
+                    if (debug > 2) debug("ESC ) :G1 char set  (" + c + " " + ((int) c) + ")");
+
+                    gx[1] = c;
+                }
+
+                term_state = TSTATE_DATA;
+                break;
+
+            case TSTATE_SETG2:
+                if (c != '0' && c != 'A' && c != 'B' && c != '<')
+                    debug("ESC*:G2 char set?  (" + ((int) c) + ")");
+                else {
+                    if (debug > 2) debug("ESC*:G2 char set  (" + c + " " + ((int) c) + ")");
+
+                    gx[2] = c;
+                }
+
+                term_state = TSTATE_DATA;
+                break;
+
+            case TSTATE_SETG3:
+                if (c != '0' && c != 'A' && c != 'B' && c != '<')
+                    debug("ESC+:G3 char set?  (" + ((int) c) + ")");
+                else {
+                    if (debug > 2) debug("ESC+:G3 char set  (" + c + " " + ((int) c) + ")");
+
+                    gx[3] = c;
+                }
+
+                term_state = TSTATE_DATA;
+                break;
+
+            case TSTATE_ESCSQUARE:
+                switch (c) {
+                    case '8':
+                        for (int i = 0; i < columns; i++)
+                            for (int j = 0; j < rows; j++)
+                                putChar(i, j, 'E', 0);
+
+                        break;
+
+                    default:
+                        debug("ESC # " + c + " not supported.");
+                        break;
+                }
+
+                term_state = TSTATE_DATA;
+                break;
+
+            case TSTATE_DCS:
+                if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) {
+                    handle_dcs(dcs);
+                    term_state = TSTATE_DATA;
+                    break;
+                }
+
+                dcs = dcs + c;
+                break;
+
+            case TSTATE_DCEQ:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                        DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
+                        term_state = TSTATE_DCEQ;
+                        break;
+
+                    case ';':
+                        DCEvar++;
+                        DCEvars[DCEvar] = 0;
+                        term_state = TSTATE_DCEQ;
+                        break;
+
+                    case 's': // XTERM_SAVE missing!
+                        if (true || debug > 1)
+                            debug("ESC [ ? " + DCEvars[0] + " s unimplemented!");
+
+                        break;
+
+                    case 'r': // XTERM_RESTORE
+                        if (true || debug > 1)
+                            debug("ESC [ ? " + DCEvars[0] + " r");
+
+                        /* DEC Mode reset */
+                        for (int i = 0; i <= DCEvar; i++) {
+                            switch (DCEvars[i]) {
+                                case 3: /* 80 columns*/
+                                    setScreenSize(80, height, true);
+                                    break;
+
+                                case 4: /* scrolling mode, smooth */
+                                    break;
+
+                                case 5: /* light background */
+                                    break;
+
+                                case 6: /* DECOM (Origin Mode) move inside margins. */
+                                    moveoutsidemargins = true;
+                                    break;
+
+                                case 7: /* DECAWM: Autowrap Mode */
+                                    wraparound = false;
+                                    break;
+
+                                case 12:/* local echo off */
+                                    break;
+
+                                case 9:     /* X10 mouse */
+                                case 1000:  /* xterm style mouse report on */
+                                case 1001:
+                                case 1002:
+                                case 1003:
+                                    mouserpt = DCEvars[i];
+                                    break;
+
+                                default:
+                                    debug("ESC [ ? " + DCEvars[0] + " r, unimplemented!");
+                            }
+                        }
+
+                        break;
+
+                    case 'h': // DECSET
+                        if (debug > 0)
+                            debug("ESC [ ? " + DCEvars[0] + " h");
+
+                        /* DEC Mode set */
+                        for (int i = 0; i <= DCEvar; i++) {
+                            switch (DCEvars[i]) {
+                                case 1:  /* Application cursor keys */
+                                    KeyUp[0] = "\u001bOA";
+                                    KeyDown[0] = "\u001bOB";
+                                    KeyRight[0] = "\u001bOC";
+                                    KeyLeft[0] = "\u001bOD";
+                                    break;
+
+                                case 2: /* DECANM */
+                                    vt52mode = false;
+                                    break;
+
+                                case 3: /* 132 columns*/
+                                    setScreenSize(132, height, true);
+                                    break;
+
+                                case 6: /* DECOM: move inside margins. */
+                                    moveoutsidemargins = false;
+                                    break;
+
+                                case 7: /* DECAWM: Autowrap Mode */
+                                    wraparound = true;
+                                    break;
+
+                                case 25: /* turn cursor on */
+                                    showCursor(true);
+                                    break;
+
+                                case 9:     /* X10 mouse */
+                                case 1000:  /* xterm style mouse report on */
+                                case 1001:
+                                case 1002:
+                                case 1003:
+                                    mouserpt = DCEvars[i];
+                                    break;
+
+                                /* unimplemented stuff, fall through */
+                                /* 4  - scrolling mode, smooth */
+                                /* 5  - light background */
+                                /* 12 - local echo off */
+                                /* 18 - DECPFF - Printer Form Feed Mode -> On */
+                                /* 19 - DECPEX - Printer Extent Mode -> Screen */
+                                default:
+                                    debug("ESC [ ? " + DCEvars[0] + " h, unsupported.");
+                                    break;
+                            }
+                        }
+
+                        break;
+
+                    case 'i': // DEC Printer Control, autoprint, echo screenchars to printer
+
+                        // This is different to CSI i!
+                        // Also: "Autoprint prints a final display line only when the
+                        // cursor is moved off the line by an autowrap or LF, FF, or
+                        // VT (otherwise do not print the line)."
+                        switch (DCEvars[0]) {
+                            case 1:
+                                if (debug > 1)
+                                    debug("CSI ? 1 i : Print line containing cursor");
+
+                                break;
+
+                            case 4:
+                                if (debug > 1)
+                                    debug("CSI ? 4 i : Start passthrough printing");
+
+                                break;
+
+                            case 5:
+                                if (debug > 1)
+                                    debug("CSI ? 4 i : Stop passthrough printing");
+
+                                break;
+                        }
+
+                        break;
+
+                    case 'l': //DECRST
+
+                        /* DEC Mode reset */
+                        if (debug > 0)
+                            debug("ESC [ ? " + DCEvars[0] + " l");
+
+                        for (int i = 0; i <= DCEvar; i++) {
+                            switch (DCEvars[i]) {
+                                case 1:  /* Application cursor keys */
+                                    KeyUp[0] = "\u001b[A";
+                                    KeyDown[0] = "\u001b[B";
+                                    KeyRight[0] = "\u001b[C";
+                                    KeyLeft[0] = "\u001b[D";
+                                    break;
+
+                                case 2: /* DECANM */
+                                    vt52mode = true;
+                                    break;
+
+                                case 3: /* 80 columns*/
+                                    setScreenSize(80, height, true);
+                                    break;
+
+                                case 6: /* DECOM: move outside margins. */
+                                    moveoutsidemargins = true;
+                                    break;
+
+                                case 7: /* DECAWM: Autowrap Mode OFF */
+                                    wraparound = false;
+                                    break;
+
+                                case 25: /* turn cursor off */
+                                    showCursor(false);
+                                    break;
+
+                                /* Unimplemented stuff: */
+                                /* 4  - scrolling mode, jump */
+                                /* 5  - dark background */
+                                /* 7  - DECAWM - no wrap around mode */
+                                /* 12 - local echo on */
+                                /* 18 - DECPFF - Printer Form Feed Mode -> Off*/
+                                /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */
+                                case 9:     /* X10 mouse */
+                                case 1000:  /* xterm style mouse report OFF */
+                                case 1001:
+                                case 1002:
+                                case 1003:
+                                    mouserpt = 0;
+                                    break;
+
+                                default:
+                                    debug("ESC [ ? " + DCEvars[0] + " l, unsupported.");
+                                    break;
+                            }
+                        }
+
+                        break;
+
+                    case 'n':
+                        if (debug > 0)
+                            debug("ESC [ ? " + DCEvars[0] + " n");
+
+                        switch (DCEvars[0]) {
+                            case 15:
+                                /* printer? no printer. */
+                                write((ESC) + "[?13n", false);
+                                debug("ESC[5n");
+                                break;
+
+                            default:
+                                debug("ESC [ ? " + DCEvars[0] + " n, unsupported.");
+                                break;
+                        }
+
+                        break;
+
+                    default:
+                        debug("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported.");
+                        break;
+                }
+
+                break;
+
+            case TSTATE_CSI_EX:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case ESC:
+                        term_state = TSTATE_ESC;
+                        break;
+
+                    default:
+                        debug("Unknown character ESC[! character is " + (int) c);
+                        break;
+                }
+
+                break;
+
+            case TSTATE_CSI_TICKS:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case 'p':
+                        debug("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]);
+
+                        if (DCEvars[0] == 61) {
+                            output8bit = false;
+                            break;
+                        }
+
+                        if (DCEvars[1] == 1) {
+                            output8bit = false;
+                        }
+                        else {
+                            output8bit = true; /* 0 or 2 */
+                        }
+
+                        break;
+
+                    default:
+                        debug("Unknown ESC [...  \"" + c);
+                        break;
+                }
+
+                break;
+
+            case TSTATE_CSI_EQUAL:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                        DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
+                        term_state = TSTATE_CSI_EQUAL;
+                        break;
+
+                    case ';':
+                        DCEvar++;
+                        DCEvars[DCEvar] = 0;
+                        term_state = TSTATE_CSI_EQUAL;
+                        break;
+
+                    case 'F': { /* SCO ANSI foreground */
+                            int newcolor;
+                            debug("ESC [ = " + DCEvars[0] + " F");
+                            attributes &= ~COLOR_FG;
+                            newcolor = ((DCEvars[0] & 1) << 2) |
+                                       (DCEvars[0] & 2)   |
+                                       ((DCEvars[0] & 4) >> 2) ;
+                            attributes |= (newcolor + 1) << COLOR_FG_SHIFT;
+                            break;
+                        }
+
+                    case 'G': { /* SCO ANSI background */
+                            int newcolor;
+                            debug("ESC [ = " + DCEvars[0] + " G");
+                            attributes &= ~COLOR_BG;
+                            newcolor = ((DCEvars[0] & 1) << 2) |
+                                       (DCEvars[0] & 2)   |
+                                       ((DCEvars[0] & 4) >> 2) ;
+                            attributes |= (newcolor + 1) << COLOR_BG_SHIFT;
+                            break;
+                        }
+
+                    default:
+                        debugStr.append("Unknown ESC [ = ");
+
+                        for (int i = 0; i <= DCEvar; i++) {
+                            debugStr.append(DCEvars[i])
+                            .append(',');
+                        }
+
+                        debugStr.append(c);
+                        debug(debugStr.toString());
+                        debugStr.setLength(0);
+                        break;
+                }
+
+                break;
+
+            case TSTATE_CSI_DOLLAR:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case '}':
+                        debug("Active Status Display now " + DCEvars[0]);
+                        statusmode = DCEvars[0];
+                        break;
+
+                    /* bad documentation?
+                       case '-':
+                       debug("Set Status Display now "+DCEvars[0]);
+                       break;
+                    */
+                    case '~':
+                        debug("Status Line mode now " + DCEvars[0]);
+                        break;
+
+                    default:
+                        debug("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]);
+                        break;
+                }
+
+                break;
+
+            case TSTATE_CSI:
+                term_state = TSTATE_DATA;
+
+                switch (c) {
+                    case '"':
+                        term_state = TSTATE_CSI_TICKS;
+                        break;
+
+                    case '$':
+                        term_state = TSTATE_CSI_DOLLAR;
+                        break;
+
+                    case '=':
+                        term_state = TSTATE_CSI_EQUAL;
+                        break;
+
+                    case '!':
+                        term_state = TSTATE_CSI_EX;
+                        break;
+
+                    case '?':
+                        DCEvar = 0;
+                        DCEvars[0] = 0;
+                        term_state = TSTATE_DCEQ;
+                        break;
+
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                        DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
+                        term_state = TSTATE_CSI;
+                        break;
+
+                    case ';':
+                        DCEvar++;
+                        DCEvars[DCEvar] = 0;
+                        term_state = TSTATE_CSI;
+                        break;
+
+                    case 'c':/* send primary device attributes */
+                        /* send (ESC[?61c) */
+                        String subcode = "";
+
+                        if (terminalID.equals("vt320")) subcode = "63;";
+
+                        if (terminalID.equals("vt220")) subcode = "62;";
+
+                        if (terminalID.equals("vt100")) subcode = "61;";
+
+                        write((ESC) + "[?" + subcode + "1;2c", false);
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " c");
+
+                        break;
+
+                    case 'q':
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " q");
+
+                        break;
+
+                    case 'g':
+
+                        /* used for tabsets */
+                        switch (DCEvars[0]) {
+                            case 3:/* clear them */
+                                Tabs = new byte[width];
+                                break;
+
+                            case 0:
+                                Tabs[C] = 0;
+                                break;
+                        }
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " g");
+
+                        break;
+
+                    case 'h':
+                        switch (DCEvars[0]) {
+                            case 4:
+                                insertmode = 1;
+                                break;
+
+                            case 20:
+                                debug("Setting CRLF to TRUE");
+                                sendcrlf = true;
+                                break;
+
+                            default:
+                                debug("unsupported: ESC [ " + DCEvars[0] + " h");
+                                break;
+                        }
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " h");
+
+                        break;
+
+                    case 'i': // Printer Controller mode.
+
+                        // "Transparent printing sends all output, except the CSI 4 i
+                        //  termination string, to the printer and not the screen,
+                        //  uses an 8-bit channel if no parity so NUL and DEL will be
+                        //  seen by the printer and by the termination recognizer code,
+                        //  and all translation and character set selections are
+                        //  bypassed."
+                        switch (DCEvars[0]) {
+                            case 0:
+                                if (debug > 1)
+                                    debug("CSI 0 i:  Print Screen, not implemented.");
+
+                                break;
+
+                            case 4:
+                                if (debug > 1)
+                                    debug("CSI 4 i:  Enable Transparent Printing, not implemented.");
+
+                                break;
+
+                            case 5:
+                                if (debug > 1)
+                                    debug("CSI 4/5 i:  Disable Transparent Printing, not implemented.");
+
+                                break;
+
+                            default:
+                                debug("ESC [ " + DCEvars[0] + " i, unimplemented!");
+                        }
+
+                        break;
+
+                    case 'l':
+                        switch (DCEvars[0]) {
+                            case 4:
+                                insertmode = 0;
+                                break;
+
+                            case 20:
+                                debug("Setting CRLF to FALSE");
+                                sendcrlf = false;
+                                break;
+
+                            default:
+                                debug("ESC [ " + DCEvars[0] + " l, unimplemented!");
+                                break;
+                        }
+
+                        break;
+
+                    case 'A': { // CUU
+                            int limit;
+
+                            /* FIXME: xterm only cares about 0 and topmargin */
+                            if (R >= getTopMargin()) {
+                                limit = getTopMargin();
+                            }
+                            else
+                                limit = 0;
+
+                            if (DCEvars[0] == 0)
+                                R--;
+                            else
+                                R -= DCEvars[0];
+
+                            if (R < limit)
+                                R = limit;
+
+                            if (debug > 1)
+                                debug("ESC [ " + DCEvars[0] + " A");
+
+                            break;
+                        }
+
+                    case 'B': // CUD
+                        /* cursor down n (1) times */
+                        {
+                            int limit;
+
+                            if (R <= getBottomMargin()) {
+                                limit = getBottomMargin();
+                            }
+                            else
+                                limit = rows - 1;
+
+                            if (DCEvars[0] == 0)
+                                R++;
+                            else
+                                R += DCEvars[0];
+
+                            if (R > limit)
+                                R = limit;
+                            else {
+                                if (debug > 2) debug("Not limited.");
+                            }
+
+                            if (debug > 2) debug("to: " + R);
+
+                            if (debug > 1)
+                                debug("ESC [ " + DCEvars[0] + " B (at C=" + C + ")");
+
+                            break;
+                        }
+
+                    case 'C':
+                        if (DCEvars[0] == 0)
+                            DCEvars[0] = 1;
+
+                        while (DCEvars[0]-- > 0) {
+                            C++;
+                        }
+
+                        if (C >= columns)
+                            C = columns - 1;
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " C");
+
+                        break;
+
+                    case 'd': // CVA
+                        R = DCEvars[0] - 1;
+
+                        if (R < 0)
+                            R = 0;
+                        else if (R >= height)
+                            R = height - 1;
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " d");
+
+                        break;
+
+                    case 'D':
+                        if (DCEvars[0] == 0)
+                            DCEvars[0] = 1;
+
+                        while (DCEvars[0]-- > 0) {
+                            C--;
+                        }
+
+                        if (C < 0) C = 0;
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " D");
+
+                        break;
+
+                    case 'r': // DECSTBM
+                        if (DCEvar > 0) { //  Ray:  Any argument is optional
+                            R = DCEvars[1] - 1;
+
+                            if (R < 0)
+                                R = rows - 1;
+                            else if (R >= rows) {
+                                R = rows - 1;
+                            }
+                        }
+                        else
+                            R = rows - 1;
+
+                        int bot = R;
+
+                        if (R >= DCEvars[0]) {
+                            R = DCEvars[0] - 1;
+
+                            if (R < 0)
+                                R = 0;
+                        }
+
+                        setMargins(R, bot);
+                        _SetCursor(0, 0);
+
+                        if (debug > 1)
+                            debug("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r");
+
+                        break;
+
+                    case 'G':  /* CUP  / cursor absolute column */
+                        C = DCEvars[0];
+
+                        if (C < 0)
+                            C = 0;
+                        else if (C >= width)
+                            C = width - 1;
+
+                        if (debug > 1) debug("ESC [ " + DCEvars[0] + " G");
+
+                        break;
+
+                    case 'H':  /* CUP  / cursor position */
+                        /* gets 2 arguments */
+                        _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1);
+
+                        if (debug > 2) {
+                            debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins " + moveoutsidemargins);
+                            debug("	-> R now " + R + ", C now " + C);
+                        }
+
+                        break;
+
+                    case 'f':  /* move cursor 2 */
+                        /* gets 2 arguments */
+                        R = DCEvars[0] - 1;
+                        C = DCEvars[1] - 1;
+
+                        if (C < 0)
+                            C = 0;
+                        else if (C >= width)
+                            C = width - 1;
+
+                        if (R < 0)
+                            R = 0;
+                        else if (R >= height)
+                            R = height - 1;
+
+                        if (debug > 2)
+                            debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f");
+
+                        break;
+
+                    case 'S': /* ind aka 'scroll forward' */
+                        if (DCEvars[0] == 0)
+                            insertLine(getBottomMargin(), SCROLL_UP);
+                        else
+                            insertLine(getBottomMargin(), DCEvars[0], SCROLL_UP);
+
+                        break;
+
+                    case 'L':
+
+                        /* insert n lines */
+                        if (DCEvars[0] == 0)
+                            insertLine(R, SCROLL_DOWN);
+                        else
+                            insertLine(R, DCEvars[0], SCROLL_DOWN);
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")");
+
+                        break;
+
+                    case 'T': /* 'ri' aka scroll backward */
+                        if (DCEvars[0] == 0)
+                            insertLine(getTopMargin(), SCROLL_DOWN);
+                        else
+                            insertLine(getTopMargin(), DCEvars[0], SCROLL_DOWN);
+
+                        break;
+
+                    case 'M':
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R);
+
+                        if (DCEvars[0] == 0)
+                            deleteLine(R);
+                        else
+                            for (int i = 0; i < DCEvars[0]; i++)
+                                deleteLine(R);
+
+                        break;
+
+                    case 'K':
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " K");
+
+                        /* clear in line */
+                        switch (DCEvars[0]) {
+                            case 6: /* 97801 uses ESC[6K for delete to end of line */
+                            case 0:/*clear to right*/
+                                if (C < columns - 1)
+                                    deleteArea(C, R, columns - C, 1, attributes);
+
+                                break;
+
+                            case 1:/*clear to the left, including this */
+                                if (C > 0)
+                                    deleteArea(0, R, C + 1, 1, attributes);
+
+                                break;
+
+                            case 2:/*clear whole line */
+                                deleteArea(0, R, columns, 1, attributes);
+                                break;
+                        }
+
+                        break;
+
+                    case 'J':
+
+                        /* clear below current line */
+                        switch (DCEvars[0]) {
+                            case 0:
+                                if (R < rows - 1)
+                                    deleteArea(0, R + 1, columns, rows - R - 1, attributes);
+
+                                if (C < columns - 1)
+                                    deleteArea(C, R, columns - C, 1, attributes);
+
+                                break;
+
+                            case 1:
+                                if (R > 0)
+                                    deleteArea(0, 0, columns, R, attributes);
+
+                                if (C > 0)
+                                    deleteArea(0, R, C + 1, 1, attributes);  // include up to and including current
+
+                                break;
+
+                            case 2:
+                                deleteArea(0, 0, columns, rows, attributes);
+                                break;
+                        }
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " J");
+
+                        break;
+
+                    case '@':
+                        if (DCEvars[0] == 0) DCEvars[0] = 1;
+
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " @");
+
+                        for (int i = 0; i < DCEvars[0]; i++)
+                            insertChar(C, R, ' ', attributes);
+
+                        break;
+
+                    case 'X': {
+                            int toerase = DCEvars[0];
+
+                            if (debug > 1)
+                                debug("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R);
+
+                            if (toerase == 0)
+                                toerase = 1;
+
+                            if (toerase + C > columns)
+                                toerase = columns - C;
+
+                            deleteArea(C, R, toerase, 1, attributes);
+                            // does not change cursor position
+                            break;
+                        }
+
+                    case 'P':
+                        if (debug > 1)
+                            debug("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R);
+
+                        if (DCEvars[0] == 0) DCEvars[0] = 1;
+
+                        for (int i = 0; i < DCEvars[0]; i++)
+                            deleteChar(C, R);
+
+                        break;
+
+                    case 'n':
+                        switch (DCEvars[0]) {
+                            case 5: /* malfunction? No malfunction. */
+                                writeSpecial((ESC) + "[0n");
+
+                                if (debug > 1)
+                                    debug("ESC[5n");
+
+                                break;
+
+                            case 6:
+                                // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize
+                                // FIXME check again.
+                                // FIXME: but vttest thinks different???
+                                writeSpecial((ESC) + "[" + R + ";" + C + "R");
+
+                                if (debug > 1)
+                                    debug("ESC[6n");
+
+                                break;
+
+                            default:
+                                if (debug > 0)
+                                    debug("ESC [ " + DCEvars[0] + " n??");
+
+                                break;
+                        }
+
+                        break;
+
+                    case 's':  /* DECSC - save cursor */
+                        Sc = C;
+                        Sr = R;
+                        Sa = attributes;
+
+                        if (debug > 3)
+                            debug("ESC[s");
+
+                        break;
+
+                    case 'u': /* DECRC - restore cursor */
+                        C = Sc;
+                        R = Sr;
+                        attributes = Sa;
+
+                        if (debug > 3)
+                            debug("ESC[u");
+
+                        break;
+
+                    case 'm':  /* attributes as color, bold , blink,*/
+                        if (debug > 3)
+                            debug("ESC [ ");
+
+                        if (DCEvar == 0 && DCEvars[0] == 0)
+                            attributes = 0;
+
+                        for (int i = 0; i <= DCEvar; i++) {
+                            switch (DCEvars[i]) {
+                                case 0:
+                                    if (DCEvar > 0) {
+                                        if (terminalID.equals("scoansi")) {
+                                            attributes &= COLOR; /* Keeps color. Strange but true. */
+                                        }
+                                        else {
+                                            attributes = 0;
+                                        }
+                                    }
+
+                                    break;
+
+                                case 1:
+                                    attributes |= BOLD;
+                                    attributes &= ~LOW;
+                                    break;
+
+                                case 2:
+
+                                    /* SCO color hack mode */
+                                    if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) {
+                                        int ncolor;
+                                        attributes &= ~(COLOR | BOLD);
+                                        ncolor = DCEvars[i + 1];
+
+                                        if ((ncolor & 8) == 8)
+                                            attributes |= BOLD;
+
+                                        ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
+                                        attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT;
+                                        ncolor = DCEvars[i + 2];
+                                        ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
+                                        attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT;
+                                        i += 2;
+                                    }
+                                    else {
+                                        attributes |= LOW;
+                                    }
+
+                                    break;
+
+                                case 3: /* italics */
+                                    attributes |= INVERT;
+                                    break;
+
+                                case 4:
+                                    attributes |= UNDERLINE;
+                                    break;
+
+                                case 7:
+                                    attributes |= INVERT;
+                                    break;
+
+                                case 8:
+                                    attributes |= INVISIBLE;
+                                    break;
+
+                                case 5: /* blink on */
+                                    break;
+
+                                /* 10 - ANSI X3.64-1979, select primary font, don't display control
+                                 *      chars, don't set bit 8 on output */
+                                case 10:
+                                    gl = 0;
+                                    usedcharsets = true;
+                                    break;
+
+                                /* 11 - ANSI X3.64-1979, select second alt. font, display control
+                                 *      chars, set bit 8 on output */
+                                case 11: /* SMACS , as */
+                                case 12:
+                                    gl = 1;
+                                    usedcharsets = true;
+                                    break;
+
+                                case 21: /* normal intensity */
+                                    attributes &= ~(LOW | BOLD);
+                                    break;
+
+                                case 23: /* italics off */
+                                    attributes &= ~INVERT;
+                                    break;
+
+                                case 25: /* blinking off */
+                                    break;
+
+                                case 27:
+                                    attributes &= ~INVERT;
+                                    break;
+
+                                case 28:
+                                    attributes &= ~INVISIBLE;
+                                    break;
+
+                                case 24:
+                                    attributes &= ~UNDERLINE;
+                                    break;
+
+                                case 22:
+                                    attributes &= ~BOLD;
+                                    break;
+
+                                case 30:
+                                case 31:
+                                case 32:
+                                case 33:
+                                case 34:
+                                case 35:
+                                case 36:
+                                case 37:
+                                    attributes &= ~COLOR_FG;
+                                    attributes |= ((DCEvars[i] - 30) + 1) << COLOR_FG_SHIFT;
+                                    break;
+
+                                case 38:
+                                    if (DCEvars[i + 1] == 5) {
+                                        attributes &= ~COLOR_FG;
+                                        attributes |= ((DCEvars[i + 2]) + 1) << COLOR_FG_SHIFT;
+                                        i += 2;
+                                    }
+
+                                    break;
+
+                                case 39:
+                                    attributes &= ~COLOR_FG;
+                                    break;
+
+                                case 40:
+                                case 41:
+                                case 42:
+                                case 43:
+                                case 44:
+                                case 45:
+                                case 46:
+                                case 47:
+                                    attributes &= ~COLOR_BG;
+                                    attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT;
+                                    break;
+
+                                case 48:
+                                    if (DCEvars[i + 1] == 5) {
+                                        attributes &= ~COLOR_BG;
+                                        attributes |= (DCEvars[i + 2] + 1) << COLOR_BG_SHIFT;
+                                        i += 2;
+                                    }
+
+                                    break;
+
+                                case 49:
+                                    attributes &= ~COLOR_BG;
+                                    break;
+
+                                case 90:
+                                case 91:
+                                case 92:
+                                case 93:
+                                case 94:
+                                case 95:
+                                case 96:
+                                case 97:
+                                    attributes &= ~COLOR_FG;
+                                    attributes |= ((DCEvars[i] - 82) + 1) << COLOR_FG_SHIFT;
+                                    break;
+
+                                case 100:
+                                case 101:
+                                case 102:
+                                case 103:
+                                case 104:
+                                case 105:
+                                case 106:
+                                case 107:
+                                    attributes &= ~COLOR_BG;
+                                    attributes |= ((DCEvars[i] - 92) + 1) << COLOR_BG_SHIFT;
+                                    break;
+
+                                default:
+                                    debugStr.append("ESC [ ")
+                                    .append(DCEvars[i])
+                                    .append(" m unknown...");
+                                    debug(debugStr.toString());
+                                    debugStr.setLength(0);
+                                    break;
+                            }
+
+                            if (debug > 3) {
+                                debugStr.append(DCEvars[i])
+                                .append(';');
+                                debug(debugStr.toString());
+                                debugStr.setLength(0);
+                            }
+                        }
+
+                        if (debug > 3) {
+                            debugStr.append(" (attributes = ")
+                            .append(attributes)
+                            .append(")m");
+                            debug(debugStr.toString());
+                            debugStr.setLength(0);
+                        }
+
+                        break;
+
+                    default:
+                        debugStr.append("ESC [ unknown letter: ")
+                        .append(c)
+                        .append(" (")
+                        .append((int)c)
+                        .append(')');
+                        debug(debugStr.toString());
+                        debugStr.setLength(0);
+                        break;
+                }
+
+                break;
+
+            case TSTATE_TITLE:
+                switch (c) {
+                    case ESC:
+                        term_state = TSTATE_ESC;
+                        break;
+
+                    default:
+                        // TODO save title
+                        break;
+                }
+
+                break;
+
+            default:
+                term_state = TSTATE_DATA;
+                break;
+        }
+
+        setCursorPosition(C, R);
+    }
+
+    /* hard reset the terminal */
+    public void reset() {
+        gx[0] = 'B';
+        gx[1] = 'B';
+        gx[2] = 'B';
+        gx[3] = 'B';
+        gl = 0;  // default GL to G0
+        gr = 2;  // default GR to G2
+        onegl = -1; // Single shift override
+        /* reset tabs */
+        int nw = width;
+
+        if (nw < 132) nw = 132;
+
+        Tabs = new byte[nw];
+
+        for (int i = 0; i < nw; i += 8) {
+            Tabs[i] = 1;
+        }
+
+        deleteArea(0, 0, width, height, attributes);
+        setMargins(0, height);
+        C = R = 0;
+        _SetCursor(0, 0);
+
+        if (display != null)
+            display.resetColors();
+
+        showCursor(true);
+        /*FIXME:*/
+        term_state = TSTATE_DATA;
+    }
+}