Java tutorial
//Changes (c) STFC/CCLRC 2006-2007 /* * Sshtools - SSHTerm * * The contents of this package have been derived from the Java * Telnet/SSH Applet from http://javassh.org. The files have been * modified and are supplied under the terms of the original license. * * 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 Library 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. */ package com.sshtools.sshterm.emulation; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.awt.Toolkit; import java.awt.event.KeyEvent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.sshtools.j2ssh.io.DynamicBuffer; import com.sshtools.j2ssh.session.PseudoTerminal; public class TerminalEmulation extends VDUBuffer implements VDUInput, PseudoTerminal { private static Log log = LogFactory.getLog(TerminalEmulation.class); private final static int debug = 0; public final static String VT320 = "vt320"; public final static String VT220 = "vt220"; public final static String VT100 = "vt100"; public final static String ANSI = "ansi"; public final static int EOL_DEFAULT = 0; public final static int EOL_CR_LF = 1; public final static int EOL_CR = 2; 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; // 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' }; 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, }; //private OutputStream consoleOut; private Object consoleLock = new Object(); // Output stream that accepts raw terminal data private TerminalOutputStream tout; private DynamicBuffer in; private DynamicBuffer out; //private OutputStream uout; private boolean localecho = false; // =================================================================== // the actual terminal emulation code comes here: // =================================================================== private String terminalID = "vt320"; private String answerBack = "Use Terminal.answerback to set ...\n"; private int eol; // X - COLUMNS, Y - ROWS int R; // X - COLUMNS, Y - ROWS int C; int attributes = 0; int Sc; int Sr; int Sa; int Stm; int Sbm; char Sgr; char 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; /* * The graphics charsets * B - default ASCII * A - ISO Latin 1 * 0 - DEC SPECIAL * < - User defined * .... */ char[] gx = { // same initial set as in XTERM. 'B', // g0 '0', // g1 'B', // g2 'B', }; char gl = 0; // default GL to G0 char gr = 2; // default GR to G2 int onegl = -1; private String[] Numpad; private String[] FunctionKey; private String[] FunctionKeyShift; private String[] FunctionKeyCtrl; private String[] FunctionKeyAlt; private String[] TabKey; private String[] KeyUp; private String[] KeyDown; private String[] KeyLeft; private String[] KeyRight; private String KPMinus; private String KPComma; private String KPPeriod; private String KPEnter; private String PF1; private String PF2; private String PF3; private String PF4; private String Help; private String Do; private String Find; private String Select; private String[] KeyHome; private String[] KeyEnd; private String[] Insert; private String[] Remove; private String[] PrevScn; private String[] NextScn; private String[] Escape; private String[] BackSpace; private String[] NUMDot; private String[] NUMPlus; private String osc; private String dcs; /* * to memorize OSC & DCS control sequence */ private int term_state = TSTATE_DATA; private boolean vms = false; private byte[] Tabs; private int[] DCEvars = new int[30]; private int DCEvar; /* public InputStream getTerminalInputStream() { return termIn; }*/ public TerminalEmulation(String term, int width, int height) throws IOException { super(width, height); this.terminalID = term; reset(); setVMS(false); setIBMCharset(false); setBufferSize(100); //setBorder(2, false); int nw = getColumns(); if (nw < 132) { nw = 132; } //catch possible later 132/80 resizes Tabs = new byte[nw]; for (int i = 0; i < nw; i += 8) { Tabs[i] = 1; } /* * 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] = "\u007F"; //"\b"; } /* * 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 TerminalEmulation(String term) throws IOException { this(term, 80, 24); } public static List getSupportedEmulations() { List list = new ArrayList(); list.add(ANSI); list.add(VT100); list.add(VT220); list.add(VT320); return list; } private void write(byte[] b) { write(b, 0, b.length); } private void write(byte[] b, int off, int len) { try { in.getOutputStream().write(b, off, len); // termOut.write(b, off, len); } catch (IOException ioe) { log.error("Terminal emulation attempted to write", ioe); } } public void beep() { /* * do nothing by default */ Toolkit.getDefaultToolkit().beep(); } public void setEOL(int eol) { this.eol = eol; } public int getEOL() { return eol; } public void setTerminalType(String term) { terminalID = term; } private void putString(String s) { int len = s.length(); // System.err.println("'"+s+"'"); if (len > 0) { markLine(R, 1); for (int i = 0; i < len; i++) { // System.err.print(s.charAt(i)+"("+(int)s.charAt(i)+")"); putChar(s.charAt(i), false); } setCursorPosition(C, R); redraw(); } } protected void sendTelnetCommand(byte cmd) { } /*public void setConsoleOutputStream(OutputStream consoleOut) { synchronized (consoleLock) { this.consoleOut = consoleOut; } }*/ public OutputStream getOutputStream() { return in.getOutputStream(); } private boolean doWrite = false; // Only write if someone is reading. No one seems to do this! public InputStream getInputStream() { doWrite = true; return out.getInputStream(); } public OutputStream getTerminalOutputStream() { return tout; } public InputStream getTerminalInputStream() { return in.getInputStream(); } /*public void setUserOutputStream(OutputStream uout) { this.uout = uout; }*/ public String getTerm() { return this.terminalID; } public void clearScreen() { charArray = new char[getBufferSize()][width]; charAttributes = new int[getBufferSize()][width]; setCursorPosition(0, 0); R = 0; C = 0; } 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 } 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; } public void setLocalEcho(boolean echo) { localecho = echo; } public void setVMS(boolean vms) { this.vms = vms; } public void setIBMCharset(boolean ibm) { useibmcharset = ibm; } public void setKeyCodes(Properties codes) { String res; String[] 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); } } } public void setAnswerBack(String ab) { this.answerBack = unEscape(ab); } public int getWidth() { return 0; } public int getHeight() { return 0; } public String getEncodedTerminalModes() { return ""; } private boolean write(String s, boolean doecho) { if (debug > 2) { System.out.println("write(|" + s + "|," + doecho); } 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(String s) { return write(s, localecho); } static String unEscape(String tmp) { int idx = 0; int oldidx = 0; String cmd; // System.err.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; } 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); } public void keyPressed(int keyCode, char keyChar, int modifiers) { if (debug > 0) { System.out.println("keyPressed(" + keyCode + "," + keyChar + "," + modifiers); } boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0; boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0; boolean alt = (modifiers & VDUInput.KEY_ALT) != 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 KeyEvent.VK_PAUSE: if (shift || control) { sendTelnetCommand((byte) 243); } // BREAK break; case KeyEvent.VK_ESCAPE: writeSpecial(Escape[xind]); break; case KeyEvent.VK_F1: writeSpecial(fmap[1]); break; case KeyEvent.VK_F2: writeSpecial(fmap[2]); break; case KeyEvent.VK_F3: writeSpecial(fmap[3]); break; case KeyEvent.VK_F4: writeSpecial(fmap[4]); break; case KeyEvent.VK_F5: writeSpecial(fmap[5]); break; case KeyEvent.VK_F6: writeSpecial(fmap[6]); break; case KeyEvent.VK_F7: writeSpecial(fmap[7]); break; case KeyEvent.VK_F8: writeSpecial(fmap[8]); break; case KeyEvent.VK_F9: writeSpecial(fmap[9]); break; case KeyEvent.VK_F10: writeSpecial(fmap[10]); break; case KeyEvent.VK_F11: writeSpecial(fmap[11]); break; case KeyEvent.VK_F12: writeSpecial(fmap[12]); break; case KeyEvent.VK_UP: writeSpecial(KeyUp[xind]); break; case KeyEvent.VK_DOWN: writeSpecial(KeyDown[xind]); break; case KeyEvent.VK_LEFT: writeSpecial(KeyLeft[xind]); break; case KeyEvent.VK_RIGHT: writeSpecial(KeyRight[xind]); break; case KeyEvent.VK_PAGE_DOWN: writeSpecial(NextScn[xind]); break; case KeyEvent.VK_PAGE_UP: writeSpecial(PrevScn[xind]); break; case KeyEvent.VK_INSERT: writeSpecial(Insert[xind]); break; case KeyEvent.VK_DELETE: writeSpecial(Remove[xind]); break; case KeyEvent.VK_BACK_SPACE: writeSpecial(BackSpace[xind]); if (localecho) { if (BackSpace[xind] == "\b" || BackSpace[xind] == "\u007f") { putString("\b \b"); // make the last char 'deleted' } else { putString(BackSpace[xind]); // echo it } } break; case KeyEvent.VK_HOME: writeSpecial(KeyHome[xind]); break; case KeyEvent.VK_END: writeSpecial(KeyEnd[xind]); break; case KeyEvent.VK_NUM_LOCK: if (vms && control) { writeSpecial(PF1); } if (!control) { numlock = !numlock; } break; case KeyEvent.VK_CAPS_LOCK: capslock = !capslock; return; case KeyEvent.VK_SHIFT: case KeyEvent.VK_CONTROL: case KeyEvent.VK_ALT: return; default: break; } } public void keyReleased(KeyEvent evt) { } public void keyTyped(int keyCode, char keyChar, int modifiers) { if (debug > 0) { System.out.println("keyTyped(" + keyCode + "," + keyChar + "," + modifiers); } // If there is a scrollbar, scroll to the end if ((display != null) && (display.getScrollBar() != null)) { if (display.getScrollBar().getValue() != display.getScrollBar().getMaximum()) { display.getScrollBar().setValue(display.getScrollBar().getMaximum()); } } boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0; boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0; // fix problem with Linux Java 6 -- really nasty if (control && keyChar >= 'a' && keyChar <= 'z') keyChar = (char) (keyChar - 96); if (control && shift && keyChar >= 'A' && keyChar <= 'Z') keyChar = (char) (keyChar - 64); boolean alt = (modifiers & VDUInput.KEY_ALT) != 0; if (keyChar == '\t') { if (shift) { write(TabKey[1], false); } else { if (control) { write(TabKey[2], false); } else { if (alt) { write(TabKey[3], false); } else { write(TabKey[0], false); } } } return; } if (alt) { //04/04/07 commented out to stop shortcuts causing strange characters. //write("" + ( (char) (keyChar | 0x80))); return; } if (((keyCode == KeyEvent.VK_ENTER) || (keyChar == 10)) && !control) { if (((eol == EOL_DEFAULT) && sendcrlf) || (eol == EOL_CR_LF)) { write("\r\n", false); if (localecho) { putString("\r\n"); } } else { write("\r", false); if (localecho) { putString("\r"); } } return; } if ((keyCode == 10) && !control) { System.out.println("Sending \\r"); write("\r", false); return; } // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @, // so we can't just use it here... will probably break some other VMS // codes. -Marcus // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ') // && control) if (((!vms && (keyChar == '2')) || (keyChar == ' ')) && control) { write("" + (char) 0); } if (vms) { if ((keyChar == 127) && !control) { if (shift) { writeSpecial(Insert[0]); } // VMS shift delete = insert else { writeSpecial(Remove[0]); } // VMS delete = remove return; } else if (control) { switch (keyChar) { case '0': writeSpecial(Numpad[0]); return; case '1': writeSpecial(Numpad[1]); return; case '2': writeSpecial(Numpad[2]); return; case '3': writeSpecial(Numpad[3]); return; case '4': writeSpecial(Numpad[4]); return; case '5': writeSpecial(Numpad[5]); return; case '6': writeSpecial(Numpad[6]); return; case '7': writeSpecial(Numpad[7]); return; case '8': writeSpecial(Numpad[8]); return; case '9': writeSpecial(Numpad[9]); return; case '.': writeSpecial(KPPeriod); return; case '-': case 31: writeSpecial(KPMinus); return; case '+': writeSpecial(KPComma); return; case 10: writeSpecial(KPEnter); return; case '/': writeSpecial(PF2); return; case '*': writeSpecial(PF3); return; /* * NUMLOCK handled in keyPressed */ default: break; } } /* * Now what does this do and how did it get here. -Marcus * if (shift && keyChar < 32) { * write(PF1+(char)(keyChar + 64)); * return; * } */ } if (debug > 2) { System.out.println("vt320: keyPressed " + keyCode + "\"" + keyChar + "\""); } // FIXME: not used? String[] fmap; int xind; xind = 0; fmap = FunctionKey; if (shift) { fmap = FunctionKeyShift; xind = 1; } if (control) { fmap = FunctionKeyCtrl; xind = 2; } if (alt) { fmap = FunctionKeyAlt; xind = 3; } if (keyCode == KeyEvent.VK_ESCAPE) { writeSpecial(Escape[xind]); return; } if ((modifiers & VDUInput.KEY_ACTION) != 0) { switch (keyCode) { case KeyEvent.VK_NUMPAD0: writeSpecial(Numpad[0]); return; case KeyEvent.VK_NUMPAD1: writeSpecial(Numpad[1]); return; case KeyEvent.VK_NUMPAD2: writeSpecial(Numpad[2]); return; case KeyEvent.VK_NUMPAD3: writeSpecial(Numpad[3]); return; case KeyEvent.VK_NUMPAD4: writeSpecial(Numpad[4]); return; case KeyEvent.VK_NUMPAD5: writeSpecial(Numpad[5]); return; case KeyEvent.VK_NUMPAD6: writeSpecial(Numpad[6]); return; case KeyEvent.VK_NUMPAD7: writeSpecial(Numpad[7]); return; case KeyEvent.VK_NUMPAD8: writeSpecial(Numpad[8]); return; case KeyEvent.VK_NUMPAD9: writeSpecial(Numpad[9]); return; case KeyEvent.VK_DECIMAL: writeSpecial(NUMDot[xind]); return; case KeyEvent.VK_ADD: writeSpecial(NUMPlus[xind]); return; } } if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) { write("" + keyChar); return; } } private void handle_dcs(String dcs) { System.out.println("DCS: " + dcs); } private void handle_osc(String osc) { System.out.println("OSC: " + osc); } public char map_cp850_unicode(char x) { if (x >= 0x100) { return x; } return unimap[x]; } private void _SetCursor(int row, int col) { int maxr = getRows(); int tm = getTopMargin(); R = (row < 0) ? 0 : row; C = (col < 0) ? 0 : col; if (!moveoutsidemargins) { R += tm; maxr = getBottomMargin(); } if (R > maxr) { R = maxr; } } private void putChar(char c, boolean doshowcursor) { int rows = getRows(); //statusline int columns = getColumns(); int tm = getTopMargin(); int bm = getBottomMargin(); // byte msg[]; boolean mapped = false; if (debug > 4) { System.out.println("putChar(" + c + " [" + ((int) c) + "]) at R=" + R + " , C=" + C + ", columns=" + columns + ", rows=" + rows + ", state=" + term_state + ")"); } markLine(R, 1); if (c > 255) { if (debug > 0) { System.out.println("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 > tm) { R--; } else { insertLine(R, 1, SCROLL_DOWN); } if (debug > 1) { System.out.println("RI"); } break; case IND: if (debug > 2) { System.out.println("IND at " + R + ", tm is " + tm + ", bm is " + bm); } if ((R == bm) || (R == (rows - 1))) { insertLine(R, 1, SCROLL_UP); } else { R++; } if (debug > 1) { System.out.println("IND (at " + R + " )"); } break; case NEL: if ((R == bm) || (R == (rows - 1))) { insertLine(R, 1, SCROLL_UP); } else { R++; } C = 0; if (debug > 1) { System.out.println("NEL (at " + R + " )"); } break; case HTS: Tabs[C] = 1; if (debug > 1) { System.out.println("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': try { if (doWrite) out.getOutputStream().write(c); } catch (IOException ex) { } do { // Don't overwrite or insert! TABS are not destructive, but movement! C++; } while ((C < columns) && (Tabs[C] == 0)); lastwaslf = 0; break; case '\r': try { if (doWrite) out.getOutputStream().write(c); } catch (IOException ex1) { } C = 0; break; case '\n': try { if (doWrite) out.getOutputStream().write(c); } catch (IOException ex2) { } if (debug > 3) { System.out.println("R= " + R + ", bm " + bm + ", tm=" + tm + ", rows=" + rows); } if (!vms) { if ((lastwaslf != 0) && (lastwaslf != c)) { // Ray: I do not understand this logic. break; } lastwaslf = c; /* * C = 0; */ } if ((R == bm) || (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) { System.out.println("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) { if (R < (rows - 1)) { R++; } else { insertLine(R, 1, SCROLL_UP); } C = 0; } else { // cursor stays on last character. C = columns - 1; } } // 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) (((int) c & 0x7f) | 0x80); mapped = true; break; case 'A': case 'B': // Latin-1 , ASCII -> fall through mapped = true; break; default: System.out.println("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: System.out.println("Unsupported GR mapping: " + gx[gr]); break; } } } if (!mapped && useibmcharset) { c = map_cp850_unicode(c); } /* * if(true || (statusmode == 0)) { */ if (insertmode == 1) { insertChar(C, R, c, attributes); } else { try { if (doWrite) out.getOutputStream().write(c); putChar(C, R, c, attributes); } catch (IOException ex3) { } } /* * } 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: System.out.println("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 character sets */ gx[0] = 'B'; gx[1] = '0'; gx[2] = 'B'; gx[3] = 'B'; gl = 0; // default GL to G0 gr = 1; // default GR to G1 /* * reset tabs */ int nw = getColumns(); if (nw < 132) { nw = 132; } Tabs = new byte[nw]; for (int i = 0; i < nw; i += 8) { Tabs[i] = 1; } /* * FIXME: */ 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 - 1)) { 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 == bm) || (R == (rows - 1))) { insertLine(R, 1, SCROLL_UP); } else { R++; } C = 0; if (debug > 1) { System.out.println("ESC E (at " + R + ")"); } break; case 'D': /* * IND */ if ((R == bm) || (R == (rows - 1))) { insertLine(R, 1, SCROLL_UP); } else { R++; } if (debug > 1) { System.out.println("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 if (R > bm) { // outside scrolling region break; } if (R > tm) { // just go up 1 line. R--; } else { // scroll down insertLine(R, 1, SCROLL_DOWN); } /* * else do nothing ; */ if (debug > 2) { System.out.println("ESC M "); } break; case 'H': if (debug > 1) { System.out.println("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) { System.out.println("ESC ="); } keypadmode = true; break; case '<': /* * vt52 mode off */ vt52mode = false; break; case '>': /* * normal keypad */ if (debug > 0) { System.out.println("ESC >"); } keypadmode = false; break; case '7': /* * save cursor, attributes, margins */ 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]; } Stm = getTopMargin(); Sbm = getBottomMargin(); if (debug > 1) { System.out.println("ESC 7"); } break; case '8': /* * restore cursor, attributes, margins */ C = Sc; R = Sr; gl = Sgl; gr = Sgr; for (int i = 0; i < 4; i++) { gx[i] = Sgx[i]; } setTopMargin(Stm); setBottomMargin(Sbm); attributes = Sa; if (debug > 1) { System.out.println("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; default: System.out.println("ESC unknown letter: " + c + " (" + ((int) c) + ")"); break; } break; case TSTATE_VT52X: C = c - 37; term_state = TSTATE_VT52Y; break; case TSTATE_VT52Y: R = c - 37; term_state = TSTATE_DATA; break; case TSTATE_SETG0: if ((c != '0') && (c != 'A') && (c != 'B') && (c != '<')) { System.out.println("ESC ( " + c + ": G0 char set? (" + ((int) c) + ")"); } else { if (debug > 2) { System.out.println("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 != '<')) { System.out.println("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?"); } else { if (debug > 2) { System.out.println("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 != '<')) { System.out.println("ESC*:G2 char set? (" + ((int) c) + ")"); } else { if (debug > 2) { System.out.println("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 != '<')) { System.out.println("ESC+:G3 char set? (" + ((int) c) + ")"); } else { if (debug > 2) { System.out.println("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: System.out.println("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) + ((int) 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)) { System.out.println("ESC [ ? " + DCEvars[0] + " s unimplemented!"); } break; case 'r': // XTERM_RESTORE if (true || (debug > 1)) { System.out.println("ESC [ ? " + DCEvars[0] + " r"); } /* * DEC Mode reset */ for (int i = 0; i <= DCEvar; i++) { switch (DCEvars[i]) { case 3: /* * 80 columns */ setScreenSize(80, getRows()); 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: System.out.println("ESC [ ? " + DCEvars[0] + " r, unimplemented!"); } } break; case 'h': // DECSET if (debug > 0) { System.out.println("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, getRows()); 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); redraw(); 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: System.out.println("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) { System.out.println("CSI ? 1 i : Print line containing cursor"); } break; case 4: if (debug > 1) { System.out.println("CSI ? 4 i : Start passthrough printing"); } break; case 5: if (debug > 1) { System.out.println("CSI ? 4 i : Stop passthrough printing"); } break; } break; case 'l': //DECRST /* * DEC Mode reset */ if (debug > 0) { System.out.println("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, getRows()); 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); redraw(); 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: System.out.println("ESC [ ? " + DCEvars[0] + " l, unsupported."); break; } } break; case 'n': if (debug > 0) { System.out.println("ESC [ ? " + DCEvars[0] + " n"); } switch (DCEvars[0]) { case 15: /* * printer? no printer. */ write(((char) ESC) + "[?13n", false); System.out.println("ESC[5n"); break; default: System.out.println("ESC [ ? " + DCEvars[0] + " n, unsupported."); break; } break; default: System.out.println("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: System.out.println("Unknown character ESC[! character is " + (int) c); break; } break; case TSTATE_CSI_TICKS: term_state = TSTATE_DATA; switch (c) { case 'p': System.out.println("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: System.out.println("Unknown ESC [... \"" + c); break; } break; case TSTATE_CSI_DOLLAR: term_state = TSTATE_DATA; switch (c) { case '}': System.out.println("Active Status Display now " + DCEvars[0]); statusmode = DCEvars[0]; break; /* * bad documentation? * case '-': * System.out.println("Set Status Display now "+DCEvars[0]); * break; */ case '~': System.out.println("Status Line mode now " + DCEvars[0]); break; default: System.out.println("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_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) + ((int) 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(((char) ESC) + "[?" + subcode + "1;2c", false); if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " c"); } break; case 'q': if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " q"); } break; case 'g': /* * used for tabsets */ switch (DCEvars[0]) { case 3: /* * clear them */ Tabs = new byte[getColumns()]; break; case 0: Tabs[C] = 0; break; } if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " g"); } break; case 'h': switch (DCEvars[0]) { case 4: insertmode = 1; break; case 20: System.out.println("Setting CRLF to TRUE"); sendcrlf = true; break; default: System.out.println("unsupported: ESC [ " + DCEvars[0] + " h"); break; } if (debug > 1) { System.out.println("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) { System.out.println("CSI 0 i: Print Screen, not implemented."); } break; case 4: if (debug > 1) { System.out.println("CSI 4 i: Enable Transparent Printing, not implemented."); } break; case 5: if (debug > 1) { System.out.println("CSI 4/5 i: Disable Transparent Printing, not implemented."); } break; default: System.out.println("ESC [ " + DCEvars[0] + " i, unimplemented!"); } break; case 'l': switch (DCEvars[0]) { case 4: insertmode = 0; break; case 20: System.out.println("Setting CRLF to FALSE"); sendcrlf = false; break; default: System.out.println("ESC [ " + DCEvars[0] + " l, unimplemented!"); break; } break; case 'A': { // CUU int limit; /* * FIXME: xterm only cares about 0 and topmargin */ if (R > bm) { limit = bm + 1; } else if (R >= tm) { limit = tm; } else { limit = 0; } if (DCEvars[0] == 0) { R--; } else { R -= DCEvars[0]; } if (R < limit) { R = limit; } if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " A"); } break; } case 'B': { // CUD /* * cursor down n (1) times */ int limit; if (R < tm) { limit = tm - 1; } else if (R <= bm) { limit = bm; } else { limit = rows - 1; } if (DCEvars[0] == 0) { R++; } else { R += DCEvars[0]; } if (R > limit) { R = limit; } else { if (debug > 2) { System.out.println("Not limited."); } } if (debug > 2) { System.out.println("to: " + R); } if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " B (at C=" + C + ")"); } break; } case 'C': if (DCEvars[0] == 0) { C++; } else { C += DCEvars[0]; } if (C > (columns - 1)) { C = columns - 1; } if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " C"); } break; case 'd': // CVA R = DCEvars[0]; if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " d"); } break; case 'D': if (DCEvars[0] == 0) { C--; } else { C -= DCEvars[0]; } if (C < 0) { C = 0; } if (debug > 1) { System.out.println("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; } setBottomMargin(R); if (R >= DCEvars[0]) { R = DCEvars[0] - 1; if (R < 0) { R = 0; } } setTopMargin(R); _SetCursor(0, 0); if (debug > 1) { System.out.println("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r"); } break; case 'G': /* * CUP / cursor absolute column */ C = DCEvars[0]; if (debug > 1) { System.out.println("ESC [ " + DCEvars[0] + " G"); } break; case 'H': /* * CUP / cursor position */ /* * gets 2 arguments */ _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1); if (debug > 2) { System.out.println("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins " + moveoutsidemargins); System.out.println(" -> 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; } if (R < 0) { R = 0; } if (debug > 2) { System.out.println("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f"); } break; case 'S': /* * ind aka 'scroll forward' */ if (DCEvars[0] == 0) { insertLine(rows - 1, SCROLL_UP); } else { insertLine(rows - 1, 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) { System.out.println("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")"); } break; case 'T': /* * 'ri' aka scroll backward */ if (DCEvars[0] == 0) { insertLine(0, SCROLL_DOWN); } else { insertLine(0, DCEvars[0], SCROLL_DOWN); } break; case 'M': if (debug > 1) { System.out.println("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) { System.out.println("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) { System.out.println("ESC [ " + DCEvars[0] + " J"); } break; case '@': if (debug > 1) { System.out.println("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) { System.out.println("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) { System.out.println("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(((char) ESC) + "[0n"); if (debug > 1) { System.out.println("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(((char) ESC) + "[" + R + ";" + C + "R"); if (debug > 1) { System.out.println("ESC[6n"); } break; default: if (debug > 0) { System.out.println("ESC [ " + DCEvars[0] + " n??"); } break; } break; case 's': /* * DECSC - save cursor */ Sc = C; Sr = R; Sa = attributes; if (debug > 3) { System.out.println("ESC[s"); } break; case 'u': /* * DECRC - restore cursor */ C = Sc; R = Sr; attributes = Sa; if (debug > 3) { System.out.println("ESC[u"); } break; case 'm': /* * attributes as color, bold , blink, */ if (debug > 3) { System.out.print("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) << 4); ncolor = DCEvars[i + 2]; ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2); attributes |= (((ncolor) + 1) << 8); i += 2; } else { attributes |= LOW; } break; case 4: attributes |= UNDERLINE; break; case 7: attributes |= INVERT; 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 25: /* * blinking off */ break; case 27: attributes &= ~INVERT; 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) << 4); 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) << 8); break; case 49: attributes &= ~COLOR_BG; break; default: System.out.println("ESC [ " + DCEvars[i] + " m unknown..."); break; } if (debug > 3) { System.out.print("" + DCEvars[i] + ";"); } } if (debug > 3) { System.out.print(" (attributes = " + attributes + ")m \n"); } break; default: System.out.println("ESC [ unknown letter:" + c + " (" + ((int) c) + ")"); break; } break; default: term_state = TSTATE_DATA; break; } if (C > columns) { C = columns; } if (R > rows) { R = rows; } if (C < 0) { C = 0; } if (R < 0) { R = 0; } if (doshowcursor) { setCursorPosition(C, R); } markLine(R, 1); } /* * hard reset the terminal */ public void reset() { try { // Force a write to clear any blocked threads waiting if (in != null) { in.getOutputStream().close(); //in.getOutputStream().write(0); } if (out != null) { out.getOutputStream().close(); // out.getOutputStream().write(0); } if (tout != null) { //tout.write(0); tout.close(); } } catch (IOException ex) { } tout = new TerminalOutputStream(); in = new DynamicBuffer(); out = new DynamicBuffer(); gx[0] = 'B'; gx[1] = '0'; gx[2] = 'B'; gx[3] = 'B'; gl = 0; // default GL to G0 gr = 1; // default GR to G1 /* * reset tabs */ int nw = getColumns(); if (nw < 132) { nw = 132; } Tabs = new byte[nw]; for (int i = 0; i < nw; i += 8) { Tabs[i] = 1; } /* * FIXME: */ term_state = TSTATE_DATA; } class TerminalOutputStream extends OutputStream { private Object lock = new Object(); public TerminalOutputStream() { } public void write(int b) throws IOException { synchronized (lock) { byte[] buf = new byte[1]; buf[0] = (byte) b; TerminalEmulation.this.putString(new String(buf, 0, 1, "latin1")); } } public void write(byte[] buf, int off, int len) throws IOException { synchronized (lock) { TerminalEmulation.this.putString(new String(buf, off, len, "latin1")); } } } }