aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/de/mud
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2014-10-01 23:04:51 +0100
committerKenny Root <kenny@the-b.org>2014-10-01 12:48:19 +0100
commit49b779dcaf03e3598d2709b321e20ea029b25163 (patch)
tree05af547b1f1433d7dd6f7373d0b25a455e053a03 /app/src/main/java/de/mud
parentd64786d9197090c74072b648e487e3d34817bb57 (diff)
downloadconnectbot-49b779dcaf03e3598d2709b321e20ea029b25163.tar.gz
connectbot-49b779dcaf03e3598d2709b321e20ea029b25163.tar.bz2
connectbot-49b779dcaf03e3598d2709b321e20ea029b25163.zip
Convert to gradle build system
Diffstat (limited to 'app/src/main/java/de/mud')
-rw-r--r--app/src/main/java/de/mud/telnet/TelnetProtocolHandler.java678
-rw-r--r--app/src/main/java/de/mud/terminal/Precomposer.java1052
-rw-r--r--app/src/main/java/de/mud/terminal/VDUBuffer.java854
-rw-r--r--app/src/main/java/de/mud/terminal/VDUDisplay.java40
-rw-r--r--app/src/main/java/de/mud/terminal/VDUInput.java90
-rw-r--r--app/src/main/java/de/mud/terminal/vt320.java3032
6 files changed, 5746 insertions, 0 deletions
diff --git a/app/src/main/java/de/mud/telnet/TelnetProtocolHandler.java b/app/src/main/java/de/mud/telnet/TelnetProtocolHandler.java
new file mode 100644
index 0000000..74f08bb
--- /dev/null
+++ b/app/src/main/java/de/mud/telnet/TelnetProtocolHandler.java
@@ -0,0 +1,678 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 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.telnet;
+
+import java.io.IOException;
+/**
+ * This is a telnet protocol handler. The handler needs implementations
+ * for several methods to handle the telnet options and to be able to
+ * read and write the buffer.
+ * <P>
+ * <B>Maintainer:</B> Marcus Meissner
+ *
+ * @version $Id: TelnetProtocolHandler.java 503 2005-10-24 07:34:13Z marcus $
+ * @author Matthias L. Jugel, Marcus Meissner
+ */
+public abstract class TelnetProtocolHandler {
+ /** contains the current revision id */
+ public final static String ID = "$Id: TelnetProtocolHandler.java 503 2005-10-24 07:34:13Z marcus $";
+
+ /** debug level */
+ private final static int debug = 0;
+
+ /** temporary buffer for data-telnetstuff-data transformation */
+ private byte[] tempbuf = new byte[0];
+
+ /** the data sent on pressing <RETURN> \n */
+ private byte[] crlf = new byte[2];
+ /** the data sent on pressing <LineFeed> \r */
+ private byte[] cr = new byte[2];
+
+ /**
+ * Create a new telnet protocol handler.
+ */
+ public TelnetProtocolHandler() {
+ reset();
+
+ crlf[0] = 13; crlf[1] = 10;
+ cr[0] = 13; cr[1] = 0;
+ }
+
+ /**
+ * Get the current terminal type for TTYPE telnet option.
+ * @return the string id of the terminal
+ */
+ protected abstract String getTerminalType();
+
+ /**
+ * Get the current window size of the terminal for the
+ * NAWS telnet option.
+ * @return the size of the terminal as Dimension
+ */
+ protected abstract int[] getWindowSize();
+
+ /**
+ * Set the local echo option of telnet.
+ * @param echo true for local echo, false for no local echo
+ */
+ protected abstract void setLocalEcho(boolean echo);
+
+ /**
+ * Generate an EOR (end of record) request. For use by prompt displaying.
+ */
+ protected abstract void notifyEndOfRecord();
+
+ /**
+ * Send data to the remote host.
+ * @param b array of bytes to send
+ */
+ protected abstract void write(byte[] b) throws IOException;
+
+ /**
+ * Read the charset name from terminal.
+ */
+ protected abstract String getCharsetName();
+
+ /**
+ * Send one byte to the remote host.
+ * @param b the byte to be sent
+ * @see #write(byte[] b)
+ */
+ private static byte[] one = new byte[1];
+ private void write(byte b) throws IOException {
+ one[0] = b;
+ write(one);
+ }
+
+ /**
+ * Reset the protocol handler. This may be necessary after the
+ * connection was closed or some other problem occured.
+ */
+ public void reset() {
+ neg_state = 0;
+ receivedDX = new byte[256];
+ sentDX = new byte[256];
+ receivedWX = new byte[256];
+ sentWX = new byte[256];
+ }
+
+ // ===================================================================
+ // the actual negotiation handling for the telnet protocol follows:
+ // ===================================================================
+
+ /** state variable for telnet negotiation reader */
+ private byte neg_state = 0;
+
+ /** constants for the negotiation state */
+ private final static byte STATE_DATA = 0;
+ private final static byte STATE_IAC = 1;
+ private final static byte STATE_IACSB = 2;
+ private final static byte STATE_IACWILL = 3;
+ private final static byte STATE_IACDO = 4;
+ private final static byte STATE_IACWONT = 5;
+ private final static byte STATE_IACDONT = 6;
+ private final static byte STATE_IACSBIAC = 7;
+ private final static byte STATE_IACSBDATA = 8;
+ private final static byte STATE_IACSBDATAIAC = 9;
+
+ /** What IAC SB <xx> we are handling right now */
+ private byte current_sb;
+
+ /** current SB negotiation buffer */
+ private byte[] sbbuf;
+
+ /** IAC - init sequence for telnet negotiation. */
+ private final static byte IAC = (byte)255;
+ /** [IAC] End Of Record */
+ private final static byte EOR = (byte)239;
+ /** [IAC] WILL */
+ private final static byte WILL = (byte)251;
+ /** [IAC] WONT */
+ private final static byte WONT = (byte)252;
+ /** [IAC] DO */
+ private final static byte DO = (byte)253;
+ /** [IAC] DONT */
+ private final static byte DONT = (byte)254;
+ /** [IAC] Sub Begin */
+ private final static byte SB = (byte)250;
+ /** [IAC] Sub End */
+ private final static byte SE = (byte)240;
+ /** Telnet option: binary mode */
+ private final static byte TELOPT_BINARY= (byte)0; /* binary mode */
+ /** Telnet option: echo text */
+ private final static byte TELOPT_ECHO = (byte)1; /* echo on/off */
+ /** Telnet option: sga */
+ private final static byte TELOPT_SGA = (byte)3; /* supress go ahead */
+ /** Telnet option: End Of Record */
+ private final static byte TELOPT_EOR = (byte)25; /* end of record */
+ /** Telnet option: Negotiate About Window Size */
+ private final static byte TELOPT_NAWS = (byte)31; /* NA-WindowSize*/
+ /** Telnet option: Terminal Type */
+ private final static byte TELOPT_TTYPE = (byte)24; /* terminal type */
+ /** Telnet option: CHARSET */
+ private final static byte TELOPT_CHARSET= (byte)42; /* charset */
+
+ private final static byte[] IACWILL = { IAC, WILL };
+ private final static byte[] IACWONT = { IAC, WONT };
+ private final static byte[] IACDO = { IAC, DO };
+ private final static byte[] IACDONT = { IAC, DONT };
+ private final static byte[] IACSB = { IAC, SB };
+ private final static byte[] IACSE = { IAC, SE };
+
+ private final static byte CHARSET_ACCEPTED = (byte)2;
+ private final static byte CHARSET_REJECTED = (byte)3;
+
+ /** Telnet option qualifier 'IS' */
+ private final static byte TELQUAL_IS = (byte)0;
+ /** Telnet option qualifier 'SEND' */
+ private final static byte TELQUAL_SEND = (byte)1;
+
+ /** What IAC DO(NT) request do we have received already ? */
+ private byte[] receivedDX;
+ /** What IAC WILL/WONT request do we have received already ? */
+ private byte[] receivedWX;
+ /** What IAC DO/DONT request do we have sent already ? */
+ private byte[] sentDX;
+ /** What IAC WILL/WONT request do we have sent already ? */
+ private byte[] sentWX;
+
+ /**
+ * Send a Telnet Escape character (IAC <code>)
+ */
+ public void sendTelnetControl(byte code)
+ throws IOException {
+ byte[] b = new byte[2];
+
+ b[0] = IAC;
+ b[1] = code;
+ write(b);
+ }
+
+ /**
+ * Send the new Window Size (via NAWS)
+ */
+ public void setWindowSize(int columns,int rows)
+ throws IOException {
+ if(debug > 2) System.err.println("sending NAWS");
+
+ if (receivedDX[TELOPT_NAWS] != DO) {
+ System.err.println("not allowed to send NAWS? (DONT NAWS)");
+ return;
+ }
+ write(IAC);write(SB);write(TELOPT_NAWS);
+ write((byte) (columns >> 8));
+ write((byte) (columns & 0xff));
+ write((byte) (rows >> 8));
+ write((byte) (rows & 0xff));
+ write(IAC);write(SE);
+ }
+
+
+ /**
+ * Handle an incoming IAC SB &lt;type&gt; &lt;bytes&gt; IAC SE
+ * @param type type of SB
+ * @param sbata byte array as &lt;bytes&gt;
+ */
+ private void handle_sb(byte type, byte[] sbdata)
+ throws IOException {
+ if(debug > 1)
+ System.err.println("TelnetIO.handle_sb("+type+")");
+ switch (type) {
+ case TELOPT_TTYPE:
+ if (sbdata.length>0 && sbdata[0]==TELQUAL_SEND) {
+ write(IACSB);write(TELOPT_TTYPE);write(TELQUAL_IS);
+ /* FIXME: need more logic here if we use
+ * more than one terminal type
+ */
+ String ttype = getTerminalType();
+ if(ttype == null) ttype = "dumb";
+ write(ttype.getBytes());
+ write(IACSE);
+ }
+ break;
+ case TELOPT_CHARSET:
+ System.out.println("Got SB CHARSET");
+
+ String charsetStr = new String(sbdata, "US-ASCII");
+ if (charsetStr.startsWith("TTABLE ")) {
+ charsetStr = charsetStr.substring(7);
+ }
+ String[] charsets = charsetStr.split(charsetStr.substring(0,0));
+ String myCharset = getCharsetName();
+ for (String charset : charsets) {
+ if (charset.equals(myCharset)) {
+ write(IACSB);write(TELOPT_CHARSET);write(CHARSET_ACCEPTED);
+ write(charset.getBytes());
+ write(IACSE);
+ System.out.println("Sent our charset!");
+ return;
+ }
+ }
+ write(IACSB);write(TELOPT_CHARSET);write(CHARSET_REJECTED);
+ write(IACSE);
+ break;
+ }
+ }
+
+ /**
+ * Do not send any notifications at startup. We do not know,
+ * whether the remote client understands telnet protocol handling,
+ * so we are silent.
+ * (This used to send IAC WILL SGA, but this is false for a compliant
+ * client.)
+ */
+ public void startup() throws IOException {
+ }
+ /**
+ * Transpose special telnet codes like 0xff or newlines to values
+ * that are compliant to the protocol. This method will also send
+ * the buffer immediately after transposing the data.
+ * @param buf the data buffer to be sent
+ */
+ public void transpose(byte[] buf) throws IOException {
+ int i;
+
+ byte[] nbuf,xbuf;
+ int nbufptr=0;
+ nbuf = new byte[buf.length*2]; // FIXME: buffer overflows possible
+
+ for (i = 0; i < buf.length ; i++) {
+ switch (buf[i]) {
+ // Escape IAC twice in stream ... to be telnet protocol compliant
+ // this is there in binary and non-binary mode.
+ case IAC:
+ nbuf[nbufptr++]=IAC;
+ nbuf[nbufptr++]=IAC;
+ break;
+ // We need to heed RFC 854. LF (\n) is 10, CR (\r) is 13
+ // we assume that the Terminal sends \n for lf+cr and \r for just cr
+ // linefeed+carriage return is CR LF */
+ case 10: // \n
+ if (receivedDX[TELOPT_BINARY + 128 ] != DO) {
+ while (nbuf.length - nbufptr < crlf.length) {
+ xbuf = new byte[nbuf.length*2];
+ System.arraycopy(nbuf,0,xbuf,0,nbufptr);
+ nbuf = xbuf;
+ }
+ for (int j=0;j<crlf.length;j++)
+ nbuf[nbufptr++]=crlf[j];
+ break;
+ } else {
+ // copy verbatim in binary mode.
+ nbuf[nbufptr++]=buf[i];
+ }
+ break;
+ // carriage return is CR NUL */
+ case 13: // \r
+ if (receivedDX[TELOPT_BINARY + 128 ] != DO) {
+ while (nbuf.length - nbufptr < cr.length) {
+ xbuf = new byte[nbuf.length*2];
+ System.arraycopy(nbuf,0,xbuf,0,nbufptr);
+ nbuf = xbuf;
+ }
+ for (int j=0;j<cr.length;j++)
+ nbuf[nbufptr++]=cr[j];
+ } else {
+ // copy verbatim in binary mode.
+ nbuf[nbufptr++]=buf[i];
+ }
+ break;
+ // all other characters are just copied
+ default:
+ nbuf[nbufptr++]=buf[i];
+ break;
+ }
+ }
+ xbuf = new byte[nbufptr];
+ System.arraycopy(nbuf,0,xbuf,0,nbufptr);
+ write(xbuf);
+ }
+
+ public void setCRLF(String xcrlf) { crlf = xcrlf.getBytes(); }
+ public void setCR(String xcr) { cr = xcr.getBytes(); }
+
+ /**
+ * Handle telnet protocol negotiation. The buffer will be parsed
+ * and necessary actions are taken according to the telnet protocol.
+ * See <A HREF="RFC-Telnet-URL">RFC-Telnet</A>
+ * @param nbuf the byte buffer put out after negotiation
+ * @return number of bytes processed, 0 for none, and -1 for end of buffer.
+ */
+ public int negotiate(byte nbuf[], int offset)
+ throws IOException
+ {
+ int count = tempbuf.length;
+ byte[] buf = tempbuf;
+ byte sendbuf[] = new byte[3];
+ byte b,reply;
+ int boffset = 0, noffset = offset;
+ boolean dobreak = false;
+
+ if (count == 0) // buffer is empty.
+ return -1;
+
+ while(!dobreak && (boffset < count) && (noffset < nbuf.length)) {
+ b=buf[boffset++];
+ // of course, byte is a signed entity (-128 -> 127)
+ // but apparently the SGI Netscape 3.0 doesn't seem
+ // to care and provides happily values up to 255
+ if (b>=128)
+ b=(byte)(b-256);
+ if(debug > 2) {
+ Byte B = new Byte(b);
+ System.err.print("byte: " + B.intValue()+ " ");
+ }
+ switch (neg_state) {
+ case STATE_DATA:
+ if (b==IAC) {
+ neg_state = STATE_IAC;
+ dobreak = true; // leave the loop so we can sync.
+ } else
+ nbuf[noffset++]=b;
+ break;
+ case STATE_IAC:
+ switch (b) {
+ case IAC:
+ if(debug > 2) System.err.print("IAC ");
+ neg_state = STATE_DATA;
+ nbuf[noffset++]=IAC;
+ break;
+ case WILL:
+ if(debug > 2) System.err.print("WILL ");
+ neg_state = STATE_IACWILL;
+ break;
+ case WONT:
+ if(debug > 2) System.err.print("WONT ");
+ neg_state = STATE_IACWONT;
+ break;
+ case DONT:
+ if(debug > 2) System.err.print("DONT ");
+ neg_state = STATE_IACDONT;
+ break;
+ case DO:
+ if(debug > 2) System.err.print("DO ");
+ neg_state = STATE_IACDO;
+ break;
+ case EOR:
+ if(debug > 1) System.err.print("EOR ");
+ notifyEndOfRecord();
+ dobreak = true; // leave the loop so we can sync.
+ neg_state = STATE_DATA;
+ break;
+ case SB:
+ if(debug > 2) System.err.print("SB ");
+ neg_state = STATE_IACSB;
+ break;
+ default:
+ if(debug > 2) System.err.print("<UNKNOWN "+b+" > ");
+ neg_state = STATE_DATA;
+ break;
+ }
+ break;
+ case STATE_IACWILL:
+ switch(b) {
+ case TELOPT_ECHO:
+ if(debug > 2) System.err.println("ECHO");
+ reply = DO;
+ setLocalEcho(false);
+ break;
+ case TELOPT_SGA:
+ if(debug > 2) System.err.println("SGA");
+ reply = DO;
+ break;
+ case TELOPT_EOR:
+ if(debug > 2) System.err.println("EOR");
+ reply = DO;
+ break;
+ case TELOPT_BINARY:
+ if(debug > 2) System.err.println("BINARY");
+ reply = DO;
+ break;
+ default:
+ if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+ reply = DONT;
+ break;
+ }
+ if(debug > 1) System.err.println("<"+b+", WILL ="+WILL+">");
+ if (reply != sentDX[b+128] || WILL != receivedWX[b+128]) {
+ sendbuf[0]=IAC;
+ sendbuf[1]=reply;
+ sendbuf[2]=b;
+ write(sendbuf);
+ sentDX[b+128] = reply;
+ receivedWX[b+128] = WILL;
+ }
+ neg_state = STATE_DATA;
+ break;
+ case STATE_IACWONT:
+ switch(b) {
+ case TELOPT_ECHO:
+ if(debug > 2) System.err.println("ECHO");
+ setLocalEcho(true);
+ reply = DONT;
+ break;
+ case TELOPT_SGA:
+ if(debug > 2) System.err.println("SGA");
+ reply = DONT;
+ break;
+ case TELOPT_EOR:
+ if(debug > 2) System.err.println("EOR");
+ reply = DONT;
+ break;
+ case TELOPT_BINARY:
+ if(debug > 2) System.err.println("BINARY");
+ reply = DONT;
+ break;
+ default:
+ if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+ reply = DONT;
+ break;
+ }
+ if(reply != sentDX[b+128] || WONT != receivedWX[b+128]) {
+ sendbuf[0]=IAC;
+ sendbuf[1]=reply;
+ sendbuf[2]=b;
+ write(sendbuf);
+ sentDX[b+128] = reply;
+ receivedWX[b+128] = WILL;
+ }
+ neg_state = STATE_DATA;
+ break;
+ case STATE_IACDO:
+ switch (b) {
+ case TELOPT_ECHO:
+ if(debug > 2) System.err.println("ECHO");
+ reply = WILL;
+ setLocalEcho(true);
+ break;
+ case TELOPT_SGA:
+ if(debug > 2) System.err.println("SGA");
+ reply = WILL;
+ break;
+ case TELOPT_TTYPE:
+ if(debug > 2) System.err.println("TTYPE");
+ reply = WILL;
+ break;
+ case TELOPT_BINARY:
+ if(debug > 2) System.err.println("BINARY");
+ reply = WILL;
+ break;
+ case TELOPT_NAWS:
+ if(debug > 2) System.err.println("NAWS");
+ int[] size = getWindowSize();
+ receivedDX[b] = DO;
+ if(size == null) {
+ // this shouldn't happen
+ write(IAC);
+ write(WONT);
+ write(TELOPT_NAWS);
+ reply = WONT;
+ sentWX[b] = WONT;
+ break;
+ }
+ reply = WILL;
+ sentWX[b] = WILL;
+ sendbuf[0]=IAC;
+ sendbuf[1]=WILL;
+ sendbuf[2]=TELOPT_NAWS;
+ write(sendbuf);
+ write(IAC);write(SB);write(TELOPT_NAWS);
+ write((byte) (size[0] >> 8));
+ write((byte) (size[0] & 0xff));
+ write((byte) (size[1] >> 8));
+ write((byte) (size[1] & 0xff));
+ write(IAC);write(SE);
+ break;
+ default:
+ if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+ reply = WONT;
+ break;
+ }
+ if(reply != sentWX[128+b] || DO != receivedDX[128+b]) {
+ sendbuf[0]=IAC;
+ sendbuf[1]=reply;
+ sendbuf[2]=b;
+ write(sendbuf);
+ sentWX[b+128] = reply;
+ receivedDX[b+128] = DO;
+ }
+ neg_state = STATE_DATA;
+ break;
+ case STATE_IACDONT:
+ switch (b) {
+ case TELOPT_ECHO:
+ if(debug > 2) System.err.println("ECHO");
+ reply = WONT;
+ setLocalEcho(false);
+ break;
+ case TELOPT_SGA:
+ if(debug > 2) System.err.println("SGA");
+ reply = WONT;
+ break;
+ case TELOPT_NAWS:
+ if(debug > 2) System.err.println("NAWS");
+ reply = WONT;
+ break;
+ case TELOPT_BINARY:
+ if(debug > 2) System.err.println("BINARY");
+ reply = WONT;
+ break;
+ default:
+ if(debug > 2) System.err.println("<UNKNOWN,"+b+">");
+ reply = WONT;
+ break;
+ }
+ if(reply != sentWX[b+128] || DONT != receivedDX[b+128]) {
+ write(IAC);write(reply);write(b);
+ sentWX[b+128] = reply;
+ receivedDX[b+128] = DONT;
+ }
+ neg_state = STATE_DATA;
+ break;
+ case STATE_IACSBIAC:
+ if(debug > 2) System.err.println(""+b+" ");
+ if (b == IAC) {
+ sbbuf = new byte[0];
+ current_sb = b;
+ neg_state = STATE_IACSBDATA;
+ } else {
+ System.err.println("(bad) "+b+" ");
+ neg_state = STATE_DATA;
+ }
+ break;
+ case STATE_IACSB:
+ if(debug > 2) System.err.println(""+b+" ");
+ switch (b) {
+ case IAC:
+ neg_state = STATE_IACSBIAC;
+ break;
+ default:
+ current_sb = b;
+ sbbuf = new byte[0];
+ neg_state = STATE_IACSBDATA;
+ break;
+ }
+ break;
+ case STATE_IACSBDATA:
+ if (debug > 2) System.err.println(""+b+" ");
+ switch (b) {
+ case IAC:
+ neg_state = STATE_IACSBDATAIAC;
+ break;
+ default:
+ byte[] xsb = new byte[sbbuf.length+1];
+ System.arraycopy(sbbuf,0,xsb,0,sbbuf.length);
+ sbbuf = xsb;
+ sbbuf[sbbuf.length-1] = b;
+ break;
+ }
+ break;
+ case STATE_IACSBDATAIAC:
+ if (debug > 2) System.err.println(""+b+" ");
+ switch (b) {
+ case IAC:
+ neg_state = STATE_IACSBDATA;
+ byte[] xsb = new byte[sbbuf.length+1];
+ System.arraycopy(sbbuf,0,xsb,0,sbbuf.length);
+ sbbuf = xsb;
+ sbbuf[sbbuf.length-1] = IAC;
+ break;
+ case SE:
+ handle_sb(current_sb,sbbuf);
+ current_sb = 0;
+ neg_state = STATE_DATA;
+ break;
+ case SB:
+ handle_sb(current_sb,sbbuf);
+ neg_state = STATE_IACSB;
+ break;
+ default:
+ neg_state = STATE_DATA;
+ break;
+ }
+ break;
+ default:
+ if (debug > 1)
+ System.err.println("This should not happen: "+neg_state+" ");
+ neg_state = STATE_DATA;
+ break;
+ }
+ }
+ // shrink tempbuf to new processed size.
+ byte[] xb = new byte[count-boffset];
+ System.arraycopy(tempbuf,boffset,xb,0,count-boffset);
+ tempbuf = xb;
+ return noffset - offset;
+ }
+
+ public void inputfeed(byte[] b, int offset, int len) {
+ byte[] xb = new byte[tempbuf.length+len];
+
+ System.arraycopy(tempbuf,0,xb,0,tempbuf.length);
+ System.arraycopy(b,offset,xb,tempbuf.length,len);
+ tempbuf = xb;
+ }
+}
diff --git a/app/src/main/java/de/mud/terminal/Precomposer.java b/app/src/main/java/de/mud/terminal/Precomposer.java
new file mode 100644
index 0000000..edad64c
--- /dev/null
+++ b/app/src/main/java/de/mud/terminal/Precomposer.java
@@ -0,0 +1,1052 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2007 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package de.mud.terminal;
+
+/**
+ * @author Kenny Root
+ * This data was taken from xterm's precompose.c
+ */
+public class Precomposer {
+ public final static char precompositions[][] = {
+ { 0x226E, 0x003C, 0x0338},
+ { 0x2260, 0x003D, 0x0338},
+ { 0x226F, 0x003E, 0x0338},
+ { 0x00C0, 0x0041, 0x0300},
+ { 0x00C1, 0x0041, 0x0301},
+ { 0x00C2, 0x0041, 0x0302},
+ { 0x00C3, 0x0041, 0x0303},
+ { 0x0100, 0x0041, 0x0304},
+ { 0x0102, 0x0041, 0x0306},
+ { 0x0226, 0x0041, 0x0307},
+ { 0x00C4, 0x0041, 0x0308},
+ { 0x1EA2, 0x0041, 0x0309},
+ { 0x00C5, 0x0041, 0x030A},
+ { 0x01CD, 0x0041, 0x030C},
+ { 0x0200, 0x0041, 0x030F},
+ { 0x0202, 0x0041, 0x0311},
+ { 0x1EA0, 0x0041, 0x0323},
+ { 0x1E00, 0x0041, 0x0325},
+ { 0x0104, 0x0041, 0x0328},
+ { 0x1E02, 0x0042, 0x0307},
+ { 0x1E04, 0x0042, 0x0323},
+ { 0x1E06, 0x0042, 0x0331},
+ { 0x0106, 0x0043, 0x0301},
+ { 0x0108, 0x0043, 0x0302},
+ { 0x010A, 0x0043, 0x0307},
+ { 0x010C, 0x0043, 0x030C},
+ { 0x00C7, 0x0043, 0x0327},
+ { 0x1E0A, 0x0044, 0x0307},
+ { 0x010E, 0x0044, 0x030C},
+ { 0x1E0C, 0x0044, 0x0323},
+ { 0x1E10, 0x0044, 0x0327},
+ { 0x1E12, 0x0044, 0x032D},
+ { 0x1E0E, 0x0044, 0x0331},
+ { 0x00C8, 0x0045, 0x0300},
+ { 0x00C9, 0x0045, 0x0301},
+ { 0x00CA, 0x0045, 0x0302},
+ { 0x1EBC, 0x0045, 0x0303},
+ { 0x0112, 0x0045, 0x0304},
+ { 0x0114, 0x0045, 0x0306},
+ { 0x0116, 0x0045, 0x0307},
+ { 0x00CB, 0x0045, 0x0308},
+ { 0x1EBA, 0x0045, 0x0309},
+ { 0x011A, 0x0045, 0x030C},
+ { 0x0204, 0x0045, 0x030F},
+ { 0x0206, 0x0045, 0x0311},
+ { 0x1EB8, 0x0045, 0x0323},
+ { 0x0228, 0x0045, 0x0327},
+ { 0x0118, 0x0045, 0x0328},
+ { 0x1E18, 0x0045, 0x032D},
+ { 0x1E1A, 0x0045, 0x0330},
+ { 0x1E1E, 0x0046, 0x0307},
+ { 0x01F4, 0x0047, 0x0301},
+ { 0x011C, 0x0047, 0x0302},
+ { 0x1E20, 0x0047, 0x0304},
+ { 0x011E, 0x0047, 0x0306},
+ { 0x0120, 0x0047, 0x0307},
+ { 0x01E6, 0x0047, 0x030C},
+ { 0x0122, 0x0047, 0x0327},
+ { 0x0124, 0x0048, 0x0302},
+ { 0x1E22, 0x0048, 0x0307},
+ { 0x1E26, 0x0048, 0x0308},
+ { 0x021E, 0x0048, 0x030C},
+ { 0x1E24, 0x0048, 0x0323},
+ { 0x1E28, 0x0048, 0x0327},
+ { 0x1E2A, 0x0048, 0x032E},
+ { 0x00CC, 0x0049, 0x0300},
+ { 0x00CD, 0x0049, 0x0301},
+ { 0x00CE, 0x0049, 0x0302},
+ { 0x0128, 0x0049, 0x0303},
+ { 0x012A, 0x0049, 0x0304},
+ { 0x012C, 0x0049, 0x0306},
+ { 0x0130, 0x0049, 0x0307},
+ { 0x00CF, 0x0049, 0x0308},
+ { 0x1EC8, 0x0049, 0x0309},
+ { 0x01CF, 0x0049, 0x030C},
+ { 0x0208, 0x0049, 0x030F},
+ { 0x020A, 0x0049, 0x0311},
+ { 0x1ECA, 0x0049, 0x0323},
+ { 0x012E, 0x0049, 0x0328},
+ { 0x1E2C, 0x0049, 0x0330},
+ { 0x0134, 0x004A, 0x0302},
+ { 0x1E30, 0x004B, 0x0301},
+ { 0x01E8, 0x004B, 0x030C},
+ { 0x1E32, 0x004B, 0x0323},
+ { 0x0136, 0x004B, 0x0327},
+ { 0x1E34, 0x004B, 0x0331},
+ { 0x0139, 0x004C, 0x0301},
+ { 0x013D, 0x004C, 0x030C},
+ { 0x1E36, 0x004C, 0x0323},
+ { 0x013B, 0x004C, 0x0327},
+ { 0x1E3C, 0x004C, 0x032D},
+ { 0x1E3A, 0x004C, 0x0331},
+ { 0x1E3E, 0x004D, 0x0301},
+ { 0x1E40, 0x004D, 0x0307},
+ { 0x1E42, 0x004D, 0x0323},
+ { 0x01F8, 0x004E, 0x0300},
+ { 0x0143, 0x004E, 0x0301},
+ { 0x00D1, 0x004E, 0x0303},
+ { 0x1E44, 0x004E, 0x0307},
+ { 0x0147, 0x004E, 0x030C},
+ { 0x1E46, 0x004E, 0x0323},
+ { 0x0145, 0x004E, 0x0327},
+ { 0x1E4A, 0x004E, 0x032D},
+ { 0x1E48, 0x004E, 0x0331},
+ { 0x00D2, 0x004F, 0x0300},
+ { 0x00D3, 0x004F, 0x0301},
+ { 0x00D4, 0x004F, 0x0302},
+ { 0x00D5, 0x004F, 0x0303},
+ { 0x014C, 0x004F, 0x0304},
+ { 0x014E, 0x004F, 0x0306},
+ { 0x022E, 0x004F, 0x0307},
+ { 0x00D6, 0x004F, 0x0308},
+ { 0x1ECE, 0x004F, 0x0309},
+ { 0x0150, 0x004F, 0x030B},
+ { 0x01D1, 0x004F, 0x030C},
+ { 0x020C, 0x004F, 0x030F},
+ { 0x020E, 0x004F, 0x0311},
+ { 0x01A0, 0x004F, 0x031B},
+ { 0x1ECC, 0x004F, 0x0323},
+ { 0x01EA, 0x004F, 0x0328},
+ { 0x1E54, 0x0050, 0x0301},
+ { 0x1E56, 0x0050, 0x0307},
+ { 0x0154, 0x0052, 0x0301},
+ { 0x1E58, 0x0052, 0x0307},
+ { 0x0158, 0x0052, 0x030C},
+ { 0x0210, 0x0052, 0x030F},
+ { 0x0212, 0x0052, 0x0311},
+ { 0x1E5A, 0x0052, 0x0323},
+ { 0x0156, 0x0052, 0x0327},
+ { 0x1E5E, 0x0052, 0x0331},
+ { 0x015A, 0x0053, 0x0301},
+ { 0x015C, 0x0053, 0x0302},
+ { 0x1E60, 0x0053, 0x0307},
+ { 0x0160, 0x0053, 0x030C},
+ { 0x1E62, 0x0053, 0x0323},
+ { 0x0218, 0x0053, 0x0326},
+ { 0x015E, 0x0053, 0x0327},
+ { 0x1E6A, 0x0054, 0x0307},
+ { 0x0164, 0x0054, 0x030C},
+ { 0x1E6C, 0x0054, 0x0323},
+ { 0x021A, 0x0054, 0x0326},
+ { 0x0162, 0x0054, 0x0327},
+ { 0x1E70, 0x0054, 0x032D},
+ { 0x1E6E, 0x0054, 0x0331},
+ { 0x00D9, 0x0055, 0x0300},
+ { 0x00DA, 0x0055, 0x0301},
+ { 0x00DB, 0x0055, 0x0302},
+ { 0x0168, 0x0055, 0x0303},
+ { 0x016A, 0x0055, 0x0304},
+ { 0x016C, 0x0055, 0x0306},
+ { 0x00DC, 0x0055, 0x0308},
+ { 0x1EE6, 0x0055, 0x0309},
+ { 0x016E, 0x0055, 0x030A},
+ { 0x0170, 0x0055, 0x030B},
+ { 0x01D3, 0x0055, 0x030C},
+ { 0x0214, 0x0055, 0x030F},
+ { 0x0216, 0x0055, 0x0311},
+ { 0x01AF, 0x0055, 0x031B},
+ { 0x1EE4, 0x0055, 0x0323},
+ { 0x1E72, 0x0055, 0x0324},
+ { 0x0172, 0x0055, 0x0328},
+ { 0x1E76, 0x0055, 0x032D},
+ { 0x1E74, 0x0055, 0x0330},
+ { 0x1E7C, 0x0056, 0x0303},
+ { 0x1E7E, 0x0056, 0x0323},
+ { 0x1E80, 0x0057, 0x0300},
+ { 0x1E82, 0x0057, 0x0301},
+ { 0x0174, 0x0057, 0x0302},
+ { 0x1E86, 0x0057, 0x0307},
+ { 0x1E84, 0x0057, 0x0308},
+ { 0x1E88, 0x0057, 0x0323},
+ { 0x1E8A, 0x0058, 0x0307},
+ { 0x1E8C, 0x0058, 0x0308},
+ { 0x1EF2, 0x0059, 0x0300},
+ { 0x00DD, 0x0059, 0x0301},
+ { 0x0176, 0x0059, 0x0302},
+ { 0x1EF8, 0x0059, 0x0303},
+ { 0x0232, 0x0059, 0x0304},
+ { 0x1E8E, 0x0059, 0x0307},
+ { 0x0178, 0x0059, 0x0308},
+ { 0x1EF6, 0x0059, 0x0309},
+ { 0x1EF4, 0x0059, 0x0323},
+ { 0x0179, 0x005A, 0x0301},
+ { 0x1E90, 0x005A, 0x0302},
+ { 0x017B, 0x005A, 0x0307},
+ { 0x017D, 0x005A, 0x030C},
+ { 0x1E92, 0x005A, 0x0323},
+ { 0x1E94, 0x005A, 0x0331},
+ { 0x00E0, 0x0061, 0x0300},
+ { 0x00E1, 0x0061, 0x0301},
+ { 0x00E2, 0x0061, 0x0302},
+ { 0x00E3, 0x0061, 0x0303},
+ { 0x0101, 0x0061, 0x0304},
+ { 0x0103, 0x0061, 0x0306},
+ { 0x0227, 0x0061, 0x0307},
+ { 0x00E4, 0x0061, 0x0308},
+ { 0x1EA3, 0x0061, 0x0309},
+ { 0x00E5, 0x0061, 0x030A},
+ { 0x01CE, 0x0061, 0x030C},
+ { 0x0201, 0x0061, 0x030F},
+ { 0x0203, 0x0061, 0x0311},
+ { 0x1EA1, 0x0061, 0x0323},
+ { 0x1E01, 0x0061, 0x0325},
+ { 0x0105, 0x0061, 0x0328},
+ { 0x1E03, 0x0062, 0x0307},
+ { 0x1E05, 0x0062, 0x0323},
+ { 0x1E07, 0x0062, 0x0331},
+ { 0x0107, 0x0063, 0x0301},
+ { 0x0109, 0x0063, 0x0302},
+ { 0x010B, 0x0063, 0x0307},
+ { 0x010D, 0x0063, 0x030C},
+ { 0x00E7, 0x0063, 0x0327},
+ { 0x1E0B, 0x0064, 0x0307},
+ { 0x010F, 0x0064, 0x030C},
+ { 0x1E0D, 0x0064, 0x0323},
+ { 0x1E11, 0x0064, 0x0327},
+ { 0x1E13, 0x0064, 0x032D},
+ { 0x1E0F, 0x0064, 0x0331},
+ { 0x00E8, 0x0065, 0x0300},
+ { 0x00E9, 0x0065, 0x0301},
+ { 0x00EA, 0x0065, 0x0302},
+ { 0x1EBD, 0x0065, 0x0303},
+ { 0x0113, 0x0065, 0x0304},
+ { 0x0115, 0x0065, 0x0306},
+ { 0x0117, 0x0065, 0x0307},
+ { 0x00EB, 0x0065, 0x0308},
+ { 0x1EBB, 0x0065, 0x0309},
+ { 0x011B, 0x0065, 0x030C},
+ { 0x0205, 0x0065, 0x030F},
+ { 0x0207, 0x0065, 0x0311},
+ { 0x1EB9, 0x0065, 0x0323},
+ { 0x0229, 0x0065, 0x0327},
+ { 0x0119, 0x0065, 0x0328},
+ { 0x1E19, 0x0065, 0x032D},
+ { 0x1E1B, 0x0065, 0x0330},
+ { 0x1E1F, 0x0066, 0x0307},
+ { 0x01F5, 0x0067, 0x0301},
+ { 0x011D, 0x0067, 0x0302},
+ { 0x1E21, 0x0067, 0x0304},
+ { 0x011F, 0x0067, 0x0306},
+ { 0x0121, 0x0067, 0x0307},
+ { 0x01E7, 0x0067, 0x030C},
+ { 0x0123, 0x0067, 0x0327},
+ { 0x0125, 0x0068, 0x0302},
+ { 0x1E23, 0x0068, 0x0307},
+ { 0x1E27, 0x0068, 0x0308},
+ { 0x021F, 0x0068, 0x030C},
+ { 0x1E25, 0x0068, 0x0323},
+ { 0x1E29, 0x0068, 0x0327},
+ { 0x1E2B, 0x0068, 0x032E},
+ { 0x1E96, 0x0068, 0x0331},
+ { 0x00EC, 0x0069, 0x0300},
+ { 0x00ED, 0x0069, 0x0301},
+ { 0x00EE, 0x0069, 0x0302},
+ { 0x0129, 0x0069, 0x0303},
+ { 0x012B, 0x0069, 0x0304},
+ { 0x012D, 0x0069, 0x0306},
+ { 0x00EF, 0x0069, 0x0308},
+ { 0x1EC9, 0x0069, 0x0309},
+ { 0x01D0, 0x0069, 0x030C},
+ { 0x0209, 0x0069, 0x030F},
+ { 0x020B, 0x0069, 0x0311},
+ { 0x1ECB, 0x0069, 0x0323},
+ { 0x012F, 0x0069, 0x0328},
+ { 0x1E2D, 0x0069, 0x0330},
+ { 0x0135, 0x006A, 0x0302},
+ { 0x01F0, 0x006A, 0x030C},
+ { 0x1E31, 0x006B, 0x0301},
+ { 0x01E9, 0x006B, 0x030C},
+ { 0x1E33, 0x006B, 0x0323},
+ { 0x0137, 0x006B, 0x0327},
+ { 0x1E35, 0x006B, 0x0331},
+ { 0x013A, 0x006C, 0x0301},
+ { 0x013E, 0x006C, 0x030C},
+ { 0x1E37, 0x006C, 0x0323},
+ { 0x013C, 0x006C, 0x0327},
+ { 0x1E3D, 0x006C, 0x032D},
+ { 0x1E3B, 0x006C, 0x0331},
+ { 0x1E3F, 0x006D, 0x0301},
+ { 0x1E41, 0x006D, 0x0307},
+ { 0x1E43, 0x006D, 0x0323},
+ { 0x01F9, 0x006E, 0x0300},
+ { 0x0144, 0x006E, 0x0301},
+ { 0x00F1, 0x006E, 0x0303},
+ { 0x1E45, 0x006E, 0x0307},
+ { 0x0148, 0x006E, 0x030C},
+ { 0x1E47, 0x006E, 0x0323},
+ { 0x0146, 0x006E, 0x0327},
+ { 0x1E4B, 0x006E, 0x032D},
+ { 0x1E49, 0x006E, 0x0331},
+ { 0x00F2, 0x006F, 0x0300},
+ { 0x00F3, 0x006F, 0x0301},
+ { 0x00F4, 0x006F, 0x0302},
+ { 0x00F5, 0x006F, 0x0303},
+ { 0x014D, 0x006F, 0x0304},
+ { 0x014F, 0x006F, 0x0306},
+ { 0x022F, 0x006F, 0x0307},
+ { 0x00F6, 0x006F, 0x0308},
+ { 0x1ECF, 0x006F, 0x0309},
+ { 0x0151, 0x006F, 0x030B},
+ { 0x01D2, 0x006F, 0x030C},
+ { 0x020D, 0x006F, 0x030F},
+ { 0x020F, 0x006F, 0x0311},
+ { 0x01A1, 0x006F, 0x031B},
+ { 0x1ECD, 0x006F, 0x0323},
+ { 0x01EB, 0x006F, 0x0328},
+ { 0x1E55, 0x0070, 0x0301},
+ { 0x1E57, 0x0070, 0x0307},
+ { 0x0155, 0x0072, 0x0301},
+ { 0x1E59, 0x0072, 0x0307},
+ { 0x0159, 0x0072, 0x030C},
+ { 0x0211, 0x0072, 0x030F},
+ { 0x0213, 0x0072, 0x0311},
+ { 0x1E5B, 0x0072, 0x0323},
+ { 0x0157, 0x0072, 0x0327},
+ { 0x1E5F, 0x0072, 0x0331},
+ { 0x015B, 0x0073, 0x0301},
+ { 0x015D, 0x0073, 0x0302},
+ { 0x1E61, 0x0073, 0x0307},
+ { 0x0161, 0x0073, 0x030C},
+ { 0x1E63, 0x0073, 0x0323},
+ { 0x0219, 0x0073, 0x0326},
+ { 0x015F, 0x0073, 0x0327},
+ { 0x1E6B, 0x0074, 0x0307},
+ { 0x1E97, 0x0074, 0x0308},
+ { 0x0165, 0x0074, 0x030C},
+ { 0x1E6D, 0x0074, 0x0323},
+ { 0x021B, 0x0074, 0x0326},
+ { 0x0163, 0x0074, 0x0327},
+ { 0x1E71, 0x0074, 0x032D},
+ { 0x1E6F, 0x0074, 0x0331},
+ { 0x00F9, 0x0075, 0x0300},
+ { 0x00FA, 0x0075, 0x0301},
+ { 0x00FB, 0x0075, 0x0302},
+ { 0x0169, 0x0075, 0x0303},
+ { 0x016B, 0x0075, 0x0304},
+ { 0x016D, 0x0075, 0x0306},
+ { 0x00FC, 0x0075, 0x0308},
+ { 0x1EE7, 0x0075, 0x0309},
+ { 0x016F, 0x0075, 0x030A},
+ { 0x0171, 0x0075, 0x030B},
+ { 0x01D4, 0x0075, 0x030C},
+ { 0x0215, 0x0075, 0x030F},
+ { 0x0217, 0x0075, 0x0311},
+ { 0x01B0, 0x0075, 0x031B},
+ { 0x1EE5, 0x0075, 0x0323},
+ { 0x1E73, 0x0075, 0x0324},
+ { 0x0173, 0x0075, 0x0328},
+ { 0x1E77, 0x0075, 0x032D},
+ { 0x1E75, 0x0075, 0x0330},
+ { 0x1E7D, 0x0076, 0x0303},
+ { 0x1E7F, 0x0076, 0x0323},
+ { 0x1E81, 0x0077, 0x0300},
+ { 0x1E83, 0x0077, 0x0301},
+ { 0x0175, 0x0077, 0x0302},
+ { 0x1E87, 0x0077, 0x0307},
+ { 0x1E85, 0x0077, 0x0308},
+ { 0x1E98, 0x0077, 0x030A},
+ { 0x1E89, 0x0077, 0x0323},
+ { 0x1E8B, 0x0078, 0x0307},
+ { 0x1E8D, 0x0078, 0x0308},
+ { 0x1EF3, 0x0079, 0x0300},
+ { 0x00FD, 0x0079, 0x0301},
+ { 0x0177, 0x0079, 0x0302},
+ { 0x1EF9, 0x0079, 0x0303},
+ { 0x0233, 0x0079, 0x0304},
+ { 0x1E8F, 0x0079, 0x0307},
+ { 0x00FF, 0x0079, 0x0308},
+ { 0x1EF7, 0x0079, 0x0309},
+ { 0x1E99, 0x0079, 0x030A},
+ { 0x1EF5, 0x0079, 0x0323},
+ { 0x017A, 0x007A, 0x0301},
+ { 0x1E91, 0x007A, 0x0302},
+ { 0x017C, 0x007A, 0x0307},
+ { 0x017E, 0x007A, 0x030C},
+ { 0x1E93, 0x007A, 0x0323},
+ { 0x1E95, 0x007A, 0x0331},
+ { 0x1FED, 0x00A8, 0x0300},
+ { 0x0385, 0x00A8, 0x0301},
+ { 0x1FC1, 0x00A8, 0x0342},
+ { 0x1EA6, 0x00C2, 0x0300},
+ { 0x1EA4, 0x00C2, 0x0301},
+ { 0x1EAA, 0x00C2, 0x0303},
+ { 0x1EA8, 0x00C2, 0x0309},
+ { 0x01DE, 0x00C4, 0x0304},
+ { 0x01FA, 0x00C5, 0x0301},
+ { 0x01FC, 0x00C6, 0x0301},
+ { 0x01E2, 0x00C6, 0x0304},
+ { 0x1E08, 0x00C7, 0x0301},
+ { 0x1EC0, 0x00CA, 0x0300},
+ { 0x1EBE, 0x00CA, 0x0301},
+ { 0x1EC4, 0x00CA, 0x0303},
+ { 0x1EC2, 0x00CA, 0x0309},
+ { 0x1E2E, 0x00CF, 0x0301},
+ { 0x1ED2, 0x00D4, 0x0300},
+ { 0x1ED0, 0x00D4, 0x0301},
+ { 0x1ED6, 0x00D4, 0x0303},
+ { 0x1ED4, 0x00D4, 0x0309},
+ { 0x1E4C, 0x00D5, 0x0301},
+ { 0x022C, 0x00D5, 0x0304},
+ { 0x1E4E, 0x00D5, 0x0308},
+ { 0x022A, 0x00D6, 0x0304},
+ { 0x01FE, 0x00D8, 0x0301},
+ { 0x01DB, 0x00DC, 0x0300},
+ { 0x01D7, 0x00DC, 0x0301},
+ { 0x01D5, 0x00DC, 0x0304},
+ { 0x01D9, 0x00DC, 0x030C},
+ { 0x1EA7, 0x00E2, 0x0300},
+ { 0x1EA5, 0x00E2, 0x0301},
+ { 0x1EAB, 0x00E2, 0x0303},
+ { 0x1EA9, 0x00E2, 0x0309},
+ { 0x01DF, 0x00E4, 0x0304},
+ { 0x01FB, 0x00E5, 0x0301},
+ { 0x01FD, 0x00E6, 0x0301},
+ { 0x01E3, 0x00E6, 0x0304},
+ { 0x1E09, 0x00E7, 0x0301},
+ { 0x1EC1, 0x00EA, 0x0300},
+ { 0x1EBF, 0x00EA, 0x0301},
+ { 0x1EC5, 0x00EA, 0x0303},
+ { 0x1EC3, 0x00EA, 0x0309},
+ { 0x1E2F, 0x00EF, 0x0301},
+ { 0x1ED3, 0x00F4, 0x0300},
+ { 0x1ED1, 0x00F4, 0x0301},
+ { 0x1ED7, 0x00F4, 0x0303},
+ { 0x1ED5, 0x00F4, 0x0309},
+ { 0x1E4D, 0x00F5, 0x0301},
+ { 0x022D, 0x00F5, 0x0304},
+ { 0x1E4F, 0x00F5, 0x0308},
+ { 0x022B, 0x00F6, 0x0304},
+ { 0x01FF, 0x00F8, 0x0301},
+ { 0x01DC, 0x00FC, 0x0300},
+ { 0x01D8, 0x00FC, 0x0301},
+ { 0x01D6, 0x00FC, 0x0304},
+ { 0x01DA, 0x00FC, 0x030C},
+ { 0x1EB0, 0x0102, 0x0300},
+ { 0x1EAE, 0x0102, 0x0301},
+ { 0x1EB4, 0x0102, 0x0303},
+ { 0x1EB2, 0x0102, 0x0309},
+ { 0x1EB1, 0x0103, 0x0300},
+ { 0x1EAF, 0x0103, 0x0301},
+ { 0x1EB5, 0x0103, 0x0303},
+ { 0x1EB3, 0x0103, 0x0309},
+ { 0x1E14, 0x0112, 0x0300},
+ { 0x1E16, 0x0112, 0x0301},
+ { 0x1E15, 0x0113, 0x0300},
+ { 0x1E17, 0x0113, 0x0301},
+ { 0x1E50, 0x014C, 0x0300},
+ { 0x1E52, 0x014C, 0x0301},
+ { 0x1E51, 0x014D, 0x0300},
+ { 0x1E53, 0x014D, 0x0301},
+ { 0x1E64, 0x015A, 0x0307},
+ { 0x1E65, 0x015B, 0x0307},
+ { 0x1E66, 0x0160, 0x0307},
+ { 0x1E67, 0x0161, 0x0307},
+ { 0x1E78, 0x0168, 0x0301},
+ { 0x1E79, 0x0169, 0x0301},
+ { 0x1E7A, 0x016A, 0x0308},
+ { 0x1E7B, 0x016B, 0x0308},
+ { 0x1E9B, 0x017F, 0x0307},
+ { 0x1EDC, 0x01A0, 0x0300},
+ { 0x1EDA, 0x01A0, 0x0301},
+ { 0x1EE0, 0x01A0, 0x0303},
+ { 0x1EDE, 0x01A0, 0x0309},
+ { 0x1EE2, 0x01A0, 0x0323},
+ { 0x1EDD, 0x01A1, 0x0300},
+ { 0x1EDB, 0x01A1, 0x0301},
+ { 0x1EE1, 0x01A1, 0x0303},
+ { 0x1EDF, 0x01A1, 0x0309},
+ { 0x1EE3, 0x01A1, 0x0323},
+ { 0x1EEA, 0x01AF, 0x0300},
+ { 0x1EE8, 0x01AF, 0x0301},
+ { 0x1EEE, 0x01AF, 0x0303},
+ { 0x1EEC, 0x01AF, 0x0309},
+ { 0x1EF0, 0x01AF, 0x0323},
+ { 0x1EEB, 0x01B0, 0x0300},
+ { 0x1EE9, 0x01B0, 0x0301},
+ { 0x1EEF, 0x01B0, 0x0303},
+ { 0x1EED, 0x01B0, 0x0309},
+ { 0x1EF1, 0x01B0, 0x0323},
+ { 0x01EE, 0x01B7, 0x030C},
+ { 0x01EC, 0x01EA, 0x0304},
+ { 0x01ED, 0x01EB, 0x0304},
+ { 0x01E0, 0x0226, 0x0304},
+ { 0x01E1, 0x0227, 0x0304},
+ { 0x1E1C, 0x0228, 0x0306},
+ { 0x1E1D, 0x0229, 0x0306},
+ { 0x0230, 0x022E, 0x0304},
+ { 0x0231, 0x022F, 0x0304},
+ { 0x01EF, 0x0292, 0x030C},
+ { 0x0344, 0x0308, 0x0301},
+ { 0x1FBA, 0x0391, 0x0300},
+ { 0x0386, 0x0391, 0x0301},
+ { 0x1FB9, 0x0391, 0x0304},
+ { 0x1FB8, 0x0391, 0x0306},
+ { 0x1F08, 0x0391, 0x0313},
+ { 0x1F09, 0x0391, 0x0314},
+ { 0x1FBC, 0x0391, 0x0345},
+ { 0x1FC8, 0x0395, 0x0300},
+ { 0x0388, 0x0395, 0x0301},
+ { 0x1F18, 0x0395, 0x0313},
+ { 0x1F19, 0x0395, 0x0314},
+ { 0x1FCA, 0x0397, 0x0300},
+ { 0x0389, 0x0397, 0x0301},
+ { 0x1F28, 0x0397, 0x0313},
+ { 0x1F29, 0x0397, 0x0314},
+ { 0x1FCC, 0x0397, 0x0345},
+ { 0x1FDA, 0x0399, 0x0300},
+ { 0x038A, 0x0399, 0x0301},
+ { 0x1FD9, 0x0399, 0x0304},
+ { 0x1FD8, 0x0399, 0x0306},
+ { 0x03AA, 0x0399, 0x0308},
+ { 0x1F38, 0x0399, 0x0313},
+ { 0x1F39, 0x0399, 0x0314},
+ { 0x1FF8, 0x039F, 0x0300},
+ { 0x038C, 0x039F, 0x0301},
+ { 0x1F48, 0x039F, 0x0313},
+ { 0x1F49, 0x039F, 0x0314},
+ { 0x1FEC, 0x03A1, 0x0314},
+ { 0x1FEA, 0x03A5, 0x0300},
+ { 0x038E, 0x03A5, 0x0301},
+ { 0x1FE9, 0x03A5, 0x0304},
+ { 0x1FE8, 0x03A5, 0x0306},
+ { 0x03AB, 0x03A5, 0x0308},
+ { 0x1F59, 0x03A5, 0x0314},
+ { 0x1FFA, 0x03A9, 0x0300},
+ { 0x038F, 0x03A9, 0x0301},
+ { 0x1F68, 0x03A9, 0x0313},
+ { 0x1F69, 0x03A9, 0x0314},
+ { 0x1FFC, 0x03A9, 0x0345},
+ { 0x1FB4, 0x03AC, 0x0345},
+ { 0x1FC4, 0x03AE, 0x0345},
+ { 0x1F70, 0x03B1, 0x0300},
+ { 0x03AC, 0x03B1, 0x0301},
+ { 0x1FB1, 0x03B1, 0x0304},
+ { 0x1FB0, 0x03B1, 0x0306},
+ { 0x1F00, 0x03B1, 0x0313},
+ { 0x1F01, 0x03B1, 0x0314},
+ { 0x1FB6, 0x03B1, 0x0342},
+ { 0x1FB3, 0x03B1, 0x0345},
+ { 0x1F72, 0x03B5, 0x0300},
+ { 0x03AD, 0x03B5, 0x0301},
+ { 0x1F10, 0x03B5, 0x0313},
+ { 0x1F11, 0x03B5, 0x0314},
+ { 0x1F74, 0x03B7, 0x0300},
+ { 0x03AE, 0x03B7, 0x0301},
+ { 0x1F20, 0x03B7, 0x0313},
+ { 0x1F21, 0x03B7, 0x0314},
+ { 0x1FC6, 0x03B7, 0x0342},
+ { 0x1FC3, 0x03B7, 0x0345},
+ { 0x1F76, 0x03B9, 0x0300},
+ { 0x03AF, 0x03B9, 0x0301},
+ { 0x1FD1, 0x03B9, 0x0304},
+ { 0x1FD0, 0x03B9, 0x0306},
+ { 0x03CA, 0x03B9, 0x0308},
+ { 0x1F30, 0x03B9, 0x0313},
+ { 0x1F31, 0x03B9, 0x0314},
+ { 0x1FD6, 0x03B9, 0x0342},
+ { 0x1F78, 0x03BF, 0x0300},
+ { 0x03CC, 0x03BF, 0x0301},
+ { 0x1F40, 0x03BF, 0x0313},
+ { 0x1F41, 0x03BF, 0x0314},
+ { 0x1FE4, 0x03C1, 0x0313},
+ { 0x1FE5, 0x03C1, 0x0314},
+ { 0x1F7A, 0x03C5, 0x0300},
+ { 0x03CD, 0x03C5, 0x0301},
+ { 0x1FE1, 0x03C5, 0x0304},
+ { 0x1FE0, 0x03C5, 0x0306},
+ { 0x03CB, 0x03C5, 0x0308},
+ { 0x1F50, 0x03C5, 0x0313},
+ { 0x1F51, 0x03C5, 0x0314},
+ { 0x1FE6, 0x03C5, 0x0342},
+ { 0x1F7C, 0x03C9, 0x0300},
+ { 0x03CE, 0x03C9, 0x0301},
+ { 0x1F60, 0x03C9, 0x0313},
+ { 0x1F61, 0x03C9, 0x0314},
+ { 0x1FF6, 0x03C9, 0x0342},
+ { 0x1FF3, 0x03C9, 0x0345},
+ { 0x1FD2, 0x03CA, 0x0300},
+ { 0x0390, 0x03CA, 0x0301},
+ { 0x1FD7, 0x03CA, 0x0342},
+ { 0x1FE2, 0x03CB, 0x0300},
+ { 0x03B0, 0x03CB, 0x0301},
+ { 0x1FE7, 0x03CB, 0x0342},
+ { 0x1FF4, 0x03CE, 0x0345},
+ { 0x03D3, 0x03D2, 0x0301},
+ { 0x03D4, 0x03D2, 0x0308},
+ { 0x0407, 0x0406, 0x0308},
+ { 0x04D0, 0x0410, 0x0306},
+ { 0x04D2, 0x0410, 0x0308},
+ { 0x0403, 0x0413, 0x0301},
+ { 0x0400, 0x0415, 0x0300},
+ { 0x04D6, 0x0415, 0x0306},
+ { 0x0401, 0x0415, 0x0308},
+ { 0x04C1, 0x0416, 0x0306},
+ { 0x04DC, 0x0416, 0x0308},
+ { 0x04DE, 0x0417, 0x0308},
+ { 0x040D, 0x0418, 0x0300},
+ { 0x04E2, 0x0418, 0x0304},
+ { 0x0419, 0x0418, 0x0306},
+ { 0x04E4, 0x0418, 0x0308},
+ { 0x040C, 0x041A, 0x0301},
+ { 0x04E6, 0x041E, 0x0308},
+ { 0x04EE, 0x0423, 0x0304},
+ { 0x040E, 0x0423, 0x0306},
+ { 0x04F0, 0x0423, 0x0308},
+ { 0x04F2, 0x0423, 0x030B},
+ { 0x04F4, 0x0427, 0x0308},
+ { 0x04F8, 0x042B, 0x0308},
+ { 0x04EC, 0x042D, 0x0308},
+ { 0x04D1, 0x0430, 0x0306},
+ { 0x04D3, 0x0430, 0x0308},
+ { 0x0453, 0x0433, 0x0301},
+ { 0x0450, 0x0435, 0x0300},
+ { 0x04D7, 0x0435, 0x0306},
+ { 0x0451, 0x0435, 0x0308},
+ { 0x04C2, 0x0436, 0x0306},
+ { 0x04DD, 0x0436, 0x0308},
+ { 0x04DF, 0x0437, 0x0308},
+ { 0x045D, 0x0438, 0x0300},
+ { 0x04E3, 0x0438, 0x0304},
+ { 0x0439, 0x0438, 0x0306},
+ { 0x04E5, 0x0438, 0x0308},
+ { 0x045C, 0x043A, 0x0301},
+ { 0x04E7, 0x043E, 0x0308},
+ { 0x04EF, 0x0443, 0x0304},
+ { 0x045E, 0x0443, 0x0306},
+ { 0x04F1, 0x0443, 0x0308},
+ { 0x04F3, 0x0443, 0x030B},
+ { 0x04F5, 0x0447, 0x0308},
+ { 0x04F9, 0x044B, 0x0308},
+ { 0x04ED, 0x044D, 0x0308},
+ { 0x0457, 0x0456, 0x0308},
+ { 0x0476, 0x0474, 0x030F},
+ { 0x0477, 0x0475, 0x030F},
+ { 0x04DA, 0x04D8, 0x0308},
+ { 0x04DB, 0x04D9, 0x0308},
+ { 0x04EA, 0x04E8, 0x0308},
+ { 0x04EB, 0x04E9, 0x0308},
+ { 0xFB2E, 0x05D0, 0x05B7},
+ { 0xFB2F, 0x05D0, 0x05B8},
+ { 0xFB30, 0x05D0, 0x05BC},
+ { 0xFB31, 0x05D1, 0x05BC},
+ { 0xFB4C, 0x05D1, 0x05BF},
+ { 0xFB32, 0x05D2, 0x05BC},
+ { 0xFB33, 0x05D3, 0x05BC},
+ { 0xFB34, 0x05D4, 0x05BC},
+ { 0xFB4B, 0x05D5, 0x05B9},
+ { 0xFB35, 0x05D5, 0x05BC},
+ { 0xFB36, 0x05D6, 0x05BC},
+ { 0xFB38, 0x05D8, 0x05BC},
+ { 0xFB1D, 0x05D9, 0x05B4},
+ { 0xFB39, 0x05D9, 0x05BC},
+ { 0xFB3A, 0x05DA, 0x05BC},
+ { 0xFB3B, 0x05DB, 0x05BC},
+ { 0xFB4D, 0x05DB, 0x05BF},
+ { 0xFB3C, 0x05DC, 0x05BC},
+ { 0xFB3E, 0x05DE, 0x05BC},
+ { 0xFB40, 0x05E0, 0x05BC},
+ { 0xFB41, 0x05E1, 0x05BC},
+ { 0xFB43, 0x05E3, 0x05BC},
+ { 0xFB44, 0x05E4, 0x05BC},
+ { 0xFB4E, 0x05E4, 0x05BF},
+ { 0xFB46, 0x05E6, 0x05BC},
+ { 0xFB47, 0x05E7, 0x05BC},
+ { 0xFB48, 0x05E8, 0x05BC},
+ { 0xFB49, 0x05E9, 0x05BC},
+ { 0xFB2A, 0x05E9, 0x05C1},
+ { 0xFB2B, 0x05E9, 0x05C2},
+ { 0xFB4A, 0x05EA, 0x05BC},
+ { 0xFB1F, 0x05F2, 0x05B7},
+ { 0x0622, 0x0627, 0x0653},
+ { 0x0623, 0x0627, 0x0654},
+ { 0x0625, 0x0627, 0x0655},
+ { 0x0624, 0x0648, 0x0654},
+ { 0x0626, 0x064A, 0x0654},
+ { 0x06C2, 0x06C1, 0x0654},
+ { 0x06D3, 0x06D2, 0x0654},
+ { 0x06C0, 0x06D5, 0x0654},
+ { 0x0958, 0x0915, 0x093C},
+ { 0x0959, 0x0916, 0x093C},
+ { 0x095A, 0x0917, 0x093C},
+ { 0x095B, 0x091C, 0x093C},
+ { 0x095C, 0x0921, 0x093C},
+ { 0x095D, 0x0922, 0x093C},
+ { 0x0929, 0x0928, 0x093C},
+ { 0x095E, 0x092B, 0x093C},
+ { 0x095F, 0x092F, 0x093C},
+ { 0x0931, 0x0930, 0x093C},
+ { 0x0934, 0x0933, 0x093C},
+ { 0x09DC, 0x09A1, 0x09BC},
+ { 0x09DD, 0x09A2, 0x09BC},
+ { 0x09DF, 0x09AF, 0x09BC},
+ { 0x09CB, 0x09C7, 0x09BE},
+ { 0x09CC, 0x09C7, 0x09D7},
+ { 0x0A59, 0x0A16, 0x0A3C},
+ { 0x0A5A, 0x0A17, 0x0A3C},
+ { 0x0A5B, 0x0A1C, 0x0A3C},
+ { 0x0A5E, 0x0A2B, 0x0A3C},
+ { 0x0A33, 0x0A32, 0x0A3C},
+ { 0x0A36, 0x0A38, 0x0A3C},
+ { 0x0B5C, 0x0B21, 0x0B3C},
+ { 0x0B5D, 0x0B22, 0x0B3C},
+ { 0x0B4B, 0x0B47, 0x0B3E},
+ { 0x0B48, 0x0B47, 0x0B56},
+ { 0x0B4C, 0x0B47, 0x0B57},
+ { 0x0B94, 0x0B92, 0x0BD7},
+ { 0x0BCA, 0x0BC6, 0x0BBE},
+ { 0x0BCC, 0x0BC6, 0x0BD7},
+ { 0x0BCB, 0x0BC7, 0x0BBE},
+ { 0x0C48, 0x0C46, 0x0C56},
+ { 0x0CC0, 0x0CBF, 0x0CD5},
+ { 0x0CCA, 0x0CC6, 0x0CC2},
+ { 0x0CC7, 0x0CC6, 0x0CD5},
+ { 0x0CC8, 0x0CC6, 0x0CD6},
+ { 0x0CCB, 0x0CCA, 0x0CD5},
+ { 0x0D4A, 0x0D46, 0x0D3E},
+ { 0x0D4C, 0x0D46, 0x0D57},
+ { 0x0D4B, 0x0D47, 0x0D3E},
+ { 0x0DDA, 0x0DD9, 0x0DCA},
+ { 0x0DDC, 0x0DD9, 0x0DCF},
+ { 0x0DDE, 0x0DD9, 0x0DDF},
+ { 0x0DDD, 0x0DDC, 0x0DCA},
+ { 0x0F69, 0x0F40, 0x0FB5},
+ { 0x0F43, 0x0F42, 0x0FB7},
+ { 0x0F4D, 0x0F4C, 0x0FB7},
+ { 0x0F52, 0x0F51, 0x0FB7},
+ { 0x0F57, 0x0F56, 0x0FB7},
+ { 0x0F5C, 0x0F5B, 0x0FB7},
+ { 0x0F73, 0x0F71, 0x0F72},
+ { 0x0F75, 0x0F71, 0x0F74},
+ { 0x0F81, 0x0F71, 0x0F80},
+ { 0x0FB9, 0x0F90, 0x0FB5},
+ { 0x0F93, 0x0F92, 0x0FB7},
+ { 0x0F9D, 0x0F9C, 0x0FB7},
+ { 0x0FA2, 0x0FA1, 0x0FB7},
+ { 0x0FA7, 0x0FA6, 0x0FB7},
+ { 0x0FAC, 0x0FAB, 0x0FB7},
+ { 0x0F76, 0x0FB2, 0x0F80},
+ { 0x0F78, 0x0FB3, 0x0F80},
+ { 0x1026, 0x1025, 0x102E},
+ { 0x1B06, 0x1B05, 0x1B35},
+ { 0x1B08, 0x1B07, 0x1B35},
+ { 0x1B0A, 0x1B09, 0x1B35},
+ { 0x1B0C, 0x1B0B, 0x1B35},
+ { 0x1B0E, 0x1B0D, 0x1B35},
+ { 0x1B12, 0x1B11, 0x1B35},
+ { 0x1B3B, 0x1B3A, 0x1B35},
+ { 0x1B3D, 0x1B3C, 0x1B35},
+ { 0x1B40, 0x1B3E, 0x1B35},
+ { 0x1B41, 0x1B3F, 0x1B35},
+ { 0x1B43, 0x1B42, 0x1B35},
+ { 0x1E38, 0x1E36, 0x0304},
+ { 0x1E39, 0x1E37, 0x0304},
+ { 0x1E5C, 0x1E5A, 0x0304},
+ { 0x1E5D, 0x1E5B, 0x0304},
+ { 0x1E68, 0x1E62, 0x0307},
+ { 0x1E69, 0x1E63, 0x0307},
+ { 0x1EAC, 0x1EA0, 0x0302},
+ { 0x1EB6, 0x1EA0, 0x0306},
+ { 0x1EAD, 0x1EA1, 0x0302},
+ { 0x1EB7, 0x1EA1, 0x0306},
+ { 0x1EC6, 0x1EB8, 0x0302},
+ { 0x1EC7, 0x1EB9, 0x0302},
+ { 0x1ED8, 0x1ECC, 0x0302},
+ { 0x1ED9, 0x1ECD, 0x0302},
+ { 0x1F02, 0x1F00, 0x0300},
+ { 0x1F04, 0x1F00, 0x0301},
+ { 0x1F06, 0x1F00, 0x0342},
+ { 0x1F80, 0x1F00, 0x0345},
+ { 0x1F03, 0x1F01, 0x0300},
+ { 0x1F05, 0x1F01, 0x0301},
+ { 0x1F07, 0x1F01, 0x0342},
+ { 0x1F81, 0x1F01, 0x0345},
+ { 0x1F82, 0x1F02, 0x0345},
+ { 0x1F83, 0x1F03, 0x0345},
+ { 0x1F84, 0x1F04, 0x0345},
+ { 0x1F85, 0x1F05, 0x0345},
+ { 0x1F86, 0x1F06, 0x0345},
+ { 0x1F87, 0x1F07, 0x0345},
+ { 0x1F0A, 0x1F08, 0x0300},
+ { 0x1F0C, 0x1F08, 0x0301},
+ { 0x1F0E, 0x1F08, 0x0342},
+ { 0x1F88, 0x1F08, 0x0345},
+ { 0x1F0B, 0x1F09, 0x0300},
+ { 0x1F0D, 0x1F09, 0x0301},
+ { 0x1F0F, 0x1F09, 0x0342},
+ { 0x1F89, 0x1F09, 0x0345},
+ { 0x1F8A, 0x1F0A, 0x0345},
+ { 0x1F8B, 0x1F0B, 0x0345},
+ { 0x1F8C, 0x1F0C, 0x0345},
+ { 0x1F8D, 0x1F0D, 0x0345},
+ { 0x1F8E, 0x1F0E, 0x0345},
+ { 0x1F8F, 0x1F0F, 0x0345},
+ { 0x1F12, 0x1F10, 0x0300},
+ { 0x1F14, 0x1F10, 0x0301},
+ { 0x1F13, 0x1F11, 0x0300},
+ { 0x1F15, 0x1F11, 0x0301},
+ { 0x1F1A, 0x1F18, 0x0300},
+ { 0x1F1C, 0x1F18, 0x0301},
+ { 0x1F1B, 0x1F19, 0x0300},
+ { 0x1F1D, 0x1F19, 0x0301},
+ { 0x1F22, 0x1F20, 0x0300},
+ { 0x1F24, 0x1F20, 0x0301},
+ { 0x1F26, 0x1F20, 0x0342},
+ { 0x1F90, 0x1F20, 0x0345},
+ { 0x1F23, 0x1F21, 0x0300},
+ { 0x1F25, 0x1F21, 0x0301},
+ { 0x1F27, 0x1F21, 0x0342},
+ { 0x1F91, 0x1F21, 0x0345},
+ { 0x1F92, 0x1F22, 0x0345},
+ { 0x1F93, 0x1F23, 0x0345},
+ { 0x1F94, 0x1F24, 0x0345},
+ { 0x1F95, 0x1F25, 0x0345},
+ { 0x1F96, 0x1F26, 0x0345},
+ { 0x1F97, 0x1F27, 0x0345},
+ { 0x1F2A, 0x1F28, 0x0300},
+ { 0x1F2C, 0x1F28, 0x0301},
+ { 0x1F2E, 0x1F28, 0x0342},
+ { 0x1F98, 0x1F28, 0x0345},
+ { 0x1F2B, 0x1F29, 0x0300},
+ { 0x1F2D, 0x1F29, 0x0301},
+ { 0x1F2F, 0x1F29, 0x0342},
+ { 0x1F99, 0x1F29, 0x0345},
+ { 0x1F9A, 0x1F2A, 0x0345},
+ { 0x1F9B, 0x1F2B, 0x0345},
+ { 0x1F9C, 0x1F2C, 0x0345},
+ { 0x1F9D, 0x1F2D, 0x0345},
+ { 0x1F9E, 0x1F2E, 0x0345},
+ { 0x1F9F, 0x1F2F, 0x0345},
+ { 0x1F32, 0x1F30, 0x0300},
+ { 0x1F34, 0x1F30, 0x0301},
+ { 0x1F36, 0x1F30, 0x0342},
+ { 0x1F33, 0x1F31, 0x0300},
+ { 0x1F35, 0x1F31, 0x0301},
+ { 0x1F37, 0x1F31, 0x0342},
+ { 0x1F3A, 0x1F38, 0x0300},
+ { 0x1F3C, 0x1F38, 0x0301},
+ { 0x1F3E, 0x1F38, 0x0342},
+ { 0x1F3B, 0x1F39, 0x0300},
+ { 0x1F3D, 0x1F39, 0x0301},
+ { 0x1F3F, 0x1F39, 0x0342},
+ { 0x1F42, 0x1F40, 0x0300},
+ { 0x1F44, 0x1F40, 0x0301},
+ { 0x1F43, 0x1F41, 0x0300},
+ { 0x1F45, 0x1F41, 0x0301},
+ { 0x1F4A, 0x1F48, 0x0300},
+ { 0x1F4C, 0x1F48, 0x0301},
+ { 0x1F4B, 0x1F49, 0x0300},
+ { 0x1F4D, 0x1F49, 0x0301},
+ { 0x1F52, 0x1F50, 0x0300},
+ { 0x1F54, 0x1F50, 0x0301},
+ { 0x1F56, 0x1F50, 0x0342},
+ { 0x1F53, 0x1F51, 0x0300},
+ { 0x1F55, 0x1F51, 0x0301},
+ { 0x1F57, 0x1F51, 0x0342},
+ { 0x1F5B, 0x1F59, 0x0300},
+ { 0x1F5D, 0x1F59, 0x0301},
+ { 0x1F5F, 0x1F59, 0x0342},
+ { 0x1F62, 0x1F60, 0x0300},
+ { 0x1F64, 0x1F60, 0x0301},
+ { 0x1F66, 0x1F60, 0x0342},
+ { 0x1FA0, 0x1F60, 0x0345},
+ { 0x1F63, 0x1F61, 0x0300},
+ { 0x1F65, 0x1F61, 0x0301},
+ { 0x1F67, 0x1F61, 0x0342},
+ { 0x1FA1, 0x1F61, 0x0345},
+ { 0x1FA2, 0x1F62, 0x0345},
+ { 0x1FA3, 0x1F63, 0x0345},
+ { 0x1FA4, 0x1F64, 0x0345},
+ { 0x1FA5, 0x1F65, 0x0345},
+ { 0x1FA6, 0x1F66, 0x0345},
+ { 0x1FA7, 0x1F67, 0x0345},
+ { 0x1F6A, 0x1F68, 0x0300},
+ { 0x1F6C, 0x1F68, 0x0301},
+ { 0x1F6E, 0x1F68, 0x0342},
+ { 0x1FA8, 0x1F68, 0x0345},
+ { 0x1F6B, 0x1F69, 0x0300},
+ { 0x1F6D, 0x1F69, 0x0301},
+ { 0x1F6F, 0x1F69, 0x0342},
+ { 0x1FA9, 0x1F69, 0x0345},
+ { 0x1FAA, 0x1F6A, 0x0345},
+ { 0x1FAB, 0x1F6B, 0x0345},
+ { 0x1FAC, 0x1F6C, 0x0345},
+ { 0x1FAD, 0x1F6D, 0x0345},
+ { 0x1FAE, 0x1F6E, 0x0345},
+ { 0x1FAF, 0x1F6F, 0x0345},
+ { 0x1FB2, 0x1F70, 0x0345},
+ { 0x1FC2, 0x1F74, 0x0345},
+ { 0x1FF2, 0x1F7C, 0x0345},
+ { 0x1FB7, 0x1FB6, 0x0345},
+ { 0x1FCD, 0x1FBF, 0x0300},
+ { 0x1FCE, 0x1FBF, 0x0301},
+ { 0x1FCF, 0x1FBF, 0x0342},
+ { 0x1FC7, 0x1FC6, 0x0345},
+ { 0x1FF7, 0x1FF6, 0x0345},
+ { 0x1FDD, 0x1FFE, 0x0300},
+ { 0x1FDE, 0x1FFE, 0x0301},
+ { 0x1FDF, 0x1FFE, 0x0342},
+ { 0x219A, 0x2190, 0x0338},
+ { 0x219B, 0x2192, 0x0338},
+ { 0x21AE, 0x2194, 0x0338},
+ { 0x21CD, 0x21D0, 0x0338},
+ { 0x21CF, 0x21D2, 0x0338},
+ { 0x21CE, 0x21D4, 0x0338},
+ { 0x2204, 0x2203, 0x0338},
+ { 0x2209, 0x2208, 0x0338},
+ { 0x220C, 0x220B, 0x0338},
+ { 0x2224, 0x2223, 0x0338},
+ { 0x2226, 0x2225, 0x0338},
+ { 0x2241, 0x223C, 0x0338},
+ { 0x2244, 0x2243, 0x0338},
+ { 0x2247, 0x2245, 0x0338},
+ { 0x2249, 0x2248, 0x0338},
+ { 0x226D, 0x224D, 0x0338},
+ { 0x2262, 0x2261, 0x0338},
+ { 0x2270, 0x2264, 0x0338},
+ { 0x2271, 0x2265, 0x0338},
+ { 0x2274, 0x2272, 0x0338},
+ { 0x2275, 0x2273, 0x0338},
+ { 0x2278, 0x2276, 0x0338},
+ { 0x2279, 0x2277, 0x0338},
+ { 0x2280, 0x227A, 0x0338},
+ { 0x2281, 0x227B, 0x0338},
+ { 0x22E0, 0x227C, 0x0338},
+ { 0x22E1, 0x227D, 0x0338},
+ { 0x2284, 0x2282, 0x0338},
+ { 0x2285, 0x2283, 0x0338},
+ { 0x2288, 0x2286, 0x0338},
+ { 0x2289, 0x2287, 0x0338},
+ { 0x22E2, 0x2291, 0x0338},
+ { 0x22E3, 0x2292, 0x0338},
+ { 0x22AC, 0x22A2, 0x0338},
+ { 0x22AD, 0x22A8, 0x0338},
+ { 0x22AE, 0x22A9, 0x0338},
+ { 0x22AF, 0x22AB, 0x0338},
+ { 0x22EA, 0x22B2, 0x0338},
+ { 0x22EB, 0x22B3, 0x0338},
+ { 0x22EC, 0x22B4, 0x0338},
+ { 0x22ED, 0x22B5, 0x0338},
+ { 0x2ADC, 0x2ADD, 0x0338},
+ { 0x3094, 0x3046, 0x3099},
+ { 0x304C, 0x304B, 0x3099},
+ { 0x304E, 0x304D, 0x3099},
+ { 0x3050, 0x304F, 0x3099},
+ { 0x3052, 0x3051, 0x3099},
+ { 0x3054, 0x3053, 0x3099},
+ { 0x3056, 0x3055, 0x3099},
+ { 0x3058, 0x3057, 0x3099},
+ { 0x305A, 0x3059, 0x3099},
+ { 0x305C, 0x305B, 0x3099},
+ { 0x305E, 0x305D, 0x3099},
+ { 0x3060, 0x305F, 0x3099},
+ { 0x3062, 0x3061, 0x3099},
+ { 0x3065, 0x3064, 0x3099},
+ { 0x3067, 0x3066, 0x3099},
+ { 0x3069, 0x3068, 0x3099},
+ { 0x3070, 0x306F, 0x3099},
+ { 0x3071, 0x306F, 0x309A},
+ { 0x3073, 0x3072, 0x3099},
+ { 0x3074, 0x3072, 0x309A},
+ { 0x3076, 0x3075, 0x3099},
+ { 0x3077, 0x3075, 0x309A},
+ { 0x3079, 0x3078, 0x3099},
+ { 0x307A, 0x3078, 0x309A},
+ { 0x307C, 0x307B, 0x3099},
+ { 0x307D, 0x307B, 0x309A},
+ { 0x309E, 0x309D, 0x3099},
+ { 0x30F4, 0x30A6, 0x3099},
+ { 0x30AC, 0x30AB, 0x3099},
+ { 0x30AE, 0x30AD, 0x3099},
+ { 0x30B0, 0x30AF, 0x3099},
+ { 0x30B2, 0x30B1, 0x3099},
+ { 0x30B4, 0x30B3, 0x3099},
+ { 0x30B6, 0x30B5, 0x3099},
+ { 0x30B8, 0x30B7, 0x3099},
+ { 0x30BA, 0x30B9, 0x3099},
+ { 0x30BC, 0x30BB, 0x3099},
+ { 0x30BE, 0x30BD, 0x3099},
+ { 0x30C0, 0x30BF, 0x3099},
+ { 0x30C2, 0x30C1, 0x3099},
+ { 0x30C5, 0x30C4, 0x3099},
+ { 0x30C7, 0x30C6, 0x3099},
+ { 0x30C9, 0x30C8, 0x3099},
+ { 0x30D0, 0x30CF, 0x3099},
+ { 0x30D1, 0x30CF, 0x309A},
+ { 0x30D3, 0x30D2, 0x3099},
+ { 0x30D4, 0x30D2, 0x309A},
+ { 0x30D6, 0x30D5, 0x3099},
+ { 0x30D7, 0x30D5, 0x309A},
+ { 0x30D9, 0x30D8, 0x3099},
+ { 0x30DA, 0x30D8, 0x309A},
+ { 0x30DC, 0x30DB, 0x3099},
+ { 0x30DD, 0x30DB, 0x309A},
+ { 0x30F7, 0x30EF, 0x3099},
+ { 0x30F8, 0x30F0, 0x3099},
+ { 0x30F9, 0x30F1, 0x3099},
+ { 0x30FA, 0x30F2, 0x3099},
+ { 0x30FE, 0x30FD, 0x3099},
+ { 0xFB2C, 0xFB49, 0x05C1},
+ { 0xFB2D, 0xFB49, 0x05C2},
+ };
+
+ private static final int UNICODE_SHIFT = 21;
+
+ public static char precompose(char base, char comb) {
+ int min = 0;
+ int max = precompositions.length - 1;
+ int mid;
+
+ long sought = base << UNICODE_SHIFT | comb;
+ long that;
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ that = precompositions[mid][1] << UNICODE_SHIFT | precompositions[mid][2];
+ if (that < sought)
+ min = mid + 1;
+ else if (that > sought)
+ max = mid - 1;
+ else
+ return precompositions[mid][0];
+ }
+
+ // No match; return character without combiner
+ return base;
+ }
+}
diff --git a/app/src/main/java/de/mud/terminal/VDUBuffer.java b/app/src/main/java/de/mud/terminal/VDUBuffer.java
new file mode 100644
index 0000000..93e3ccf
--- /dev/null
+++ b/app/src/main/java/de/mud/terminal/VDUBuffer.java
@@ -0,0 +1,854 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Mei�ner 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.Arrays;
+
+/**
+ * Implementation of a Video Display Unit (VDU) buffer. This class contains
+ * all methods to manipulate the buffer that stores characters and their
+ * attributes as well as the regions displayed.
+ *
+ * @author Matthias L. Jugel, Marcus Meißner
+ * @version $Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $
+ */
+public class VDUBuffer {
+
+ /** The current version id tag */
+ public final static String ID = "$Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $";
+
+ /** Enable debug messages. */
+ public final static int debug = 0;
+
+ public int height, width; /* rows and columns */
+ public boolean[] update; /* contains the lines that need update */
+ public char[][] charArray; /* contains the characters */
+ public int[][] charAttributes; /* contains character attrs */
+ public int bufSize;
+ public int maxBufSize; /* buffer sizes */
+ public int screenBase; /* the actual screen start */
+ public int windowBase; /* where the start displaying */
+ public int scrollMarker; /* marks the last line inserted */
+
+ private int topMargin; /* top scroll margin */
+ private int bottomMargin; /* bottom scroll margin */
+
+ // cursor variables
+ protected boolean showcursor = true;
+ protected int cursorX, cursorY;
+
+ /** Scroll up when inserting a line. */
+ public final static boolean SCROLL_UP = false;
+ /** Scroll down when inserting a line. */
+ public final static boolean SCROLL_DOWN = true;
+
+ /* Attributes bit-field usage:
+ *
+ * 8421 8421 8421 8421 8421 8421 8421 8421
+ * |||| |||| |||| |||| |||| |||| |||| |||`- Bold
+ * |||| |||| |||| |||| |||| |||| |||| ||`-- Underline
+ * |||| |||| |||| |||| |||| |||| |||| |`--- Invert
+ * |||| |||| |||| |||| |||| |||| |||| `---- Low
+ * |||| |||| |||| |||| |||| |||| |||`------ Invisible
+ * |||| |||| |||| |||| ||`+-++++-+++------- Foreground Color
+ * |||| |||| |`++-++++-++------------------ Background Color
+ * |||| |||| `----------------------------- Fullwidth character
+ * `+++-++++------------------------------- Reserved for future use
+ */
+
+ /** Make character normal. */
+ public final static int NORMAL = 0x00;
+ /** Make character bold. */
+ public final static int BOLD = 0x01;
+ /** Underline character. */
+ public final static int UNDERLINE = 0x02;
+ /** Invert character. */
+ public final static int INVERT = 0x04;
+ /** Lower intensity character. */
+ public final static int LOW = 0x08;
+ /** Invisible character. */
+ public final static int INVISIBLE = 0x10;
+ /** Unicode full-width character (CJK, et al.) */
+ public final static int FULLWIDTH = 0x8000000;
+
+ /** how much to left shift the foreground color */
+ public final static int COLOR_FG_SHIFT = 5;
+ /** how much to left shift the background color */
+ public final static int COLOR_BG_SHIFT = 14;
+ /** color mask */
+ public final static int COLOR = 0x7fffe0; /* 0000 0000 0111 1111 1111 1111 1110 0000 */
+ /** foreground color mask */
+ public final static int COLOR_FG = 0x3fe0; /* 0000 0000 0000 0000 0011 1111 1110 0000 */
+ /** background color mask */
+ public final static int COLOR_BG = 0x7fc000; /* 0000 0000 0111 1111 1100 0000 0000 0000 */
+
+ /**
+ * Create a new video display buffer with the passed width and height in
+ * characters.
+ * @param width the length of the character lines
+ * @param height the amount of lines on the screen
+ */
+ public VDUBuffer(int width, int height) {
+ // set the display screen size
+ setScreenSize(width, height, false);
+ }
+
+ /**
+ * Create a standard video display buffer with 80 columns and 24 lines.
+ */
+ public VDUBuffer() {
+ this(80, 24);
+ }
+
+ /**
+ * Put a character on the screen with normal font and outline.
+ * The character previously on that position will be overwritten.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param ch the character to show on the screen
+ * @see #insertChar
+ * @see #deleteChar
+ * @see #redraw
+ */
+ public void putChar(int c, int l, char ch) {
+ putChar(c, l, ch, NORMAL);
+ }
+
+ /**
+ * Put a character on the screen with specific font and outline.
+ * The character previously on that position will be overwritten.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param ch the character to show on the screen
+ * @param attributes the character attributes
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #insertChar
+ * @see #deleteChar
+ * @see #redraw
+ */
+
+ public void putChar(int c, int l, char ch, int attributes) {
+ charArray[screenBase + l][c] = ch;
+ charAttributes[screenBase + l][c] = attributes;
+ if (l < height)
+ update[l + 1] = true;
+ }
+
+ /**
+ * Get the character at the specified position.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @see #putChar
+ */
+ public char getChar(int c, int l) {
+ return charArray[screenBase + l][c];
+ }
+
+ /**
+ * Get the attributes for the specified position.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @see #putChar
+ */
+ public int getAttributes(int c, int l) {
+ return charAttributes[screenBase + l][c];
+ }
+
+ /**
+ * Insert a character at a specific position on the screen.
+ * All character right to from this position will be moved one to the right.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param ch the character to insert
+ * @param attributes the character attributes
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #putChar
+ * @see #deleteChar
+ * @see #redraw
+ */
+ public void insertChar(int c, int l, char ch, int attributes) {
+ System.arraycopy(charArray[screenBase + l], c,
+ charArray[screenBase + l], c + 1, width - c - 1);
+ System.arraycopy(charAttributes[screenBase + l], c,
+ charAttributes[screenBase + l], c + 1, width - c - 1);
+ putChar(c, l, ch, attributes);
+ }
+
+ /**
+ * Delete a character at a given position on the screen.
+ * All characters right to the position will be moved one to the left.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @see #putChar
+ * @see #insertChar
+ * @see #redraw
+ */
+ public void deleteChar(int c, int l) {
+ if (c < width - 1) {
+ System.arraycopy(charArray[screenBase + l], c + 1,
+ charArray[screenBase + l], c, width - c - 1);
+ System.arraycopy(charAttributes[screenBase + l], c + 1,
+ charAttributes[screenBase + l], c, width - c - 1);
+ }
+ putChar(width - 1, l, (char) 0);
+ }
+
+ /**
+ * Put a String at a specific position. Any characters previously on that
+ * position will be overwritten. You need to call redraw() for screen update.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param s the string to be shown on the screen
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #putChar
+ * @see #insertLine
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void putString(int c, int l, String s) {
+ putString(c, l, s, NORMAL);
+ }
+
+ /**
+ * Put a String at a specific position giving all characters the same
+ * attributes. Any characters previously on that position will be
+ * overwritten. You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (line)
+ * @param s the string to be shown on the screen
+ * @param attributes character attributes
+ * @see #BOLD
+ * @see #UNDERLINE
+ * @see #INVERT
+ * @see #INVISIBLE
+ * @see #NORMAL
+ * @see #LOW
+ * @see #putChar
+ * @see #insertLine
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void putString(int c, int l, String s, int attributes) {
+ for (int i = 0; i < s.length() && c + i < width; i++)
+ putChar(c + i, l, s.charAt(i), attributes);
+ }
+
+ /**
+ * Insert a blank line at a specific position.
+ * The current line and all previous lines are scrolled one line up. The
+ * top line is lost. You need to call redraw() to update the screen.
+ * @param l the y-coordinate to insert the line
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void insertLine(int l) {
+ insertLine(l, 1, SCROLL_UP);
+ }
+
+ /**
+ * Insert blank lines at a specific position.
+ * You need to call redraw() to update the screen
+ * @param l the y-coordinate to insert the line
+ * @param n amount of lines to be inserted
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void insertLine(int l, int n) {
+ insertLine(l, n, SCROLL_UP);
+ }
+
+ /**
+ * Insert a blank line at a specific position. Scroll text according to
+ * the argument.
+ * You need to call redraw() to update the screen
+ * @param l the y-coordinate to insert the line
+ * @param scrollDown scroll down
+ * @see #deleteLine
+ * @see #SCROLL_UP
+ * @see #SCROLL_DOWN
+ * @see #redraw
+ */
+ public void insertLine(int l, boolean scrollDown) {
+ insertLine(l, 1, scrollDown);
+ }
+
+ /**
+ * Insert blank lines at a specific position.
+ * The current line and all previous lines are scrolled one line up. The
+ * top line is lost. You need to call redraw() to update the screen.
+ * @param l the y-coordinate to insert the line
+ * @param n number of lines to be inserted
+ * @param scrollDown scroll down
+ * @see #deleteLine
+ * @see #SCROLL_UP
+ * @see #SCROLL_DOWN
+ * @see #redraw
+ */
+ public synchronized void insertLine(int l, int n, boolean scrollDown) {
+ char cbuf[][] = null;
+ int abuf[][] = null;
+ int offset = 0;
+ int oldBase = screenBase;
+
+ int newScreenBase = screenBase;
+ int newWindowBase = windowBase;
+ int newBufSize = bufSize;
+
+ if (l > bottomMargin) /* We do not scroll below bottom margin (below the scrolling region). */
+ return;
+ int top = (l < topMargin ?
+ 0 : (l > bottomMargin ?
+ (bottomMargin + 1 < height ?
+ bottomMargin + 1 : height - 1) : topMargin));
+ int bottom = (l > bottomMargin ?
+ height - 1 : (l < topMargin ?
+ (topMargin > 0 ?
+ topMargin - 1 : 0) : bottomMargin));
+
+ // System.out.println("l is "+l+", top is "+top+", bottom is "+bottom+", bottomargin is "+bottomMargin+", topMargin is "+topMargin);
+
+ if (scrollDown) {
+ if (n > (bottom - top)) n = (bottom - top);
+ int size = bottom - l - (n - 1);
+ if(size < 0) size = 0;
+ cbuf = new char[size][];
+ abuf = new int[size][];
+
+ System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1));
+ System.arraycopy(charAttributes, oldBase + l,
+ abuf, 0, bottom - l - (n - 1));
+ System.arraycopy(cbuf, 0, charArray, oldBase + l + n,
+ bottom - l - (n - 1));
+ System.arraycopy(abuf, 0, charAttributes, oldBase + l + n,
+ bottom - l - (n - 1));
+ cbuf = charArray;
+ abuf = charAttributes;
+ } else {
+ try {
+ if (n > (bottom - top) + 1) n = (bottom - top) + 1;
+ if (bufSize < maxBufSize) {
+ if (bufSize + n > maxBufSize) {
+ offset = n - (maxBufSize - bufSize);
+ scrollMarker += offset;
+ newBufSize = maxBufSize;
+ newScreenBase = maxBufSize - height - 1;
+ newWindowBase = screenBase;
+ } else {
+ scrollMarker += n;
+ newScreenBase += n;
+ newWindowBase += n;
+ newBufSize += n;
+ }
+
+ cbuf = new char[newBufSize][];
+ abuf = new int[newBufSize][];
+ } else {
+ offset = n;
+ cbuf = charArray;
+ abuf = charAttributes;
+ }
+ // copy anything from the top of the buffer (+offset) to the new top
+ // up to the screenBase.
+ if (oldBase > 0) {
+ System.arraycopy(charArray, offset,
+ cbuf, 0,
+ oldBase - offset);
+ System.arraycopy(charAttributes, offset,
+ abuf, 0,
+ oldBase - offset);
+ }
+ // copy anything from the top of the screen (screenBase) up to the
+ // topMargin to the new screen
+ if (top > 0) {
+ System.arraycopy(charArray, oldBase,
+ cbuf, newScreenBase,
+ top);
+ System.arraycopy(charAttributes, oldBase,
+ abuf, newScreenBase,
+ top);
+ }
+ // copy anything from the topMargin up to the amount of lines inserted
+ // to the gap left over between scrollback buffer and screenBase
+ if (oldBase >= 0) {
+ System.arraycopy(charArray, oldBase + top,
+ cbuf, oldBase - offset,
+ n);
+ System.arraycopy(charAttributes, oldBase + top,
+ abuf, oldBase - offset,
+ n);
+ }
+ // copy anything from topMargin + n up to the line linserted to the
+ // topMargin
+ System.arraycopy(charArray, oldBase + top + n,
+ cbuf, newScreenBase + top,
+ l - top - (n - 1));
+ System.arraycopy(charAttributes, oldBase + top + n,
+ abuf, newScreenBase + top,
+ l - top - (n - 1));
+ //
+ // copy the all lines next to the inserted to the new buffer
+ if (l < height - 1) {
+ System.arraycopy(charArray, oldBase + l + 1,
+ cbuf, newScreenBase + l + 1,
+ (height - 1) - l);
+ System.arraycopy(charAttributes, oldBase + l + 1,
+ abuf, newScreenBase + l + 1,
+ (height - 1) - l);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // this should not happen anymore, but I will leave the code
+ // here in case something happens anyway. That code above is
+ // so complex I always have a hard time understanding what
+ // I did, even though there are comments
+ System.err.println("*** Error while scrolling up:");
+ System.err.println("--- BEGIN STACK TRACE ---");
+ e.printStackTrace();
+ System.err.println("--- END STACK TRACE ---");
+ System.err.println("bufSize=" + bufSize + ", maxBufSize=" + maxBufSize);
+ System.err.println("top=" + top + ", bottom=" + bottom);
+ System.err.println("n=" + n + ", l=" + l);
+ System.err.println("screenBase=" + screenBase + ", windowBase=" + windowBase);
+ System.err.println("newScreenBase=" + newScreenBase + ", newWindowBase=" + newWindowBase);
+ System.err.println("oldBase=" + oldBase);
+ System.err.println("size.width=" + width + ", size.height=" + height);
+ System.err.println("abuf.length=" + abuf.length + ", cbuf.length=" + cbuf.length);
+ System.err.println("*** done dumping debug information");
+ }
+ }
+
+ // this is a little helper to mark the scrolling
+ scrollMarker -= n;
+
+
+ for (int i = 0; i < n; i++) {
+ cbuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new char[width];
+ Arrays.fill(cbuf[(newScreenBase + l) + (scrollDown ? i : -i)], ' ');
+ abuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new int[width];
+ }
+
+ charArray = cbuf;
+ charAttributes = abuf;
+ screenBase = newScreenBase;
+ windowBase = newWindowBase;
+ bufSize = newBufSize;
+
+ if (scrollDown)
+ markLine(l, bottom - l + 1);
+ else
+ markLine(top, l - top + 1);
+
+ display.updateScrollBar();
+ }
+
+ /**
+ * Delete a line at a specific position. Subsequent lines will be scrolled
+ * up to fill the space and a blank line is inserted at the end of the
+ * screen.
+ * @param l the y-coordinate to insert the line
+ * @see #deleteLine
+ */
+ public void deleteLine(int l) {
+ int bottom = (l > bottomMargin ? height - 1:
+ (l < topMargin?topMargin:bottomMargin + 1));
+ int numRows = bottom - l - 1;
+
+ char[] discardedChars = charArray[screenBase + l];
+ int[] discardedAttributes = charAttributes[screenBase + l];
+
+ if (numRows > 0) {
+ System.arraycopy(charArray, screenBase + l + 1,
+ charArray, screenBase + l, numRows);
+ System.arraycopy(charAttributes, screenBase + l + 1,
+ charAttributes, screenBase + l, numRows);
+ }
+
+ int newBottomRow = screenBase + bottom - 1;
+ charArray[newBottomRow] = discardedChars;
+ charAttributes[newBottomRow] = discardedAttributes;
+ Arrays.fill(charArray[newBottomRow], ' ');
+ Arrays.fill(charAttributes[newBottomRow], 0);
+
+ markLine(l, bottom - l);
+ }
+
+ /**
+ * Delete a rectangular portion of the screen.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (row)
+ * @param w with of the area in characters
+ * @param h height of the area in characters
+ * @param curAttr attribute to fill
+ * @see #deleteChar
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void deleteArea(int c, int l, int w, int h, int curAttr) {
+ int endColumn = c + w;
+ int targetRow = screenBase + l;
+ for (int i = 0; i < h && l + i < height; i++) {
+ Arrays.fill(charAttributes[targetRow], c, endColumn, curAttr);
+ Arrays.fill(charArray[targetRow], c, endColumn, ' ');
+ targetRow++;
+ }
+ markLine(l, h);
+ }
+
+ /**
+ * Delete a rectangular portion of the screen.
+ * You need to call redraw() to update the screen.
+ * @param c x-coordinate (column)
+ * @param l y-coordinate (row)
+ * @param w with of the area in characters
+ * @param h height of the area in characters
+ * @see #deleteChar
+ * @see #deleteLine
+ * @see #redraw
+ */
+ public void deleteArea(int c, int l, int w, int h) {
+ deleteArea(c, l, w, h, 0);
+ }
+
+ /**
+ * Sets whether the cursor is visible or not.
+ * @param doshow
+ */
+ public void showCursor(boolean doshow) {
+ showcursor = doshow;
+ }
+
+ /**
+ * Check whether the cursor is currently visible.
+ * @return visibility
+ */
+ public boolean isCursorVisible() {
+ return showcursor;
+ }
+
+ /**
+ * Puts the cursor at the specified position.
+ * @param c column
+ * @param l line
+ */
+ public void setCursorPosition(int c, int l) {
+ cursorX = c;
+ cursorY = l;
+ }
+
+ /**
+ * Get the current column of the cursor position.
+ */
+ public int getCursorColumn() {
+ return cursorX;
+ }
+
+ /**
+ * Get the current line of the cursor position.
+ */
+ public int getCursorRow() {
+ return cursorY;
+ }
+
+ /**
+ * Set the current window base. This allows to view the scrollback buffer.
+ * @param line the line where the screen window starts
+ * @see #setBufferSize
+ * @see #getBufferSize
+ */
+ public void setWindowBase(int line) {
+ if (line > screenBase)
+ line = screenBase;
+ else if (line < 0) line = 0;
+ windowBase = line;
+ update[0] = true;
+ redraw();
+ }
+
+ /**
+ * Get the current window base.
+ * @see #setWindowBase
+ */
+ public int getWindowBase() {
+ return windowBase;
+ }
+
+ /**
+ * Set the scroll margins simultaneously. If they're out of bounds, trim them.
+ * @param l1 line that is the top
+ * @param l2 line that is the bottom
+ */
+ public void setMargins(int l1, int l2) {
+ if (l1 > l2)
+ return;
+
+ if (l1 < 0)
+ l1 = 0;
+ if (l2 >= height)
+ l2 = height - 1;
+
+ topMargin = l1;
+ bottomMargin = l2;
+ }
+
+ /**
+ * Set the top scroll margin for the screen. If the current bottom margin
+ * is smaller it will become the top margin and the line will become the
+ * bottom margin.
+ * @param l line that is the margin
+ */
+ public void setTopMargin(int l) {
+ if (l > bottomMargin) {
+ topMargin = bottomMargin;
+ bottomMargin = l;
+ } else
+ topMargin = l;
+ if (topMargin < 0) topMargin = 0;
+ if (bottomMargin >= height) bottomMargin = height - 1;
+ }
+
+ /**
+ * Get the top scroll margin.
+ */
+ public int getTopMargin() {
+ return topMargin;
+ }
+
+ /**
+ * Set the bottom scroll margin for the screen. If the current top margin
+ * is bigger it will become the bottom margin and the line will become the
+ * top margin.
+ * @param l line that is the margin
+ */
+ public void setBottomMargin(int l) {
+ if (l < topMargin) {
+ bottomMargin = topMargin;
+ topMargin = l;
+ } else
+ bottomMargin = l;
+ if (topMargin < 0) topMargin = 0;
+ if (bottomMargin >= height) bottomMargin = height - 1;
+ }
+
+ /**
+ * Get the bottom scroll margin.
+ */
+ public int getBottomMargin() {
+ return bottomMargin;
+ }
+
+ /**
+ * Set scrollback buffer size.
+ * @param amount new size of the buffer
+ */
+ public void setBufferSize(int amount) {
+ if (amount < height) amount = height;
+ if (amount < maxBufSize) {
+ char cbuf[][] = new char[amount][width];
+ int abuf[][] = new int[amount][width];
+ int copyStart = bufSize - amount < 0 ? 0 : bufSize - amount;
+ int copyCount = bufSize - amount < 0 ? bufSize : amount;
+ if (charArray != null)
+ System.arraycopy(charArray, copyStart, cbuf, 0, copyCount);
+ if (charAttributes != null)
+ System.arraycopy(charAttributes, copyStart, abuf, 0, copyCount);
+ charArray = cbuf;
+ charAttributes = abuf;
+ bufSize = copyCount;
+ screenBase = bufSize - height;
+ windowBase = screenBase;
+ }
+ maxBufSize = amount;
+
+ update[0] = true;
+ redraw();
+ }
+
+ /**
+ * Retrieve current scrollback buffer size.
+ * @see #setBufferSize
+ */
+ public int getBufferSize() {
+ return bufSize;
+ }
+
+ /**
+ * Retrieve maximum buffer Size.
+ * @see #getBufferSize
+ */
+ public int getMaxBufferSize() {
+ return maxBufSize;
+ }
+
+ /**
+ * Change the size of the screen. This will include adjustment of the
+ * scrollback buffer.
+ * @param w of the screen
+ * @param h of the screen
+ */
+ public void setScreenSize(int w, int h, boolean broadcast) {
+ char cbuf[][];
+ int abuf[][];
+ int maxSize = bufSize;
+
+ if (w < 1 || h < 1) return;
+
+ if (debug > 0)
+ System.err.println("VDU: screen size [" + w + "," + h + "]");
+
+ if (h > maxBufSize)
+ maxBufSize = h;
+
+ if (h > bufSize) {
+ bufSize = h;
+ screenBase = 0;
+ windowBase = 0;
+ }
+
+ if (windowBase + h >= bufSize)
+ windowBase = bufSize - h;
+
+ if (screenBase + h >= bufSize)
+ screenBase = bufSize - h;
+
+
+ cbuf = new char[bufSize][w];
+ abuf = new int[bufSize][w];
+
+
+ for (int i = 0; i < bufSize; i++) {
+ Arrays.fill(cbuf[i], ' ');
+ }
+
+ if (bufSize < maxSize)
+ maxSize = bufSize;
+
+ int rowLength;
+ if (charArray != null && charAttributes != null) {
+ for (int i = 0; i < maxSize && charArray[i] != null; i++) {
+ rowLength = charArray[i].length;
+ System.arraycopy(charArray[i], 0, cbuf[i], 0,
+ w < rowLength ? w : rowLength);
+ System.arraycopy(charAttributes[i], 0, abuf[i], 0,
+ w < rowLength ? w : rowLength);
+ }
+ }
+
+ int C = getCursorColumn();
+ if (C < 0)
+ C = 0;
+ else if (C >= width)
+ C = width - 1;
+
+ int R = getCursorRow();
+ if (R < 0)
+ R = 0;
+ else if (R >= height)
+ R = height - 1;
+
+ setCursorPosition(C, R);
+
+ charArray = cbuf;
+ charAttributes = abuf;
+ width = w;
+ height = h;
+ topMargin = 0;
+ bottomMargin = h - 1;
+ update = new boolean[h + 1];
+ update[0] = true;
+ /* FIXME: ???
+ if(resizeStrategy == RESIZE_FONT)
+ setBounds(getBounds());
+ */
+ }
+
+ /**
+ * Get amount of rows on the screen.
+ */
+ public int getRows() {
+ return height;
+ }
+
+ /**
+ * Get amount of columns on the screen.
+ */
+ public int getColumns() {
+ return width;
+ }
+
+ /**
+ * Mark lines to be updated with redraw().
+ * @param l starting line
+ * @param n amount of lines to be updated
+ * @see #redraw
+ */
+ public void markLine(int l, int n) {
+ for (int i = 0; (i < n) && (l + i < height); i++)
+ update[l + i + 1] = true;
+ }
+
+// private static int checkBounds(int value, int lower, int upper) {
+// if (value < lower)
+// return lower;
+// else if (value > upper)
+// return upper;
+// else
+// return value;
+// }
+
+ /** a generic display that should redraw on demand */
+ protected VDUDisplay display;
+
+ public void setDisplay(VDUDisplay display) {
+ this.display = display;
+ }
+
+ /**
+ * Trigger a redraw on the display.
+ */
+ protected void redraw() {
+ if (display != null)
+ display.redraw();
+ }
+}
diff --git a/app/src/main/java/de/mud/terminal/VDUDisplay.java b/app/src/main/java/de/mud/terminal/VDUDisplay.java
new file mode 100644
index 0000000..bb4a7b8
--- /dev/null
+++ b/app/src/main/java/de/mud/terminal/VDUDisplay.java
@@ -0,0 +1,40 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 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;
+
+/**
+ * Generic display
+ */
+public interface VDUDisplay {
+ public void redraw();
+ public void updateScrollBar();
+
+ public void setVDUBuffer(VDUBuffer buffer);
+ public VDUBuffer getVDUBuffer();
+
+ public void setColor(int index, int red, int green, int blue);
+ public void resetColors();
+}
diff --git a/app/src/main/java/de/mud/terminal/VDUInput.java b/app/src/main/java/de/mud/terminal/VDUInput.java
new file mode 100644
index 0000000..43c88de
--- /dev/null
+++ b/app/src/main/java/de/mud/terminal/VDUInput.java
@@ -0,0 +1,90 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meißner 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;
+
+/**
+ * An interface for a terminal that accepts input from keyboard and mouse.
+ *
+ * @author Matthias L. Jugel, Marcus Meißner
+ * @version $Id: VDUInput.java 499 2005-09-29 08:24:54Z leo $
+ */
+public interface VDUInput {
+
+ public final static int KEY_CONTROL = 0x01;
+ public final static int KEY_SHIFT = 0x02;
+ public final static int KEY_ALT = 0x04;
+ public final static int KEY_ACTION = 0x08;
+
+
+
+ /**
+ * Direct access to writing data ...
+ * @param b
+ */
+ void write(byte b[]);
+
+ /**
+ * 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
+ */
+ void mousePressed(int x, int y, int modifiers);
+
+ /**
+ * Terminal is mouse-aware and requires the coordinates and button
+ * of the release.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ void mouseReleased(int x, int y, int modifiers);
+
+ /**
+ * Override the standard key codes used by the terminal emulation.
+ * @param codes a properties object containing key code definitions
+ */
+ void setKeyCodes(Properties codes);
+
+ /**
+ * main keytyping event handler...
+ * @param keyCode the key code
+ * @param keyChar the character represented by the key
+ * @param modifiers shift/alt/control modifiers
+ */
+ void keyPressed(int keyCode, char keyChar, int modifiers);
+
+ /**
+ * Handle key Typed events for the terminal, this will get
+ * all normal key types, but no shift/alt/control/numlock.
+ * @param keyCode the key code
+ * @param keyChar the character represented by the key
+ * @param modifiers shift/alt/control modifiers
+ */
+ void keyTyped(int keyCode, char keyChar, int modifiers);
+}
diff --git a/app/src/main/java/de/mud/terminal/vt320.java b/app/src/main/java/de/mud/terminal/vt320.java
new file mode 100644
index 0000000..73369af
--- /dev/null
+++ b/app/src/main/java/de/mud/terminal/vt320.java
@@ -0,0 +1,3032 @@
+/*
+ * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
+ *
+ * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved.
+ *
+ * Please visit http://javatelnet.org/ for updates and contact.
+ *
+ * --LICENSE NOTICE--
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * --LICENSE NOTICE--
+ *
+ */
+
+package de.mud.terminal;
+
+import android.text.AndroidCharacter;
+
+import java.util.Properties;
+
+/**
+ * Implementation of a VT terminal emulation plus ANSI compatible.
+ * <P>
+ * <B>Maintainer:</B> Marcus Meißner
+ *
+ * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $
+ * @author Matthias L. Jugel, Marcus Meißner
+ */
+public abstract class vt320 extends VDUBuffer implements VDUInput {
+
+ /** The 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) {
+ final byte width = fullwidths[i];
+ isWide = (width == AndroidCharacter.EAST_ASIAN_WIDTH_WIDE)
+ || (width == AndroidCharacter.EAST_ASIAN_WIDTH_FULL_WIDTH);
+ }
+ }
+ }
+ }
+
+ if (lastChar != -1)
+ putChar((char) lastChar, isWide, false);
+
+ setCursorPosition(C, R);
+ redraw();
+ }
+ }
+
+ protected void sendTelnetCommand(byte cmd) {
+
+ }
+
+ /**
+ * Sent the changed window size from the terminal to all listeners.
+ */
+ protected void setWindowSize(int c, int r) {
+ /* To be overridden by Terminal.java */
+ }
+
+ @Override
+public void setScreenSize(int c, int r, boolean broadcast) {
+ int oldrows = height;
+
+ if (debug>2) {
+ if (debugStr == null)
+ debugStr = new StringBuilder();
+
+ debugStr.append("setscreensize (")
+ .append(c)
+ .append(',')
+ .append(r)
+ .append(',')
+ .append(broadcast)
+ .append(')');
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ }
+
+ super.setScreenSize(c,r,false);
+
+ boolean cursorChanged = false;
+
+ // Don't let the cursor go off the screen.
+ if (C >= c) {
+ C = c - 1;
+ cursorChanged = true;
+ }
+
+ if (R >= r) {
+ R = r - 1;
+ cursorChanged = true;
+ }
+
+ if (cursorChanged) {
+ setCursorPosition(C, R);
+ redraw();
+ }
+
+ if (broadcast) {
+ setWindowSize(c, r); /* broadcast up */
+ }
+ }
+
+
+ /**
+ * Create a new vt320 terminal and intialize it with useful settings.
+ */
+ public vt320(int width, int height) {
+ super(width, height);
+
+ debugStr = new StringBuilder();
+
+ setVMS(false);
+ setIBMCharset(false);
+ setTerminalID("vt320");
+ setBufferSize(100);
+ //setBorder(2, false);
+
+ gx = new char[4];
+ reset();
+
+ /* top row of numpad */
+ PF1 = "\u001bOP";
+ PF2 = "\u001bOQ";
+ PF3 = "\u001bOR";
+ PF4 = "\u001bOS";
+
+ /* the 3x2 keyblock on PC keyboards */
+ Insert = new String[4];
+ Remove = new String[4];
+ KeyHome = new String[4];
+ KeyEnd = new String[4];
+ NextScn = new String[4];
+ PrevScn = new String[4];
+ Escape = new String[4];
+ BackSpace = new String[4];
+ TabKey = new String[4];
+ Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
+ Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
+ PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
+ NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
+ KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
+ KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
+ Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b";
+ if (vms) {
+ BackSpace[1] = "" + (char) 10; // VMS shift deletes word back
+ BackSpace[2] = "\u0018"; // VMS control deletes line back
+ BackSpace[0] = BackSpace[3] = "\u007f"; // VMS other is delete
+ } else {
+ //BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b";
+ // ConnectBot modifications.
+ BackSpace[0] = "\b";
+ BackSpace[1] = "\u007f";
+ BackSpace[2] = "\u001b[3~";
+ BackSpace[3] = "\u001b[2~";
+ }
+
+ /* some more VT100 keys */
+ Find = "\u001b[1~";
+ Select = "\u001b[4~";
+ Help = "\u001b[28~";
+ Do = "\u001b[29~";
+
+ FunctionKey = new String[21];
+ FunctionKey[0] = "";
+ FunctionKey[1] = PF1;
+ FunctionKey[2] = PF2;
+ FunctionKey[3] = PF3;
+ FunctionKey[4] = PF4;
+ /* following are defined differently for vt220 / vt132 ... */
+ FunctionKey[5] = "\u001b[15~";
+ FunctionKey[6] = "\u001b[17~";
+ FunctionKey[7] = "\u001b[18~";
+ FunctionKey[8] = "\u001b[19~";
+ FunctionKey[9] = "\u001b[20~";
+ FunctionKey[10] = "\u001b[21~";
+ FunctionKey[11] = "\u001b[23~";
+ FunctionKey[12] = "\u001b[24~";
+ FunctionKey[13] = "\u001b[25~";
+ FunctionKey[14] = "\u001b[26~";
+ FunctionKey[15] = Help;
+ FunctionKey[16] = Do;
+ FunctionKey[17] = "\u001b[31~";
+ FunctionKey[18] = "\u001b[32~";
+ FunctionKey[19] = "\u001b[33~";
+ FunctionKey[20] = "\u001b[34~";
+
+ FunctionKeyShift = new String[21];
+ FunctionKeyAlt = new String[21];
+ FunctionKeyCtrl = new String[21];
+
+ for (int i = 0; i < 20; i++) {
+ FunctionKeyShift[i] = "";
+ FunctionKeyAlt[i] = "";
+ FunctionKeyCtrl[i] = "";
+ }
+ FunctionKeyShift[15] = Find;
+ FunctionKeyShift[16] = Select;
+
+
+ TabKey[0] = "\u0009";
+ TabKey[1] = "\u001bOP\u0009";
+ TabKey[2] = TabKey[3] = "";
+
+ KeyUp = new String[4];
+ KeyUp[0] = "\u001b[A";
+ KeyDown = new String[4];
+ KeyDown[0] = "\u001b[B";
+ KeyRight = new String[4];
+ KeyRight[0] = "\u001b[C";
+ KeyLeft = new String[4];
+ KeyLeft[0] = "\u001b[D";
+ Numpad = new String[10];
+ Numpad[0] = "\u001bOp";
+ Numpad[1] = "\u001bOq";
+ Numpad[2] = "\u001bOr";
+ Numpad[3] = "\u001bOs";
+ Numpad[4] = "\u001bOt";
+ Numpad[5] = "\u001bOu";
+ Numpad[6] = "\u001bOv";
+ Numpad[7] = "\u001bOw";
+ Numpad[8] = "\u001bOx";
+ Numpad[9] = "\u001bOy";
+ KPMinus = PF4;
+ KPComma = "\u001bOl";
+ KPPeriod = "\u001bOn";
+ KPEnter = "\u001bOM";
+
+ NUMPlus = new String[4];
+ NUMPlus[0] = "+";
+ NUMDot = new String[4];
+ NUMDot[0] = ".";
+ }
+
+ public void setBackspace(int type) {
+ switch (type) {
+ case DELETE_IS_DEL:
+ BackSpace[0] = "\u007f";
+ BackSpace[1] = "\b";
+ break;
+ case DELETE_IS_BACKSPACE:
+ BackSpace[0] = "\b";
+ BackSpace[1] = "\u007f";
+ break;
+ }
+ }
+
+ /**
+ * Create a default vt320 terminal with 80 columns and 24 lines.
+ */
+ public vt320() {
+ this(80, 24);
+ }
+
+ /**
+ * Terminal is mouse-aware and requires (x,y) coordinates of
+ * on the terminal (character coordinates) and the button clicked.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ public void mousePressed(int x, int y, int modifiers) {
+ if (mouserpt == 0)
+ return;
+
+ int mods = modifiers;
+ mousebut = 3;
+ if ((mods & 16) == 16) mousebut = 0;
+ if ((mods & 8) == 8) mousebut = 1;
+ if ((mods & 4) == 4) mousebut = 2;
+
+ int mousecode;
+ if (mouserpt == 9) /* X10 Mouse */
+ mousecode = 0x20 | mousebut;
+ else /* normal xterm mouse reporting */
+ mousecode = mousebut | 0x20 | ((mods & 7) << 2);
+
+ byte b[] = new byte[6];
+
+ b[0] = 27;
+ b[1] = (byte) '[';
+ b[2] = (byte) 'M';
+ b[3] = (byte) mousecode;
+ b[4] = (byte) (0x20 + x + 1);
+ b[5] = (byte) (0x20 + y + 1);
+
+ write(b); // FIXME: writeSpecial here
+ }
+
+ /**
+ * Terminal is mouse-aware and requires the coordinates and button
+ * of the release.
+ * @param x
+ * @param y
+ * @param modifiers
+ */
+ public void mouseReleased(int x, int y, int modifiers) {
+ if (mouserpt == 0)
+ return;
+
+ /* problem is tht modifiers still have the released button set in them.
+ int mods = modifiers;
+ mousebut = 3;
+ if ((mods & 16)==16) mousebut=0;
+ if ((mods & 8)==8 ) mousebut=1;
+ if ((mods & 4)==4 ) mousebut=2;
+ */
+
+ int mousecode;
+ if (mouserpt == 9)
+ mousecode = 0x20 + mousebut; /* same as press? appears so. */
+ else
+ mousecode = '#';
+
+ byte b[] = new byte[6];
+ b[0] = 27;
+ b[1] = (byte) '[';
+ b[2] = (byte) 'M';
+ b[3] = (byte) mousecode;
+ b[4] = (byte) (0x20 + x + 1);
+ b[5] = (byte) (0x20 + y + 1);
+ write(b); // FIXME: writeSpecial here
+ mousebut = 0;
+ }
+
+
+ /** we should do localecho (passed from other modules). false is default */
+ private boolean localecho = false;
+
+ /**
+ * Enable or disable the local echo property of the terminal.
+ * @param echo true if the terminal should echo locally
+ */
+ public void setLocalEcho(boolean echo) {
+ localecho = echo;
+ }
+
+ /**
+ * Enable the VMS mode of the terminal to handle some things differently
+ * for VMS hosts.
+ * @param vms true for vms mode, false for normal mode
+ */
+ public void setVMS(boolean vms) {
+ this.vms = vms;
+ }
+
+ /**
+ * Enable the usage of the IBM character set used by some BBS's. Special
+ * graphical character are available in this mode.
+ * @param ibm true to use the ibm character set
+ */
+ public void setIBMCharset(boolean ibm) {
+ useibmcharset = ibm;
+ }
+
+ /**
+ * Override the standard key codes used by the terminal emulation.
+ * @param codes a properties object containing key code definitions
+ */
+ public void setKeyCodes(Properties codes) {
+ String res, prefixes[] = {"", "S", "C", "A"};
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ res = codes.getProperty("NUMPAD" + i);
+ if (res != null) Numpad[i] = unEscape(res);
+ }
+ for (i = 1; i < 20; i++) {
+ res = codes.getProperty("F" + i);
+ if (res != null) FunctionKey[i] = unEscape(res);
+ res = codes.getProperty("SF" + i);
+ if (res != null) FunctionKeyShift[i] = unEscape(res);
+ res = codes.getProperty("CF" + i);
+ if (res != null) FunctionKeyCtrl[i] = unEscape(res);
+ res = codes.getProperty("AF" + i);
+ if (res != null) FunctionKeyAlt[i] = unEscape(res);
+ }
+ for (i = 0; i < 4; i++) {
+ res = codes.getProperty(prefixes[i] + "PGUP");
+ if (res != null) PrevScn[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "PGDOWN");
+ if (res != null) NextScn[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "END");
+ if (res != null) KeyEnd[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "HOME");
+ if (res != null) KeyHome[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "INSERT");
+ if (res != null) Insert[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "REMOVE");
+ if (res != null) Remove[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "UP");
+ if (res != null) KeyUp[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "DOWN");
+ if (res != null) KeyDown[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "LEFT");
+ if (res != null) KeyLeft[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "RIGHT");
+ if (res != null) KeyRight[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "ESCAPE");
+ if (res != null) Escape[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "BACKSPACE");
+ if (res != null) BackSpace[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "TAB");
+ if (res != null) TabKey[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "NUMPLUS");
+ if (res != null) NUMPlus[i] = unEscape(res);
+ res = codes.getProperty(prefixes[i] + "NUMDECIMAL");
+ if (res != null) NUMDot[i] = unEscape(res);
+ }
+ }
+
+ /**
+ * Set the terminal id used to identify this terminal.
+ * @param terminalID the id string
+ */
+ public void setTerminalID(String terminalID) {
+ this.terminalID = terminalID;
+
+ if (terminalID.equals("scoansi")) {
+ FunctionKey[1] = "\u001b[M"; FunctionKey[2] = "\u001b[N";
+ FunctionKey[3] = "\u001b[O"; FunctionKey[4] = "\u001b[P";
+ FunctionKey[5] = "\u001b[Q"; FunctionKey[6] = "\u001b[R";
+ FunctionKey[7] = "\u001b[S"; FunctionKey[8] = "\u001b[T";
+ FunctionKey[9] = "\u001b[U"; FunctionKey[10] = "\u001b[V";
+ FunctionKey[11] = "\u001b[W"; FunctionKey[12] = "\u001b[X";
+ FunctionKey[13] = "\u001b[Y"; FunctionKey[14] = "?";
+ FunctionKey[15] = "\u001b[a"; FunctionKey[16] = "\u001b[b";
+ FunctionKey[17] = "\u001b[c"; FunctionKey[18] = "\u001b[d";
+ FunctionKey[19] = "\u001b[e"; FunctionKey[20] = "\u001b[f";
+ PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I";
+ NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G";
+ // more theoretically.
+ }
+ }
+
+ public void setAnswerBack(String ab) {
+ this.answerBack = unEscape(ab);
+ }
+
+ /**
+ * Get the terminal id used to identify this terminal.
+ */
+ public String getTerminalID() {
+ return terminalID;
+ }
+
+ /**
+ * A small conveniance method thar converts the string to a byte array
+ * for sending.
+ * @param s the string to be sent
+ */
+ private boolean write(String s, boolean doecho) {
+ if (debug > 2) {
+ debugStr.append("write(|")
+ .append(s)
+ .append("|,")
+ .append(doecho);
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ }
+ if (s == null) // aka the empty string.
+ return true;
+ /* NOTE: getBytes() honours some locale, it *CONVERTS* the string.
+ * However, we output only 7bit stuff towards the target, and *some*
+ * 8 bit control codes. We must not mess up the latter, so we do hand
+ * by hand copy.
+ */
+
+ byte arr[] = new byte[s.length()];
+ for (int i = 0; i < s.length(); i++) {
+ arr[i] = (byte) s.charAt(i);
+ }
+ write(arr);
+
+ if (doecho)
+ putString(s);
+ return true;
+ }
+
+ private boolean write(int s, boolean doecho) {
+ if (debug > 2) {
+ debugStr.append("write(|")
+ .append(s)
+ .append("|,")
+ .append(doecho);
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ }
+
+ write(s);
+
+ // TODO check if character is wide
+ if (doecho)
+ putChar((char)s, false, false);
+ return true;
+ }
+
+ private boolean write(String s) {
+ return write(s, localecho);
+ }
+
+ // ===================================================================
+ // the actual terminal emulation code comes here:
+ // ===================================================================
+
+ private String terminalID = "vt320";
+ private String answerBack = "Use Terminal.answerback to set ...\n";
+
+ // X - COLUMNS, Y - ROWS
+ int R,C;
+ int attributes = 0;
+
+ int Sc,Sr,Sa,Stm,Sbm;
+ char Sgr,Sgl;
+ char Sgx[];
+
+ int insertmode = 0;
+ int statusmode = 0;
+ boolean vt52mode = false;
+ boolean keypadmode = false; /* false - numeric, true - application */
+ boolean output8bit = false;
+ int normalcursor = 0;
+ boolean moveoutsidemargins = true;
+ boolean wraparound = true;
+ boolean sendcrlf = true;
+ boolean capslock = false;
+ boolean numlock = false;
+ int mouserpt = 0;
+ byte mousebut = 0;
+
+ boolean useibmcharset = false;
+
+ int lastwaslf = 0;
+ boolean usedcharsets = false;
+
+ private final static char ESC = 27;
+ private final static char IND = 132;
+ private final static char NEL = 133;
+ private final static char RI = 141;
+ private final static char SS2 = 142;
+ private final static char SS3 = 143;
+ private final static char DCS = 144;
+ private final static char HTS = 136;
+ private final static char CSI = 155;
+ private final static char OSC = 157;
+ private final static int TSTATE_DATA = 0;
+ private final static int TSTATE_ESC = 1; /* ESC */
+ private final static int TSTATE_CSI = 2; /* ESC [ */
+ private final static int TSTATE_DCS = 3; /* ESC P */
+ private final static int TSTATE_DCEQ = 4; /* ESC [? */
+ private final static int TSTATE_ESCSQUARE = 5; /* ESC # */
+ private final static int TSTATE_OSC = 6; /* ESC ] */
+ private final static int TSTATE_SETG0 = 7; /* ESC (? */
+ private final static int TSTATE_SETG1 = 8; /* ESC )? */
+ private final static int TSTATE_SETG2 = 9; /* ESC *? */
+ private final static int TSTATE_SETG3 = 10; /* ESC +? */
+ private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */
+ private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */
+ private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */
+ private final static int TSTATE_VT52X = 14;
+ private final static int TSTATE_VT52Y = 15;
+ private final static int TSTATE_CSI_TICKS = 16;
+ private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */
+ private final static int TSTATE_TITLE = 18; /* xterm title */
+
+ /* Keys we support */
+ public final static int KEY_PAUSE = 1;
+ public final static int KEY_F1 = 2;
+ public final static int KEY_F2 = 3;
+ public final static int KEY_F3 = 4;
+ public final static int KEY_F4 = 5;
+ public final static int KEY_F5 = 6;
+ public final static int KEY_F6 = 7;
+ public final static int KEY_F7 = 8;
+ public final static int KEY_F8 = 9;
+ public final static int KEY_F9 = 10;
+ public final static int KEY_F10 = 11;
+ public final static int KEY_F11 = 12;
+ public final static int KEY_F12 = 13;
+ public final static int KEY_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 = this.height; //statusline
+ int columns = this.width;
+ // byte msg[];
+
+// if (debug > 4) {
+// debugStr.append("putChar(")
+// .append(c)
+// .append(" [")
+// .append((int) c)
+// .append("]) at R=")
+// .append(R)
+// .append(" , C=")
+// .append(C)
+// .append(", columns=")
+// .append(columns)
+// .append(", rows=")
+// .append(rows);
+// debug(debugStr.toString());
+// debugStr.setLength(0);
+// }
+// markLine(R, 1);
+// if (c > 255) {
+// if (debug > 0)
+// debug("char > 255:" + (int) c);
+// //return;
+// }
+
+ switch (term_state) {
+ case TSTATE_DATA:
+ /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset.
+ * probably... but some BBS do anyway...
+ */
+ if (!useibmcharset) {
+ boolean doneflag = true;
+ switch (c) {
+ case OSC:
+ osc = "";
+ term_state = TSTATE_OSC;
+ break;
+ case RI:
+ if (R > getTopMargin())
+ R--;
+ else
+ insertLine(R, 1, SCROLL_DOWN);
+ if (debug > 1)
+ debug("RI");
+ break;
+ case IND:
+ if (debug > 2) {
+ debugStr.append("IND at ")
+ .append(R)
+ .append(", tm is ")
+ .append(getTopMargin())
+ .append(", bm is ")
+ .append(getBottomMargin());
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ }
+ if (R == getBottomMargin() || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ if (debug > 1)
+ debug("IND (at " + R + " )");
+ break;
+ case NEL:
+ if (R == getBottomMargin() || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ C = 0;
+ if (debug > 1)
+ debug("NEL (at " + R + " )");
+ break;
+ case HTS:
+ Tabs[C] = 1;
+ if (debug > 1)
+ debug("HTS");
+ break;
+ case DCS:
+ dcs = "";
+ term_state = TSTATE_DCS;
+ break;
+ default:
+ doneflag = false;
+ break;
+ }
+ if (doneflag) break;
+ }
+ switch (c) {
+ case SS3:
+ onegl = 3;
+ break;
+ case SS2:
+ onegl = 2;
+ break;
+ case CSI: // should be in the 8bit section, but some BBS use this
+ DCEvar = 0;
+ DCEvars[0] = 0;
+ DCEvars[1] = 0;
+ DCEvars[2] = 0;
+ DCEvars[3] = 0;
+ term_state = TSTATE_CSI;
+ break;
+ case ESC:
+ term_state = TSTATE_ESC;
+ lastwaslf = 0;
+ break;
+ case 5: /* ENQ */
+ write(answerBack, false);
+ break;
+ case 12:
+ /* FormFeed, Home for the BBS world */
+ deleteArea(0, 0, columns, rows, attributes);
+ C = R = 0;
+ break;
+ case '\b': /* 8 */
+ C--;
+ if (C < 0)
+ C = 0;
+ lastwaslf = 0;
+ break;
+ case '\t':
+ do {
+ // Don't overwrite or insert! TABS are not destructive, but movement!
+ C++;
+ } while (C < columns && (Tabs[C] == 0));
+ lastwaslf = 0;
+ break;
+ case '\r': // 13 CR
+ C = 0;
+ break;
+ case '\n': // 10 LF
+ if (debug > 3)
+ debug("R= " + R + ", bm " + getBottomMargin() + ", tm=" + getTopMargin() + ", rows=" + rows);
+ if (!vms) {
+ if (lastwaslf != 0 && lastwaslf != c) // Ray: I do not understand this logic.
+ break;
+ lastwaslf = c;
+ /*C = 0;*/
+ }
+ if (R == getBottomMargin() || R >= rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ break;
+ case 7:
+ beep();
+ break;
+ case '\016': /* SMACS , as */
+ /* ^N, Shift out - Put G1 into GL */
+ gl = 1;
+ usedcharsets = true;
+ break;
+ case '\017': /* RMACS , ae */
+ /* ^O, Shift in - Put G0 into GL */
+ gl = 0;
+ usedcharsets = true;
+ break;
+ default:
+ {
+ int thisgl = gl;
+
+ if (onegl >= 0) {
+ thisgl = onegl;
+ onegl = -1;
+ }
+ lastwaslf = 0;
+ if (c < 32) {
+ if (c != 0)
+ if (debug > 0)
+ debug("TSTATE_DATA char: " + ((int) c));
+ /*break; some BBS really want those characters, like hearst etc. */
+ if (c == 0) /* print 0 ... you bet */
+ break;
+ }
+ if (C >= columns) {
+ if (wraparound) {
+ int bot = rows;
+
+ // If we're in the scroll region, check against the bottom margin
+ if (R <= getBottomMargin() && R >= getTopMargin())
+ bot = getBottomMargin() + 1;
+
+ if (R < bot - 1)
+ R++;
+ else {
+ if (debug > 3) debug("scrolling due to wrap at " + R);
+ insertLine(R, 1, SCROLL_UP);
+ }
+ C = 0;
+ } else {
+ // cursor stays on last character.
+ C = columns - 1;
+ }
+ }
+
+ boolean mapped = false;
+
+ // Mapping if DEC Special is chosen charset
+ if (usedcharsets) {
+ if (c >= '\u0020' && c <= '\u007f') {
+ switch (gx[thisgl]) {
+ case '0':
+ // Remap SCOANSI line drawing to VT100 line drawing chars
+ // for our SCO using customers.
+ if (terminalID.equals("scoansi") || terminalID.equals("ansi")) {
+ for (int i = 0; i < scoansi_acs.length(); i += 2) {
+ if (c == scoansi_acs.charAt(i)) {
+ c = scoansi_acs.charAt(i + 1);
+ break;
+ }
+ }
+ }
+ if (c >= '\u005f' && c <= '\u007e') {
+ c = DECSPECIAL[(short) c - 0x5f];
+ mapped = true;
+ }
+ break;
+ case '<': // 'user preferred' is currently 'ISO Latin-1 suppl
+ c = (char) ((c & 0x7f) | 0x80);
+ mapped = true;
+ break;
+ case 'A':
+ case 'B': // Latin-1 , ASCII -> fall through
+ mapped = true;
+ break;
+ default:
+ debug("Unsupported GL mapping: " + gx[thisgl]);
+ break;
+ }
+ }
+ if (!mapped && (c >= '\u0080' && c <= '\u00ff')) {
+ switch (gx[gr]) {
+ case '0':
+ if (c >= '\u00df' && c <= '\u00fe') {
+ c = DECSPECIAL[c - '\u00df'];
+ mapped = true;
+ }
+ break;
+ case '<':
+ case 'A':
+ case 'B':
+ mapped = true;
+ break;
+ default:
+ debug("Unsupported GR mapping: " + gx[gr]);
+ break;
+ }
+ }
+ }
+ if (!mapped && useibmcharset)
+ c = map_cp850_unicode(c);
+
+ /*if(true || (statusmode == 0)) { */
+ if (isWide) {
+ if (C >= columns - 1) {
+ if (wraparound) {
+ int bot = rows;
+
+ // If we're in the scroll region, check against the bottom margin
+ if (R <= getBottomMargin() && R >= getTopMargin())
+ bot = getBottomMargin() + 1;
+
+ if (R < bot - 1)
+ R++;
+ else {
+ if (debug > 3) debug("scrolling due to wrap at " + R);
+ insertLine(R, 1, SCROLL_UP);
+ }
+ C = 0;
+ } else {
+ // cursor stays on last wide character.
+ C = columns - 2;
+ }
+ }
+ }
+
+ if (insertmode == 1) {
+ if (isWide) {
+ insertChar(C++, R, c, attributes | FULLWIDTH);
+ insertChar(C, R, ' ', attributes | FULLWIDTH);
+ } else
+ insertChar(C, R, c, attributes);
+ } else {
+ if (isWide) {
+ putChar(C++, R, c, attributes | FULLWIDTH);
+ putChar(C, R, ' ', attributes | FULLWIDTH);
+ } else
+ putChar(C, R, c, attributes);
+ }
+
+ /*
+ } else {
+ if (insertmode==1) {
+ insertChar(C, rows, c, attributes);
+ } else {
+ putChar(C, rows, c, attributes);
+ }
+ }
+ */
+ C++;
+ break;
+ }
+ } /* switch(c) */
+ break;
+ case TSTATE_OSC:
+ if ((c < 0x20) && (c != ESC)) {// NP - No printing character
+ handle_osc(osc);
+ term_state = TSTATE_DATA;
+ break;
+ }
+ //but check for vt102 ESC \
+ if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) {
+ handle_osc(osc);
+ term_state = TSTATE_DATA;
+ break;
+ }
+ osc = osc + c;
+ break;
+ case TSTATE_ESCSPACE:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */
+ output8bit = false;
+ break;
+ case 'G': /* S8C1T, Enable output of 8-bit control codes*/
+ output8bit = true;
+ break;
+ default:
+ debug("ESC <space> " + c + " unhandled.");
+ }
+ break;
+ case TSTATE_ESC:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case ' ':
+ term_state = TSTATE_ESCSPACE;
+ break;
+ case '#':
+ term_state = TSTATE_ESCSQUARE;
+ break;
+ case 'c':
+ /* Hard terminal reset */
+ reset();
+ break;
+ case '[':
+ DCEvar = 0;
+ DCEvars[0] = 0;
+ DCEvars[1] = 0;
+ DCEvars[2] = 0;
+ DCEvars[3] = 0;
+ term_state = TSTATE_CSI;
+ break;
+ case ']':
+ osc = "";
+ term_state = TSTATE_OSC;
+ break;
+ case 'P':
+ dcs = "";
+ term_state = TSTATE_DCS;
+ break;
+ case 'A': /* CUU */
+ R--;
+ if (R < 0) R = 0;
+ break;
+ case 'B': /* CUD */
+ R++;
+ if (R >= rows) R = rows - 1;
+ break;
+ case 'C':
+ C++;
+ if (C >= columns) C = columns - 1;
+ break;
+ case 'I': // RI
+ insertLine(R, 1, SCROLL_DOWN);
+ break;
+ case 'E': /* NEL */
+ if (R == getBottomMargin() || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ C = 0;
+ if (debug > 1)
+ debug("ESC E (at " + R + ")");
+ break;
+ case 'D': /* IND */
+ if (R == getBottomMargin() || R == rows - 1)
+ insertLine(R, 1, SCROLL_UP);
+ else
+ R++;
+ if (debug > 1)
+ debug("ESC D (at " + R + " )");
+ break;
+ case 'J': /* erase to end of screen */
+ if (R < rows - 1)
+ deleteArea(0, R + 1, columns, rows - R - 1, attributes);
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 'K':
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 'M': // RI
+ debug("ESC M : R is "+R+", tm is "+getTopMargin()+", bm is "+getBottomMargin());
+ if (R > getTopMargin()) { // just go up 1 line.
+ R--;
+ } else { // scroll down
+ insertLine(R, 1, SCROLL_DOWN);
+ }
+ /* else do nothing ; */
+ if (debug > 2)
+ debug("ESC M ");
+ break;
+ case 'H':
+ if (debug > 1)
+ debug("ESC H at " + C);
+ /* right border probably ...*/
+ if (C >= columns)
+ C = columns - 1;
+ Tabs[C] = 1;
+ break;
+ case 'N': // SS2
+ onegl = 2;
+ break;
+ case 'O': // SS3
+ onegl = 3;
+ break;
+ case '=':
+ /*application keypad*/
+ if (debug > 0)
+ debug("ESC =");
+ keypadmode = true;
+ break;
+ case '<': /* vt52 mode off */
+ vt52mode = false;
+ break;
+ case '>': /*normal keypad*/
+ if (debug > 0)
+ debug("ESC >");
+ keypadmode = false;
+ break;
+ case '7': /* DECSC: save cursor, attributes */
+ Sc = C;
+ Sr = R;
+ Sgl = gl;
+ Sgr = gr;
+ Sa = attributes;
+ Sgx = new char[4];
+ for (int i = 0; i < 4; i++) Sgx[i] = gx[i];
+ if (debug > 1)
+ debug("ESC 7");
+ break;
+ case '8': /* DECRC: restore cursor, attributes */
+ C = Sc;
+ R = Sr;
+ gl = Sgl;
+ gr = Sgr;
+ if (Sgx != null)
+ for (int i = 0; i < 4; i++) gx[i] = Sgx[i];
+ attributes = Sa;
+ if (debug > 1)
+ debug("ESC 8");
+ break;
+ case '(': /* Designate G0 Character set (ISO 2022) */
+ term_state = TSTATE_SETG0;
+ usedcharsets = true;
+ break;
+ case ')': /* Designate G1 character set (ISO 2022) */
+ term_state = TSTATE_SETG1;
+ usedcharsets = true;
+ break;
+ case '*': /* Designate G2 Character set (ISO 2022) */
+ term_state = TSTATE_SETG2;
+ usedcharsets = true;
+ break;
+ case '+': /* Designate G3 Character set (ISO 2022) */
+ term_state = TSTATE_SETG3;
+ usedcharsets = true;
+ break;
+ case '~': /* Locking Shift 1, right */
+ gr = 1;
+ usedcharsets = true;
+ break;
+ case 'n': /* Locking Shift 2 */
+ gl = 2;
+ usedcharsets = true;
+ break;
+ case '}': /* Locking Shift 2, right */
+ gr = 2;
+ usedcharsets = true;
+ break;
+ case 'o': /* Locking Shift 3 */
+ gl = 3;
+ usedcharsets = true;
+ break;
+ case '|': /* Locking Shift 3, right */
+ gr = 3;
+ usedcharsets = true;
+ break;
+ case 'Y': /* vt52 cursor address mode , next chars are x,y */
+ term_state = TSTATE_VT52Y;
+ break;
+ case '_':
+ term_state = TSTATE_TITLE;
+ break;
+ case '\\':
+ // TODO save title
+ term_state = TSTATE_DATA;
+ break;
+ default:
+ debug("ESC unknown letter: " + c + " (" + ((int) c) + ")");
+ break;
+ }
+ break;
+ case TSTATE_VT52X:
+ C = c - 37;
+ if (C < 0)
+ C = 0;
+ else if (C >= width)
+ C = width - 1;
+ term_state = TSTATE_VT52Y;
+ break;
+ case TSTATE_VT52Y:
+ R = c - 37;
+ if (R < 0)
+ R = 0;
+ else if (R >= height)
+ R = height - 1;
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG0:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<')
+ debug("ESC ( " + c + ": G0 char set? (" + ((int) c) + ")");
+ else {
+ if (debug > 2) debug("ESC ( : G0 char set (" + c + " " + ((int) c) + ")");
+ gx[0] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG1:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<') {
+ debug("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?");
+ } else {
+ if (debug > 2) debug("ESC ) :G1 char set (" + c + " " + ((int) c) + ")");
+ gx[1] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG2:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<')
+ debug("ESC*:G2 char set? (" + ((int) c) + ")");
+ else {
+ if (debug > 2) debug("ESC*:G2 char set (" + c + " " + ((int) c) + ")");
+ gx[2] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_SETG3:
+ if (c != '0' && c != 'A' && c != 'B' && c != '<')
+ debug("ESC+:G3 char set? (" + ((int) c) + ")");
+ else {
+ if (debug > 2) debug("ESC+:G3 char set (" + c + " " + ((int) c) + ")");
+ gx[3] = c;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_ESCSQUARE:
+ switch (c) {
+ case '8':
+ for (int i = 0; i < columns; i++)
+ for (int j = 0; j < rows; j++)
+ putChar(i, j, 'E', 0);
+ break;
+ default:
+ debug("ESC # " + c + " not supported.");
+ break;
+ }
+ term_state = TSTATE_DATA;
+ break;
+ case TSTATE_DCS:
+ if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) {
+ handle_dcs(dcs);
+ term_state = TSTATE_DATA;
+ break;
+ }
+ dcs = dcs + c;
+ break;
+
+ case TSTATE_DCEQ:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
+ term_state = TSTATE_DCEQ;
+ break;
+ case ';':
+ DCEvar++;
+ DCEvars[DCEvar] = 0;
+ term_state = TSTATE_DCEQ;
+ break;
+ case 's': // XTERM_SAVE missing!
+ if (true || debug > 1)
+ debug("ESC [ ? " + DCEvars[0] + " s unimplemented!");
+ break;
+ case 'r': // XTERM_RESTORE
+ if (true || debug > 1)
+ debug("ESC [ ? " + DCEvars[0] + " r");
+ /* DEC Mode reset */
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 3: /* 80 columns*/
+ setScreenSize(80, height, true);
+ break;
+ case 4: /* scrolling mode, smooth */
+ break;
+ case 5: /* light background */
+ break;
+ case 6: /* DECOM (Origin Mode) move inside margins. */
+ moveoutsidemargins = true;
+ break;
+ case 7: /* DECAWM: Autowrap Mode */
+ wraparound = false;
+ break;
+ case 12:/* local echo off */
+ break;
+ case 9: /* X10 mouse */
+ case 1000: /* xterm style mouse report on */
+ case 1001:
+ case 1002:
+ case 1003:
+ mouserpt = DCEvars[i];
+ break;
+ default:
+ debug("ESC [ ? " + DCEvars[0] + " r, unimplemented!");
+ }
+ }
+ break;
+ case 'h': // DECSET
+ if (debug > 0)
+ debug("ESC [ ? " + DCEvars[0] + " h");
+ /* DEC Mode set */
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 1: /* Application cursor keys */
+ KeyUp[0] = "\u001bOA";
+ KeyDown[0] = "\u001bOB";
+ KeyRight[0] = "\u001bOC";
+ KeyLeft[0] = "\u001bOD";
+ break;
+ case 2: /* DECANM */
+ vt52mode = false;
+ break;
+ case 3: /* 132 columns*/
+ setScreenSize(132, height, true);
+ break;
+ case 6: /* DECOM: move inside margins. */
+ moveoutsidemargins = false;
+ break;
+ case 7: /* DECAWM: Autowrap Mode */
+ wraparound = true;
+ break;
+ case 25: /* turn cursor on */
+ showCursor(true);
+ break;
+ case 9: /* X10 mouse */
+ case 1000: /* xterm style mouse report on */
+ case 1001:
+ case 1002:
+ case 1003:
+ mouserpt = DCEvars[i];
+ break;
+
+ /* unimplemented stuff, fall through */
+ /* 4 - scrolling mode, smooth */
+ /* 5 - light background */
+ /* 12 - local echo off */
+ /* 18 - DECPFF - Printer Form Feed Mode -> On */
+ /* 19 - DECPEX - Printer Extent Mode -> Screen */
+ default:
+ debug("ESC [ ? " + DCEvars[0] + " h, unsupported.");
+ break;
+ }
+ }
+ break;
+ case 'i': // DEC Printer Control, autoprint, echo screenchars to printer
+ // This is different to CSI i!
+ // Also: "Autoprint prints a final display line only when the
+ // cursor is moved off the line by an autowrap or LF, FF, or
+ // VT (otherwise do not print the line)."
+ switch (DCEvars[0]) {
+ case 1:
+ if (debug > 1)
+ debug("CSI ? 1 i : Print line containing cursor");
+ break;
+ case 4:
+ if (debug > 1)
+ debug("CSI ? 4 i : Start passthrough printing");
+ break;
+ case 5:
+ if (debug > 1)
+ debug("CSI ? 4 i : Stop passthrough printing");
+ break;
+ }
+ break;
+ case 'l': //DECRST
+ /* DEC Mode reset */
+ if (debug > 0)
+ debug("ESC [ ? " + DCEvars[0] + " l");
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 1: /* Application cursor keys */
+ KeyUp[0] = "\u001b[A";
+ KeyDown[0] = "\u001b[B";
+ KeyRight[0] = "\u001b[C";
+ KeyLeft[0] = "\u001b[D";
+ break;
+ case 2: /* DECANM */
+ vt52mode = true;
+ break;
+ case 3: /* 80 columns*/
+ setScreenSize(80, height, true);
+ break;
+ case 6: /* DECOM: move outside margins. */
+ moveoutsidemargins = true;
+ break;
+ case 7: /* DECAWM: Autowrap Mode OFF */
+ wraparound = false;
+ break;
+ case 25: /* turn cursor off */
+ showCursor(false);
+ break;
+ /* Unimplemented stuff: */
+ /* 4 - scrolling mode, jump */
+ /* 5 - dark background */
+ /* 7 - DECAWM - no wrap around mode */
+ /* 12 - local echo on */
+ /* 18 - DECPFF - Printer Form Feed Mode -> Off*/
+ /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */
+ case 9: /* X10 mouse */
+ case 1000: /* xterm style mouse report OFF */
+ case 1001:
+ case 1002:
+ case 1003:
+ mouserpt = 0;
+ break;
+ default:
+ debug("ESC [ ? " + DCEvars[0] + " l, unsupported.");
+ break;
+ }
+ }
+ break;
+ case 'n':
+ if (debug > 0)
+ debug("ESC [ ? " + DCEvars[0] + " n");
+ switch (DCEvars[0]) {
+ case 15:
+ /* printer? no printer. */
+ write((ESC) + "[?13n", false);
+ debug("ESC[5n");
+ break;
+ default:
+ debug("ESC [ ? " + DCEvars[0] + " n, unsupported.");
+ break;
+ }
+ break;
+ default:
+ debug("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported.");
+ break;
+ }
+ break;
+ case TSTATE_CSI_EX:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case ESC:
+ term_state = TSTATE_ESC;
+ break;
+ default:
+ debug("Unknown character ESC[! character is " + (int) c);
+ break;
+ }
+ break;
+ case TSTATE_CSI_TICKS:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case 'p':
+ debug("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]);
+ if (DCEvars[0] == 61) {
+ output8bit = false;
+ break;
+ }
+ if (DCEvars[1] == 1) {
+ output8bit = false;
+ } else {
+ output8bit = true; /* 0 or 2 */
+ }
+ break;
+ default:
+ debug("Unknown ESC [... \"" + c);
+ break;
+ }
+ break;
+ case TSTATE_CSI_EQUAL:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
+ term_state = TSTATE_CSI_EQUAL;
+ break;
+ case ';':
+ DCEvar++;
+ DCEvars[DCEvar] = 0;
+ term_state = TSTATE_CSI_EQUAL;
+ break;
+
+ case 'F': /* SCO ANSI foreground */
+ {
+ int newcolor;
+
+ debug("ESC [ = "+DCEvars[0]+" F");
+
+ attributes &= ~COLOR_FG;
+ newcolor = ((DCEvars[0] & 1) << 2) |
+ (DCEvars[0] & 2) |
+ ((DCEvars[0] & 4) >> 2) ;
+ attributes |= (newcolor+1) << COLOR_FG_SHIFT;
+
+ break;
+ }
+ case 'G': /* SCO ANSI background */
+ {
+ int newcolor;
+
+ debug("ESC [ = "+DCEvars[0]+" G");
+
+ attributes &= ~COLOR_BG;
+ newcolor = ((DCEvars[0] & 1) << 2) |
+ (DCEvars[0] & 2) |
+ ((DCEvars[0] & 4) >> 2) ;
+ attributes |= (newcolor+1) << COLOR_BG_SHIFT;
+ break;
+ }
+
+ default:
+ debugStr.append("Unknown ESC [ = ");
+ for (int i=0;i<=DCEvar;i++) {
+ debugStr.append(DCEvars[i])
+ .append(',');
+ }
+ debugStr.append(c);
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ break;
+ }
+ break;
+ case TSTATE_CSI_DOLLAR:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '}':
+ debug("Active Status Display now " + DCEvars[0]);
+ statusmode = DCEvars[0];
+ break;
+ /* bad documentation?
+ case '-':
+ debug("Set Status Display now "+DCEvars[0]);
+ break;
+ */
+ case '~':
+ debug("Status Line mode now " + DCEvars[0]);
+ break;
+ default:
+ debug("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]);
+ break;
+ }
+ break;
+ case TSTATE_CSI:
+ term_state = TSTATE_DATA;
+ switch (c) {
+ case '"':
+ term_state = TSTATE_CSI_TICKS;
+ break;
+ case '$':
+ term_state = TSTATE_CSI_DOLLAR;
+ break;
+ case '=':
+ term_state = TSTATE_CSI_EQUAL;
+ break;
+ case '!':
+ term_state = TSTATE_CSI_EX;
+ break;
+ case '?':
+ DCEvar = 0;
+ DCEvars[0] = 0;
+ term_state = TSTATE_DCEQ;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48;
+ term_state = TSTATE_CSI;
+ break;
+ case ';':
+ DCEvar++;
+ DCEvars[DCEvar] = 0;
+ term_state = TSTATE_CSI;
+ break;
+ case 'c':/* send primary device attributes */
+ /* send (ESC[?61c) */
+
+ String subcode = "";
+ if (terminalID.equals("vt320")) subcode = "63;";
+ if (terminalID.equals("vt220")) subcode = "62;";
+ if (terminalID.equals("vt100")) subcode = "61;";
+ write((ESC) + "[?" + subcode + "1;2c", false);
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " c");
+ break;
+ case 'q':
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " q");
+ break;
+ case 'g':
+ /* used for tabsets */
+ switch (DCEvars[0]) {
+ case 3:/* clear them */
+ Tabs = new byte[width];
+ break;
+ case 0:
+ Tabs[C] = 0;
+ break;
+ }
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " g");
+ break;
+ case 'h':
+ switch (DCEvars[0]) {
+ case 4:
+ insertmode = 1;
+ break;
+ case 20:
+ debug("Setting CRLF to TRUE");
+ sendcrlf = true;
+ break;
+ default:
+ debug("unsupported: ESC [ " + DCEvars[0] + " h");
+ break;
+ }
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " h");
+ break;
+ case 'i': // Printer Controller mode.
+ // "Transparent printing sends all output, except the CSI 4 i
+ // termination string, to the printer and not the screen,
+ // uses an 8-bit channel if no parity so NUL and DEL will be
+ // seen by the printer and by the termination recognizer code,
+ // and all translation and character set selections are
+ // bypassed."
+ switch (DCEvars[0]) {
+ case 0:
+ if (debug > 1)
+ debug("CSI 0 i: Print Screen, not implemented.");
+ break;
+ case 4:
+ if (debug > 1)
+ debug("CSI 4 i: Enable Transparent Printing, not implemented.");
+ break;
+ case 5:
+ if (debug > 1)
+ debug("CSI 4/5 i: Disable Transparent Printing, not implemented.");
+ break;
+ default:
+ debug("ESC [ " + DCEvars[0] + " i, unimplemented!");
+ }
+ break;
+ case 'l':
+ switch (DCEvars[0]) {
+ case 4:
+ insertmode = 0;
+ break;
+ case 20:
+ debug("Setting CRLF to FALSE");
+ sendcrlf = false;
+ break;
+ default:
+ debug("ESC [ " + DCEvars[0] + " l, unimplemented!");
+ break;
+ }
+ break;
+ case 'A': // CUU
+ {
+ int limit;
+ /* FIXME: xterm only cares about 0 and topmargin */
+ if (R >= getTopMargin()) {
+ limit = getTopMargin();
+ } else
+ limit = 0;
+ if (DCEvars[0] == 0)
+ R--;
+ else
+ R -= DCEvars[0];
+ if (R < limit)
+ R = limit;
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " A");
+ break;
+ }
+ case 'B': // CUD
+ /* cursor down n (1) times */
+ {
+ int limit;
+ if (R <= getBottomMargin()) {
+ limit = getBottomMargin();
+ } else
+ limit = rows - 1;
+ if (DCEvars[0] == 0)
+ R++;
+ else
+ R += DCEvars[0];
+ if (R > limit)
+ R = limit;
+ else {
+ if (debug > 2) debug("Not limited.");
+ }
+ if (debug > 2) debug("to: " + R);
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " B (at C=" + C + ")");
+ break;
+ }
+ case 'C':
+ if (DCEvars[0] == 0)
+ DCEvars[0] = 1;
+ while (DCEvars[0]-- > 0) {
+ C++;
+ }
+ if (C >= columns)
+ C = columns - 1;
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " C");
+ break;
+ case 'd': // CVA
+ R = DCEvars[0] - 1;
+ if (R < 0)
+ R = 0;
+ else if (R >= height)
+ R = height - 1;
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " d");
+ break;
+ case 'D':
+ if (DCEvars[0] == 0)
+ DCEvars[0] = 1;
+ while (DCEvars[0]-- > 0) {
+ C--;
+ }
+ if (C < 0) C = 0;
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " D");
+ break;
+ case 'r': // DECSTBM
+ if (DCEvar > 0) // Ray: Any argument is optional
+ {
+ R = DCEvars[1] - 1;
+ if (R < 0)
+ R = rows - 1;
+ else if (R >= rows) {
+ R = rows - 1;
+ }
+ } else
+ R = rows - 1;
+ int bot = R;
+ if (R >= DCEvars[0]) {
+ R = DCEvars[0] - 1;
+ if (R < 0)
+ R = 0;
+ }
+ setMargins(R, bot);
+ _SetCursor(0, 0);
+ if (debug > 1)
+ debug("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r");
+ break;
+ case 'G': /* CUP / cursor absolute column */
+ C = DCEvars[0];
+ if (C < 0)
+ C = 0;
+ else if (C >= width)
+ C = width - 1;
+ if (debug > 1) debug("ESC [ " + DCEvars[0] + " G");
+ break;
+ case 'H': /* CUP / cursor position */
+ /* gets 2 arguments */
+ _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1);
+ if (debug > 2) {
+ debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins " + moveoutsidemargins);
+ debug(" -> R now " + R + ", C now " + C);
+ }
+ break;
+ case 'f': /* move cursor 2 */
+ /* gets 2 arguments */
+ R = DCEvars[0] - 1;
+ C = DCEvars[1] - 1;
+ if (C < 0)
+ C = 0;
+ else if (C >= width)
+ C = width - 1;
+ if (R < 0)
+ R = 0;
+ else if (R >= height)
+ R = height - 1;
+ if (debug > 2)
+ debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f");
+ break;
+ case 'S': /* ind aka 'scroll forward' */
+ if (DCEvars[0] == 0)
+ insertLine(getBottomMargin(), SCROLL_UP);
+ else
+ insertLine(getBottomMargin(), DCEvars[0], SCROLL_UP);
+ break;
+ case 'L':
+ /* insert n lines */
+ if (DCEvars[0] == 0)
+ insertLine(R, SCROLL_DOWN);
+ else
+ insertLine(R, DCEvars[0], SCROLL_DOWN);
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")");
+ break;
+ case 'T': /* 'ri' aka scroll backward */
+ if (DCEvars[0] == 0)
+ insertLine(getTopMargin(), SCROLL_DOWN);
+ else
+ insertLine(getTopMargin(), DCEvars[0], SCROLL_DOWN);
+ break;
+ case 'M':
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R);
+ if (DCEvars[0] == 0)
+ deleteLine(R);
+ else
+ for (int i = 0; i < DCEvars[0]; i++)
+ deleteLine(R);
+ break;
+ case 'K':
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " K");
+ /* clear in line */
+ switch (DCEvars[0]) {
+ case 6: /* 97801 uses ESC[6K for delete to end of line */
+ case 0:/*clear to right*/
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 1:/*clear to the left, including this */
+ if (C > 0)
+ deleteArea(0, R, C + 1, 1, attributes);
+ break;
+ case 2:/*clear whole line */
+ deleteArea(0, R, columns, 1, attributes);
+ break;
+ }
+ break;
+ case 'J':
+ /* clear below current line */
+ switch (DCEvars[0]) {
+ case 0:
+ if (R < rows - 1)
+ deleteArea(0, R + 1, columns, rows - R - 1, attributes);
+ if (C < columns - 1)
+ deleteArea(C, R, columns - C, 1, attributes);
+ break;
+ case 1:
+ if (R > 0)
+ deleteArea(0, 0, columns, R, attributes);
+ if (C > 0)
+ deleteArea(0, R, C + 1, 1, attributes);// include up to and including current
+ break;
+ case 2:
+ deleteArea(0, 0, columns, rows, attributes);
+ break;
+ }
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " J");
+ break;
+ case '@':
+ if (DCEvars[0] == 0) DCEvars[0] = 1;
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " @");
+ for (int i = 0; i < DCEvars[0]; i++)
+ insertChar(C, R, ' ', attributes);
+ break;
+ case 'X':
+ {
+ int toerase = DCEvars[0];
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R);
+ if (toerase == 0)
+ toerase = 1;
+ if (toerase + C > columns)
+ toerase = columns - C;
+ deleteArea(C, R, toerase, 1, attributes);
+ // does not change cursor position
+ break;
+ }
+ case 'P':
+ if (debug > 1)
+ debug("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R);
+ if (DCEvars[0] == 0) DCEvars[0] = 1;
+ for (int i = 0; i < DCEvars[0]; i++)
+ deleteChar(C, R);
+ break;
+ case 'n':
+ switch (DCEvars[0]) {
+ case 5: /* malfunction? No malfunction. */
+ writeSpecial((ESC) + "[0n");
+ if (debug > 1)
+ debug("ESC[5n");
+ break;
+ case 6:
+ // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize
+ // FIXME check again.
+ // FIXME: but vttest thinks different???
+ writeSpecial((ESC) + "[" + R + ";" + C + "R");
+ if (debug > 1)
+ debug("ESC[6n");
+ break;
+ default:
+ if (debug > 0)
+ debug("ESC [ " + DCEvars[0] + " n??");
+ break;
+ }
+ break;
+ case 's': /* DECSC - save cursor */
+ Sc = C;
+ Sr = R;
+ Sa = attributes;
+ if (debug > 3)
+ debug("ESC[s");
+ break;
+ case 'u': /* DECRC - restore cursor */
+ C = Sc;
+ R = Sr;
+ attributes = Sa;
+ if (debug > 3)
+ debug("ESC[u");
+ break;
+ case 'm': /* attributes as color, bold , blink,*/
+ if (debug > 3)
+ debug("ESC [ ");
+ if (DCEvar == 0 && DCEvars[0] == 0)
+ attributes = 0;
+ for (int i = 0; i <= DCEvar; i++) {
+ switch (DCEvars[i]) {
+ case 0:
+ if (DCEvar > 0) {
+ if (terminalID.equals("scoansi")) {
+ attributes &= COLOR; /* Keeps color. Strange but true. */
+ } else {
+ attributes = 0;
+ }
+ }
+ break;
+ case 1:
+ attributes |= BOLD;
+ attributes &= ~LOW;
+ break;
+ case 2:
+ /* SCO color hack mode */
+ if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) {
+ int ncolor;
+ attributes &= ~(COLOR | BOLD);
+
+ ncolor = DCEvars[i + 1];
+ if ((ncolor & 8) == 8)
+ attributes |= BOLD;
+ ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
+ attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT;
+ ncolor = DCEvars[i + 2];
+ ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2);
+ attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT;
+ i += 2;
+ } else {
+ attributes |= LOW;
+ }
+ break;
+ case 3: /* italics */
+ attributes |= INVERT;
+ break;
+ case 4:
+ attributes |= UNDERLINE;
+ break;
+ case 7:
+ attributes |= INVERT;
+ break;
+ case 8:
+ attributes |= INVISIBLE;
+ break;
+ case 5: /* blink on */
+ break;
+ /* 10 - ANSI X3.64-1979, select primary font, don't display control
+ * chars, don't set bit 8 on output */
+ case 10:
+ gl = 0;
+ usedcharsets = true;
+ break;
+ /* 11 - ANSI X3.64-1979, select second alt. font, display control
+ * chars, set bit 8 on output */
+ case 11: /* SMACS , as */
+ case 12:
+ gl = 1;
+ usedcharsets = true;
+ break;
+ case 21: /* normal intensity */
+ attributes &= ~(LOW | BOLD);
+ break;
+ case 23: /* italics off */
+ attributes &= ~INVERT;
+ break;
+ case 25: /* blinking off */
+ break;
+ case 27:
+ attributes &= ~INVERT;
+ break;
+ case 28:
+ attributes &= ~INVISIBLE;
+ break;
+ case 24:
+ attributes &= ~UNDERLINE;
+ break;
+ case 22:
+ attributes &= ~BOLD;
+ break;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ attributes &= ~COLOR_FG;
+ attributes |= ((DCEvars[i] - 30) + 1)<< COLOR_FG_SHIFT;
+ break;
+ case 38:
+ if (DCEvars[i+1] == 5) {
+ attributes &= ~COLOR_FG;
+ attributes |= ((DCEvars[i + 2]) + 1) << COLOR_FG_SHIFT;
+ i += 2;
+ }
+ break;
+ case 39:
+ attributes &= ~COLOR_FG;
+ break;
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ attributes &= ~COLOR_BG;
+ attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT;
+ break;
+ case 48:
+ if (DCEvars[i+1] == 5) {
+ attributes &= ~COLOR_BG;
+ attributes |= (DCEvars[i + 2] + 1) << COLOR_BG_SHIFT;
+ i += 2;
+ }
+ break;
+ case 49:
+ attributes &= ~COLOR_BG;
+ break;
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ attributes &= ~COLOR_FG;
+ attributes |= ((DCEvars[i] - 82) + 1) << COLOR_FG_SHIFT;
+ break;
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ attributes &= ~COLOR_BG;
+ attributes |= ((DCEvars[i] - 92) + 1) << COLOR_BG_SHIFT;
+ break;
+
+ default:
+ debugStr.append("ESC [ ")
+ .append(DCEvars[i])
+ .append(" m unknown...");
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ break;
+ }
+ if (debug > 3) {
+ debugStr.append(DCEvars[i])
+ .append(';');
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ }
+ }
+ if (debug > 3) {
+ debugStr.append(" (attributes = ")
+ .append(attributes)
+ .append(")m");
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ }
+ break;
+ default:
+ debugStr.append("ESC [ unknown letter: ")
+ .append(c)
+ .append(" (")
+ .append((int)c)
+ .append(')');
+ debug(debugStr.toString());
+ debugStr.setLength(0);
+ break;
+ }
+ break;
+ case TSTATE_TITLE:
+ switch (c) {
+ case ESC:
+ term_state = TSTATE_ESC;
+ break;
+ default:
+ // TODO save title
+ break;
+ }
+ break;
+ default:
+ term_state = TSTATE_DATA;
+ break;
+ }
+
+ setCursorPosition(C, R);
+ }
+
+ /* hard reset the terminal */
+ public void reset() {
+ gx[0] = 'B';
+ gx[1] = 'B';
+ gx[2] = 'B';
+ gx[3] = 'B';
+
+ gl = 0; // default GL to G0
+ gr = 2; // default GR to G2
+
+ onegl = -1; // Single shift override
+
+ /* reset tabs */
+ int nw = width;
+ if (nw < 132) nw = 132;
+ Tabs = new byte[nw];
+ for (int i = 0; i < nw; i += 8) {
+ Tabs[i] = 1;
+ }
+
+ deleteArea(0, 0, width, height, attributes);
+ setMargins(0, height);
+ C = R = 0;
+ _SetCursor(0, 0);
+
+ if (display != null)
+ display.resetColors();
+
+ showCursor(true);
+ /*FIXME:*/
+ term_state = TSTATE_DATA;
+ }
+}