| /* |
| * 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 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 |
| */ |
| @SuppressWarnings("unused") |
| public abstract class vt320 extends VDUBuffer implements VDUInput { |
| |
| /** |
| * The current version id tag. |
| * <P> |
| * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $ |
| * |
| */ |
| public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $"; |
| |
| /** 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 array of bytes to be sent |
| */ |
| public abstract void write(int b); |
| |
| /** |
| * Play the beep sound ... |
| */ |
| public void beep() { /* do nothing by default */ |
| } |
| |
| /** |
| * 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) { |
| isWide = fullwidths[i] == 1; |
| } |
| } |
| } |
| } |
| |
| if (lastChar != -1) { |
| putChar((char) lastChar, isWide, false); |
| } |
| |
| setCursorPosition(C, R); |
| redraw(); |
| } |
| } |
| |
| protected void sendTelnetCommand(byte cmd) { |
| |
| } |
| |
| /** |
| * 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) { |
| mousecode = 0x20 | mousebut; |
| } else { |
| 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) { |
| 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) { |
| 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_UP = 14; |
| public final static int KEY_DOWN = 15; |
| public final static int KEY_LEFT = 16; |
| public final static int KEY_RIGHT = 17; |
| public final static int KEY_PAGE_DOWN = 18; |
| public final static int KEY_PAGE_UP = 19; |
| public final static int KEY_INSERT = 20; |
| public final static int KEY_DELETE = 21; |
| public final static int KEY_BACK_SPACE = 22; |
| public final static int KEY_HOME = 23; |
| public final static int KEY_END = 24; |
| public final static int KEY_NUM_LOCK = 25; |
| public final static int KEY_CAPS_LOCK = 26; |
| public final static int KEY_SHIFT = 27; |
| public final static int KEY_CONTROL = 28; |
| public final static int KEY_ALT = 29; |
| public final static int KEY_ENTER = 30; |
| public final static int KEY_NUMPAD0 = 31; |
| public final static int KEY_NUMPAD1 = 32; |
| public final static int KEY_NUMPAD2 = 33; |
| public final static int KEY_NUMPAD3 = 34; |
| public final static int KEY_NUMPAD4 = 35; |
| public final static int KEY_NUMPAD5 = 36; |
| public final static int KEY_NUMPAD6 = 37; |
| public final static int KEY_NUMPAD7 = 38; |
| public final static int KEY_NUMPAD8 = 39; |
| public final static int KEY_NUMPAD9 = 40; |
| public final static int KEY_DECIMAL = 41; |
| public final static int KEY_ADD = 42; |
| public final static int KEY_ESCAPE = 43; |
| |
| 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... |
| */ |
| 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_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; |
| return; |
| case KEY_SHIFT: |
| case KEY_CONTROL: |
| case KEY_ALT: |
| return; |
| default: |
| break; |
| } |
| } |
| |
| /* |
| * public void keyReleased(KeyEvent evt) { if (debug > 1) debug("keyReleased("+evt+")"); // ignore |
| * } |
| */ |
| /** |
| * Handle key Typed events for the terminal, this will get all normal key types, but no |
| * shift/alt/control/numlock. |
| */ |
| public void keyTyped(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) { |
| debug("keyTyped(" + keyCode + ", " + (int) keyChar + ", " + modifiers + ")"); |
| } |
| |
| 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) { |
| write(((char) (keyChar | 0x80))); |
| return; |
| } |
| |
| if (((keyCode == KEY_ENTER) || (keyChar == 10)) && !control) { |
| write('\r'); |
| if (localecho) { |
| putString("\r\n"); // bad hack |
| } |
| return; |
| } |
| |
| if ((keyCode == 10) && !control) { |
| debug("Sending \\r"); |
| write('\r'); |
| 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(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; } |
| */ |
| } |
| } |
| |
| // 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 == KEY_ESCAPE) { |
| writeSpecial(Escape[xind]); |
| return; |
| } |
| |
| if ((modifiers & VDUInput.KEY_ACTION) != 0) { |
| switch (keyCode) { |
| case KEY_NUMPAD0: |
| writeSpecial(Numpad[0]); |
| return; |
| case KEY_NUMPAD1: |
| writeSpecial(Numpad[1]); |
| return; |
| case KEY_NUMPAD2: |
| writeSpecial(Numpad[2]); |
| return; |
| case KEY_NUMPAD3: |
| writeSpecial(Numpad[3]); |
| return; |
| case KEY_NUMPAD4: |
| writeSpecial(Numpad[4]); |
| return; |
| case KEY_NUMPAD5: |
| writeSpecial(Numpad[5]); |
| return; |
| case KEY_NUMPAD6: |
| writeSpecial(Numpad[6]); |
| return; |
| case KEY_NUMPAD7: |
| writeSpecial(Numpad[7]); |
| return; |
| case KEY_NUMPAD8: |
| writeSpecial(Numpad[8]); |
| return; |
| case KEY_NUMPAD9: |
| writeSpecial(Numpad[9]); |
| return; |
| case KEY_DECIMAL: |
| writeSpecial(NUMDot[xind]); |
| return; |
| case KEY_ADD: |
| writeSpecial(NUMPlus[xind]); |
| return; |
| } |
| } |
| |
| if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) { |
| write(keyChar); |
| return; |
| } |
| } |
| |
| 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 = height; // statusline |
| int columns = 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) { |
| 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) { |
| 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]; |
| 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(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) { |
| debug("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) { |
| 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 (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; |
| } |
| } |