/* This file is part of "The Java Telnet Application".
*
* (c) Matthias L. Jugel, Marcus Mei�ner 1996-2002. All Rights Reserved.
* The file was changed by Radek Polak to work as midlet in MIDP 1.0
*
* This file has been modified by Karl von Randow for MidpSSH.
*
* 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 terminal;
import gui.Redrawable;
import java.io.IOException;
/**
* Implementation of a VT terminal emulation plus ANSI compatible.
* <P>
* <B>Maintainer: </B> Marcus Mei�ner
*
* @version $Id: VT320.java,v 1.1 2006/01/14 01:56:00 karl Exp $
* @author Matthias L. Jugel, Marcus Mei�ner
*/
public abstract class VT320 {
/* Virtual key codes. */
public static final int VK_ENTER = '\n';
public static final int VK_BACK_SPACE = '\b';
public static final int VK_TAB = '\t';
public static final int VK_CANCEL = 0x03;
public static final int VK_CLEAR = 0x0C;
public static final int VK_SHIFT = 0x10;
public static final int VK_CONTROL = 0x11;
public static final int VK_ALT = 0x12;
public static final int VK_PAUSE = 0x13;
public static final int VK_CAPS_LOCK = 0x14;
public static final int VK_ESCAPE = 0x1B;
public static final int VK_SPACE = 0x20;
public static final int VK_PAGE_UP = 0x21;
public static final int VK_PAGE_DOWN = 0x22;
public static final int VK_END = 0x23;
public static final int VK_HOME = 0x24;
/**
* Constant for the non-numpad <b>left </b> arrow key.
*
* @see #VK_KP_LEFT
*/
public static final int VK_LEFT = 0x25;
/**
* Constant for the non-numpad <b>up </b> arrow key.
*
* @see #VK_KP_UP
*/
public static final int VK_UP = 0x26;
/**
* Constant for the non-numpad <b>right </b> arrow key.
*
* @see #VK_KP_RIGHT
*/
public static final int VK_RIGHT = 0x27;
/**
* Constant for the non-numpad <b>down </b> arrow key.
*
* @see #VK_KP_DOWN
*/
public static final int VK_DOWN = 0x28;
public static final int VK_COMMA = 0x2C;
/**
* Constant for the "-" key.
*
* @since 1.2
*/
public static final int VK_MINUS = 0x2D;
public static final int VK_PERIOD = 0x2E;
public static final int VK_SLASH = 0x2F;
/** VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
public static final int VK_0 = 0x30;
public static final int VK_1 = 0x31;
public static final int VK_2 = 0x32;
public static final int VK_3 = 0x33;
public static final int VK_4 = 0x34;
public static final int VK_5 = 0x35;
public static final int VK_6 = 0x36;
public static final int VK_7 = 0x37;
public static final int VK_8 = 0x38;
public static final int VK_9 = 0x39;
public static final int VK_SEMICOLON = 0x3B;
public static final int VK_EQUALS = 0x3D;
/** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
public static final int VK_A = 0x41;
public static final int VK_B = 0x42;
public static final int VK_C = 0x43;
public static final int VK_D = 0x44;
public static final int VK_E = 0x45;
public static final int VK_F = 0x46;
public static final int VK_G = 0x47;
public static final int VK_H = 0x48;
public static final int VK_I = 0x49;
public static final int VK_J = 0x4A;
public static final int VK_K = 0x4B;
public static final int VK_L = 0x4C;
public static final int VK_M = 0x4D;
public static final int VK_N = 0x4E;
public static final int VK_O = 0x4F;
public static final int VK_P = 0x50;
public static final int VK_Q = 0x51;
public static final int VK_R = 0x52;
public static final int VK_S = 0x53;
public static final int VK_T = 0x54;
public static final int VK_U = 0x55;
public static final int VK_V = 0x56;
public static final int VK_W = 0x57;
public static final int VK_X = 0x58;
public static final int VK_Y = 0x59;
public static final int VK_Z = 0x5A;
public static final int VK_OPEN_BRACKET = 0x5B;
public static final int VK_BACK_SLASH = 0x5C;
public static final int VK_CLOSE_BRACKET = 0x5D;
public static final int VK_NUMPAD0 = 0x60;
public static final int VK_NUMPAD1 = 0x61;
public static final int VK_NUMPAD2 = 0x62;
public static final int VK_NUMPAD3 = 0x63;
public static final int VK_NUMPAD4 = 0x64;
public static final int VK_NUMPAD5 = 0x65;
public static final int VK_NUMPAD6 = 0x66;
public static final int VK_NUMPAD7 = 0x67;
public static final int VK_NUMPAD8 = 0x68;
public static final int VK_NUMPAD9 = 0x69;
public static final int VK_MULTIPLY = 0x6A;
public static final int VK_ADD = 0x6B;
/**
* This constant is obsolete, and is included only for backwards
* compatibility.
*
* @see VK_SEPARATOR
*/
public static final int VK_SEPARATER = 0x6C;
/**
* Constant for the Numpad Separator key.
*
* @since 1.4
*/
public static final int VK_SEPARATOR = VK_SEPARATER;
public static final int VK_SUBTRACT = 0x6D;
public static final int VK_DECIMAL = 0x6E;
public static final int VK_DIVIDE = 0x6F;
public static final int VK_DELETE = 0x7F; /* ASCII DEL */
public static final int VK_NUM_LOCK = 0x90;
public static final int VK_SCROLL_LOCK = 0x91;
/** Constant for the F1 function key. */
public static final int VK_F1 = 0x70;
/** Constant for the F2 function key. */
public static final int VK_F2 = 0x71;
/** Constant for the F3 function key. */
public static final int VK_F3 = 0x72;
/** Constant for the F4 function key. */
public static final int VK_F4 = 0x73;
/** Constant for the F5 function key. */
public static final int VK_F5 = 0x74;
/** Constant for the F6 function key. */
public static final int VK_F6 = 0x75;
/** Constant for the F7 function key. */
public static final int VK_F7 = 0x76;
/** Constant for the F8 function key. */
public static final int VK_F8 = 0x77;
/** Constant for the F9 function key. */
public static final int VK_F9 = 0x78;
/** Constant for the F10 function key. */
public static final int VK_F10 = 0x79;
/** Constant for the F11 function key. */
public static final int VK_F11 = 0x7A;
/** Constant for the F12 function key. */
public static final int VK_F12 = 0x7B;
public static final int VK_INSERT = 0x9B;
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;
/**
* Create a new vt320 terminal and intialize it with useful settings.
*/
public VT320( int width, int height ) {
setScreenSize( width, height );
setVMS( false );
setIBMCharset( false );
setBufferSize( height ); // was 100 scroll lines back b4
int nw = width;
if ( nw < 132 )
nw = 132; //catch possible later 132/80 resizes
Tabs = new byte[nw];
for ( int i = 0; i < nw; i += 8 ) {
Tabs[i] = 1;
}
/* top row of numpad */
PF1 = "\u001bOP";
PF2 = "\u001bOQ";
PF3 = "\u001bOR";
PF4 = "\u001bOS";
//#ifndef simplevt320
/* the 3x2 keyblock on PC keyboards */
Remove = new String[4];
//#endif
Insert = 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];
//#ifndef simplevt320
Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~";
//#endif
Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~";
KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H";
KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F";
PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~";
NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~";
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";
}
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~";
//#ifndef simplevt320
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~";
/* some more VT100 keys */
Find = "\u001b[1~";
Select = "\u001b[4~";
Help = "\u001b[28~";
Do = "\u001b[29~";
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;
//#endif
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";
//#ifndef simplevt320
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] = ".";
//#endif
}
/**
* Create a default vt320 terminal with 80 columns and 24 lines.
*/
public VT320() {
this( 80, 24 );
}
private int writeBufferIndex = 0;
private byte [] writeBuffer = new byte[128];
/**
* 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
*/
protected void write( byte[] b, int offset, int length ) {
if ( writeBufferIndex + length > writeBuffer.length ) {
if ( writeBufferIndex > 0 ) {
// First write out what we have and then try to add this to the buffer
flush();
write( b, offset, length );
}
else {
// Buffer is too small so write out in parts
System.arraycopy( b, offset, writeBuffer, 0, writeBuffer.length );
writeBufferIndex = writeBuffer.length;
flush();
write( b, offset + writeBuffer.length, length - writeBuffer.length );
}
}
else {
System.arraycopy( b, offset, writeBuffer, writeBufferIndex, length );
writeBufferIndex += length;
}
}
protected void flush() {
//putString( "\r\nWRITING " + writeBufferIndex + "=" + new String( writeBuffer, 0, writeBufferIndex ) + "\r\n" );
try {
sendData( writeBuffer, 0, writeBufferIndex );
}
catch ( java.io.IOException e ) {
//System.err.println( e );
}
writeBufferIndex = 0;
}
public abstract void sendData( byte[] b, int offset, int length ) throws IOException;
/**
* Play the beep sound ...
*/
public void beep() { /* do nothing by default */
}
/**
* Put string at current cursor position. Moves cursor according to the
* String. Does NOT wrap.
*
* @param s
* the string
*/
public void putString( String s ) {
int len = s.length();
if ( len > 0 ) {
markLine( R, 1 );
for ( int i = 0; i < len; i++ ) {
putChar( s.charAt( i ), false );
}
setCursorPosition( C, R );
redraw();
}
}
protected void sendTelnetCommand( byte cmd ) {
}
//#ifndef simplevt320
/**
* 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, 0, b.length ); // FIXME: writeSpecial here
flush();
}
/**
* 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, 0, b.length ); // FIXME: writeSpecial here
flush();
mousebut = 0;
}
//#endif
/** we should do localecho (passed from other modules). false is default */
public 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;
}
/**
* Set the terminal id used to identify this terminal.
*
* @param terminalID
* the id string
*/
public void setTerminalID( String terminalID ) {
this.terminalID = terminalID;
}
// public void setAnswerBack( String ab ) {
// this.answerBack = unEscape( ab );
// }
/**
* Get the terminal id used to identify this terminal.
*/
public String getTerminalID() {
return terminalID;
}
private byte [] stringConversionBuffer = new byte[10];
/**
* 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 ( 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.
*/
// Maybe extend writeBuffer
if ( stringConversionBuffer.length < s.length() ) {
stringConversionBuffer = new byte[ s.length() ];
}
// Fill writeBuffer
for ( int i = 0; i < s.length(); i++ ) {
stringConversionBuffer[i] = (byte) s.charAt( i );
}
write( stringConversionBuffer, 0, s.length() );
if ( doecho )
putString( s );
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 = "answerBack\n";
// X - COLUMNS, Y - ROWS
public 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;
/*
* The graphics charsets B - default ASCII A - ISO Latin 1 0 - DEC SPECIAL < -
* User defined ....
*/
char gx[] = {// same initial set as in XTERM.
'B', // g0
'0', // g1
'B', // g2
'B', // g3
};
char gl = 0; // default GL to G0
char gr = 2; // default GR to G2
int onegl = -1; // single shift override for GL.
//#ifndef simplevt320
// 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
};
//#endif
private String FunctionKey[];
//#ifndef simplevt320
/** Strings to send on function key pressing */
private String Numpad[];
private String FunctionKeyShift[];
private String FunctionKeyCtrl[];
private String FunctionKeyAlt[];
//#endif
private String TabKey[];
private String KeyUp[], KeyDown[], KeyLeft[], KeyRight[];
private String PF1, PF2, PF3, PF4;
//#ifndef simplevt320
private String KPMinus, KPComma, KPPeriod, KPEnter;
private String Help, Do, Find, Select;
private String Remove[];
//#endif
private String Insert[];
private String KeyHome[], KeyEnd[], PrevScn[], NextScn[], 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;
// System.err.println("unescape("+tmp+")");
cmd = "";
while ( ( idx = tmp.indexOf( '\\', oldidx ) ) >= 0 && ++idx <= tmp.length() ) {
cmd += tmp.substring( oldidx, idx - 1 );
if ( idx == tmp.length() )
return cmd;
switch ( tmp.charAt( idx ) ) {
case 'b':
cmd += "\b";
break;
case 'e':
cmd += "\u001b";
break;
case 'n':
cmd += "\n";
break;
case 'r':
cmd += "\r";
break;
case 't':
cmd += "\t";
break;
case 'v':
cmd += "\u000b";
break;
case 'a':
cmd += "\u0012";
break;
default:
if ( ( tmp.charAt( idx ) >= '0' ) && ( tmp.charAt( idx ) <= '9' ) ) {
int i;
for ( i = idx; i < tmp.length(); i++ )
if ( ( tmp.charAt( i ) < '0' ) || ( tmp.charAt( i ) > '9' ) )
break;
cmd += (char) Integer.parseInt( tmp.substring( idx, i ) );
idx = i - 1;
}
else
cmd += tmp.substring( idx, ++idx );
break;
}
oldidx = ++idx;
}
if ( oldidx <= tmp.length() )
cmd += tmp.substring( oldidx );
return cmd;
}
/**
* 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, int modifiers ) {
boolean control = ( modifiers & KEY_CONTROL ) != 0;
boolean shift = ( modifiers & KEY_SHIFT ) != 0;
boolean alt = ( modifiers & KEY_ALT ) != 0;
int xind;
String fmap[];
xind = 0;
fmap = FunctionKey;
//#ifndef simplevt320
if ( shift ) {
fmap = FunctionKeyShift;
xind = 1;
}
if ( control ) {
fmap = FunctionKeyCtrl;
xind = 2;
}
if ( alt ) {
fmap = FunctionKeyAlt;
xind = 3;
}
//#else
if ( shift ) {
xind = 1;
}
if ( control ) {
xind = 2;
}
if ( alt ) {
xind = 3;
}
//#endif
if (keyCode >= VT320.VK_F1 && keyCode <= VT320.VK_F12) {
writeSpecial(fmap[keyCode - VT320.VK_F1 + 1]);
}
else switch ( keyCode ) {
//#ifndef simplevt320
case VT320.VK_PAUSE:
if ( shift || control )
sendTelnetCommand( (byte) 243 ); // BREAK
break;
//#endif
case VT320.VK_UP:
writeSpecial( KeyUp[xind] );
break;
case VT320.VK_DOWN:
writeSpecial( KeyDown[xind] );
break;
case VT320.VK_LEFT:
writeSpecial( KeyLeft[xind] );
break;
case VT320.VK_RIGHT:
writeSpecial( KeyRight[xind] );
break;
case VT320.VK_PAGE_DOWN:
writeSpecial( NextScn[xind] );
break;
case VT320.VK_PAGE_UP:
writeSpecial( PrevScn[xind] );
break;
case VT320.VK_INSERT:
writeSpecial( Insert[xind] );
break;
//#ifndef simplevt320
case VT320.VK_DELETE:
writeSpecial( Remove[xind] );
break;
//#endif
case VT320.VK_BACK_SPACE:
writeSpecial( BackSpace[xind] );
if ( localecho ) {
if ( BackSpace[xind].equals("\b") ) {
putString( "\b \b" ); // make the last char 'deleted'
}
else {
putString( BackSpace[xind] ); // echo it
}
}
break;
case VT320.VK_HOME:
writeSpecial( KeyHome[xind] );
break;
case VT320.VK_END:
writeSpecial( KeyEnd[xind] );
break;
//#ifndef simplevt320
case VT320.VK_NUM_LOCK:
if ( vms && control ) {
writeSpecial( PF1 );
}
if ( !control )
numlock = !numlock;
break;
case VT320.VK_CAPS_LOCK:
capslock = !capslock;
break;
case VT320.VK_SHIFT:
case VT320.VK_CONTROL:
case VT320.VK_ALT:
break;
//#endif
}
flush();
}
public void stringTyped( String str ) {
for ( int i = 0; i < str.length(); i++ ) {
_keyTyped( 0, str.charAt( i ), 0 );
}
flush();
}
/**
* 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 ) {
_keyTyped( keyCode, keyChar, modifiers );
flush();
}
private void _keyTyped( int keyCode, char keyChar, int modifiers ) {
//System.out.println("KEY TYPED keycode:"+keyCode+" keychar:"+(int)keyChar+" modifiers:"+modifiers );
boolean control = ( modifiers & KEY_CONTROL ) != 0;
boolean shift = ( modifiers & KEY_SHIFT ) != 0;
boolean alt = ( modifiers & KEY_ALT ) != 0;
if ( keyChar == '\t' ) {
if ( shift ) {
write( TabKey[1], false );
}
else {
if ( control ) {
write( TabKey[2], false );
}
else {
if ( alt ) {
write( TabKey[3], false );
}
else {
write( TabKey[0], false );
}
}
}
return;
}
if ( alt ) {
write( "" + ( (char) ( keyChar | 0x80 ) ) );
return;
}
if ( ( ( keyCode == VT320.VK_ENTER ) || ( keyChar == 10 ) ) && !control ) {
// KARL changed from \r to \n. \r doesn't work with telnet sessions such as to SMTP
// This seems to work now with everything
// KARL 27/5/2005 changed from \n to \r\n, I think this is what we're supposed to send
// and it appears to work with SSH and SMTP sessions
write( "\r", false );
if ( localecho )
putString( "\r\n" ); // bad hack
return;
}
//#ifndef simplevt320
// FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @,
// so we can't just use it here... will probably break some other VMS
// codes. -Marcus
// if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ')
// && control)
if ( ( ( !vms && keyChar == '2' ) || keyChar == ' ' ) && control )
write( "" + (char) 0 );
if ( vms ) {
if ( keyChar == 127 && !control ) {
if ( shift )
writeSpecial( Insert[0] ); // VMS shift delete = insert
else
writeSpecial( Remove[0] ); // VMS delete = remove
return;
}
else if ( control )
switch ( keyChar ) {
case '0':
writeSpecial( Numpad[0] );
return;
case '1':
writeSpecial( Numpad[1] );
return;
case '2':
writeSpecial( Numpad[2] );
return;
case '3':
writeSpecial( Numpad[3] );
return;
case '4':
writeSpecial( Numpad[4] );
return;
case '5':
writeSpecial( Numpad[5] );
return;
case '6':
writeSpecial( Numpad[6] );
return;
case '7':
writeSpecial( Numpad[7] );
return;
case '8':
writeSpecial( Numpad[8] );
return;
case '9':
writeSpecial( Numpad[9] );
return;
case '.':
writeSpecial( KPPeriod );
return;
case '-':
case 31:
writeSpecial( KPMinus );
return;
case '+':
writeSpecial( KPComma );
return;
case 10:
writeSpecial( KPEnter );
return;
case '/':
writeSpecial( PF2 );
return;
case '*':
writeSpecial( PF3 );
return;
/* NUMLOCK handled in keyPressed */
default:
break;
}
/*
* Now what does this do and how did it get here. -Marcus if (shift &&
* keyChar < 32) { write(PF1+(char)(keyChar + 64)); return; }
*/
}
//#endif
// FIXME: not used?
// String fmap[];
int xind = 0;
// fmap = FunctionKey;
//#ifndef simplevt320
if ( shift ) {
// fmap = FunctionKeyShift;
xind = 1;
}
if ( control ) {
// fmap = FunctionKeyCtrl;
xind = 2;
}
if ( alt ) {
// fmap = FunctionKeyAlt;
xind = 3;
}
//#else
if ( shift ) {
xind = 1;
}
if ( control ) {
xind = 2;
}
if ( alt ) {
xind = 3;
}
//#endif
if ( keyCode == VT320.VK_ESCAPE ) {
writeSpecial( Escape[xind] );
return;
}
//#ifndef simplevt320
if ( ( modifiers & KEY_ACTION ) != 0 )
switch ( keyCode ) {
case VT320.VK_NUMPAD0:
writeSpecial( Numpad[0] );
return;
case VT320.VK_NUMPAD1:
writeSpecial( Numpad[1] );
return;
case VT320.VK_NUMPAD2:
writeSpecial( Numpad[2] );
return;
case VT320.VK_NUMPAD3:
writeSpecial( Numpad[3] );
return;
case VT320.VK_NUMPAD4:
writeSpecial( Numpad[4] );
return;
case VT320.VK_NUMPAD5:
writeSpecial( Numpad[5] );
return;
case VT320.VK_NUMPAD6:
writeSpecial( Numpad[6] );
return;
case VT320.VK_NUMPAD7:
writeSpecial( Numpad[7] );
return;
case VT320.VK_NUMPAD8:
writeSpecial( Numpad[8] );
return;
case VT320.VK_NUMPAD9:
writeSpecial( Numpad[9] );
return;
case VT320.VK_DECIMAL:
writeSpecial( NUMDot[xind] );
return;
case VT320.VK_ADD:
writeSpecial( NUMPlus[xind] );
return;
}
//#endif
if ( !( ( keyChar == 8 ) || ( keyChar == 127 ) || ( keyChar == '\r' ) || ( keyChar == '\n' ) ) ) {
// KARL support for control codes and shift keys
if ( control ) {
if ( keyChar >= 'a' && keyChar <= 'z' ) {
keyChar = (char) ( keyChar - 'a' + 'A' );
}
if ( keyChar >= 'A' && keyChar <= 'Z' ) {
keyChar = (char) ( keyChar - 'A' + 1 );
write( "" + keyChar );
}
else {
switch ( keyChar ) {
case '@': keyChar = (char) 0; break;
case '[': keyChar = (char) 27; break;
case '\\': keyChar = (char) 28; break;
case ']': keyChar = (char) 29; break;
case '^': keyChar = (char) 30; break;
case '_': keyChar = (char) 31; break;
}
write( "" + keyChar );
}
}
else if ( shift ) {
if ( keyChar >= 'a' && keyChar <= 'z' ) {
keyChar = (char) ( keyChar - 'a' + 'A' );
}
write( "" + keyChar );
}
else {
write( "" + keyChar );
}
return;
}
}
//#ifndef simplevt320
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];
}
//#endif
private void _SetCursor( int row, int col ) {
int maxr = height;
int tm = getTopMargin();
R = ( row < 0 ) ? 0 : row;
C = ( col < 0 ) ? 0 : col;
if ( !moveoutsidemargins ) {
R += tm;
maxr = getBottomMargin();
}
if ( R > maxr )
R = maxr;
}
private void putChar( char c, boolean doshowcursor ) {
int rows = height; //statusline
int columns = width;
int tm = getTopMargin();
int bm = getBottomMargin();
// byte msg[];
boolean mapped = false;
markLine( R, 1 );
if ( c > 255 ) {
//return;
}
switch ( term_state ) {
case TSTATE_DATA:
/*
* FIXME: we shouldn't use chars with bit 8 set if ibmcharset.
* probably... but some BBS do anyway...
*/
if ( !useibmcharset ) {
boolean doneflag = true;
switch ( c ) {
case OSC:
osc = "";
term_state = TSTATE_OSC;
break;
case RI:
if ( R > tm )
R--;
else
insertLine( R, 1, SCROLL_DOWN );
break;
case IND:
if ( R == bm || R == rows - 1 )
insertLine( R, 1, SCROLL_UP );
else
R++;
break;
case NEL:
if ( R == bm || R == rows - 1 )
insertLine( R, 1, SCROLL_UP );
else
R++;
C = 0;
break;
case HTS:
Tabs[C] = 1;
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 );
// flush();
// 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':
C = 0;
break;
case '\n':
if ( !vms ) {
if ( lastwaslf != 0 && lastwaslf != c ) // Ray: I do
// not
// understand this
// logic.
break;
lastwaslf = c;
/* C = 0; */
}
if ( R == bm || R >= rows - 1 )
insertLine( R, 1, SCROLL_UP );
else
R++;
break;
case 7:
beep();
break;
case '\016': /* SMACS , as */
/* ^N, Shift out - Put G1 into GL */
gl = 1;
usedcharsets = true;
break;
case '\017': /* RMACS , ae */
/* ^O, Shift in - Put G0 into GL */
gl = 0;
usedcharsets = true;
break;
default: {
int thisgl = gl;
if ( onegl >= 0 ) {
thisgl = onegl;
onegl = -1;
}
lastwaslf = 0;
if ( c < 32 ) {
if ( c != 0 )
/*
* break; some BBS really want those characters,
* like hearst etc.
*/
if ( c == 0 ) /* print 0 ... you bet */
break;
}
if ( C >= columns ) {
if ( wraparound ) {
if ( R < rows - 1 )
R++;
else
insertLine( R, 1, SCROLL_UP );
C = 0;
}
else {
// cursor stays on last character.
C = columns - 1;
}
}
// Mapping if DEC Special is chosen charset
//#ifndef simplevt320
if ( usedcharsets ) {
if ( c >= '\u0020' && c <= '\u007f' ) {
switch ( gx[thisgl] ) {
case '0':
// Remap SCOANSI line drawing to VT100
// line drawing
// chars
// for our SCO using customers.
if ( terminalID.equals( "scoansi" ) || terminalID.equals( "ansi" ) ) {
for ( int i = 0; i < scoansi_acs.length(); i += 2 ) {
if ( c == scoansi_acs.charAt( i ) ) {
c = scoansi_acs.charAt( i + 1 );
break;
}
}
}
if ( c >= '\u005f' && c <= '\u007e' ) {
c = DECSPECIAL[(short) c - 0x5f];
mapped = true;
}
break;
case '<': // 'user preferred' is currently
// 'ISO Latin-1
// suppl
c = (char) ( ( (int) c & 0x7f ) | 0x80 );
mapped = true;
break;
case 'A':
case 'B': // Latin-1 , ASCII -> fall through
mapped = true;
break;
default:
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:
break;
}
}
}
if ( !mapped && useibmcharset )
c = map_cp850_unicode( c );
//#endif
/* if(true || (statusmode == 0)) { */
if ( insertmode == 1 ) {
insertChar( C, R, c, attributes );
}
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:
}
break;
case TSTATE_ESC:
term_state = TSTATE_DATA;
switch ( c ) {
case ' ':
term_state = TSTATE_ESCSPACE;
break;
case '#':
term_state = TSTATE_ESCSQUARE;
break;
case 'c':
/* Hard terminal reset */
/* reset character sets */
gx[0] = 'B';
gx[1] = '0';
gx[2] = 'B';
gx[3] = 'B';
gl = 0; // default GL to G0
gr = 1; // default GR to G1
/* reset tabs */
int nw = width;
if ( nw < 132 )
nw = 132;
Tabs = new byte[nw];
for ( int i = 0; i < nw; i += 8 ) {
Tabs[i] = 1;
}
/* FIXME: */
break;
case '[':
DCEvar = 0;
DCEvars[0] = 0;
DCEvars[1] = 0;
DCEvars[2] = 0;
DCEvars[3] = 0;
term_state = TSTATE_CSI;
break;
case ']':
osc = "";
term_state = TSTATE_OSC;
break;
case 'P':
dcs = "";
term_state = TSTATE_DCS;
break;
case 'A': /* CUU */
R--;
if ( R < 0 )
R = 0;
break;
case 'B': /* CUD */
R++;
if ( R > rows - 1 )
R = rows - 1;
break;
case 'C':
C++;
if ( C >= columns )
C = columns - 1;
break;
case 'I': // RI
insertLine( R, 1, SCROLL_DOWN );
break;
case 'E': /* NEL */
if ( R == bm || R == rows - 1 )
insertLine( R, 1, SCROLL_UP );
else
R++;
C = 0;
break;
case 'D': /* IND */
if ( R == bm || R == rows - 1 )
insertLine( R, 1, SCROLL_UP );
else
R++;
break;
case 'J': /* erase to end of screen */
if ( R < rows - 1 )
deleteArea( 0, R + 1, columns, rows - R - 1, attributes );
if ( C < columns - 1 )
deleteArea( C, R, columns - C, 1, attributes );
break;
case 'K':
if ( C < columns - 1 )
deleteArea( C, R, columns - C, 1, attributes );
break;
case 'M': // RI
if ( R > bm ) // outside scrolling region
break;
if ( R > tm ) { // just go up 1 line.
R--;
}
else { // scroll down
insertLine( R, 1, SCROLL_DOWN );
}
/* else do nothing ; */
break;
case 'H':
/* 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 */
keypadmode = true;
break;
case '<': /* vt52 mode off */
vt52mode = false;
break;
case '>': /* normal keypad */
keypadmode = false;
break;
case '7': /* save cursor, attributes, margins */
Sc = C;
Sr = R;
Sgl = gl;
Sgr = gr;
Sa = attributes;
Sgx = new char[4];
for ( int i = 0; i < 4; i++ )
Sgx[i] = gx[i];
Stm = getTopMargin();
Sbm = getBottomMargin();
break;
case '8': /* restore cursor, attributes, margins */
C = Sc;
R = Sr;
gl = Sgl;
gr = Sgr;
for ( int i = 0; i < 4; i++ )
gx[i] = Sgx[i];
setTopMargin( Stm );
setBottomMargin( Sbm );
attributes = Sa;
break;
case '(': /* Designate G0 Character set (ISO 2022) */
term_state = TSTATE_SETG0;
usedcharsets = true;
break;
case ')': /* Designate G1 character set (ISO 2022) */
term_state = TSTATE_SETG1;
usedcharsets = true;
break;
case '*': /* Designate G2 Character set (ISO 2022) */
term_state = TSTATE_SETG2;
usedcharsets = true;
break;
case '+': /* Designate G3 Character set (ISO 2022) */
term_state = TSTATE_SETG3;
usedcharsets = true;
break;
case '~': /* Locking Shift 1, right */
gr = 1;
usedcharsets = true;
break;
case 'n': /* Locking Shift 2 */
gl = 2;
usedcharsets = true;
break;
case '}': /* Locking Shift 2, right */
gr = 2;
usedcharsets = true;
break;
case 'o': /* Locking Shift 3 */
gl = 3;
usedcharsets = true;
break;
case '|': /* Locking Shift 3, right */
gr = 3;
usedcharsets = true;
break;
case 'Y': /* vt52 cursor address mode , next chars are x,y */
term_state = TSTATE_VT52Y;
break;
default:
break;
}
break;
case TSTATE_VT52X:
C = c - 37;
term_state = TSTATE_VT52Y;
break;
case TSTATE_VT52Y:
R = c - 37;
term_state = TSTATE_DATA;
break;
case TSTATE_SETG0:
if ( !( c != '0' && c != 'A' && c != 'B' && c != '<' ) )
gx[0] = c;
term_state = TSTATE_DATA;
break;
case TSTATE_SETG1:
if ( !( c != '0' && c != 'A' && c != 'B' && c != '<' ) ) {
gx[1] = c;
}
term_state = TSTATE_DATA;
break;
case TSTATE_SETG2:
if ( !( c != '0' && c != 'A' && c != 'B' && c != '<' ) )
gx[2] = c;
term_state = TSTATE_DATA;
break;
case TSTATE_SETG3:
if ( !( c != '0' && c != 'A' && c != 'B' && 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:
break;
}
term_state = TSTATE_DATA;
break;
case TSTATE_DCS:
if ( c == '\\' && dcs.charAt( dcs.length() - 1 ) == ESC ) {
//handle_dcs( dcs );
term_state = TSTATE_DATA;
break;
}
dcs = dcs + c;
break;
case TSTATE_DCEQ:
term_state = TSTATE_DATA;
switch ( c ) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + ( (int) c ) - 48;
term_state = TSTATE_DCEQ;
break;
case ';':
DCEvar++;
DCEvars[DCEvar] = 0;
term_state = TSTATE_DCEQ;
break;
case 's': // XTERM_SAVE missing!
break;
case 'r': // XTERM_RESTORE
/* DEC Mode reset */
for ( int i = 0; i <= DCEvar; i++ ) {
switch ( DCEvars[i] ) {
case 3: /* 80 columns */
setScreenSize( 80, height );
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:
}
}
break;
case 'h': // DECSET
/* 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 );
break;
case 6: /* DECOM: move inside margins. */
moveoutsidemargins = false;
break;
case 7: /* DECAWM: Autowrap Mode */
wraparound = true;
break;
case 25: /* turn cursor on */
showCursor( true );
redraw();
break;
case 9: /* X10 mouse */
case 1000: /* xterm style mouse report on */
case 1001:
case 1002:
case 1003:
mouserpt = DCEvars[i];
break;
/* unimplemented stuff, fall through */
/* 4 - scrolling mode, smooth */
/* 5 - light background */
/* 12 - local echo off */
/* 18 - DECPFF - Printer Form Feed Mode -> On */
/* 19 - DECPEX - Printer Extent Mode -> Screen */
default:
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:
break;
case 4:
break;
case 5:
break;
}
break;
case 'l': //DECRST
/* DEC Mode reset */
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 );
break;
case 6: /* DECOM: move outside margins. */
moveoutsidemargins = true;
break;
case 7: /* DECAWM: Autowrap Mode OFF */
wraparound = false;
break;
case 25: /* turn cursor off */
showCursor( false );
redraw();
break;
/* Unimplemented stuff: */
/* 4 - scrolling mode, jump */
/* 5 - dark background */
/* 7 - DECAWM - no wrap around mode */
/* 12 - local echo on */
/* 18 - DECPFF - Printer Form Feed Mode -> Off */
/*
* 19 - DECPEX - Printer Extent Mode ->
* Scrolling Region
*/
case 9: /* X10 mouse */
case 1000: /* xterm style mouse report OFF */
case 1001:
case 1002:
case 1003:
mouserpt = 0;
break;
default:
break;
}
}
break;
case 'n':
switch ( DCEvars[0] ) {
case 15:
/* printer? no printer. */
write( ( (char) ESC ) + "[?13n", false );
flush();
break;
default:
break;
}
break;
default:
break;
}
break;
case TSTATE_CSI_EX:
term_state = TSTATE_DATA;
switch ( c ) {
case ESC:
term_state = TSTATE_ESC;
break;
default:
break;
}
break;
case TSTATE_CSI_TICKS:
term_state = TSTATE_DATA;
switch ( c ) {
case 'p':
if ( DCEvars[0] == 61 ) {
output8bit = false;
break;
}
if ( DCEvars[1] == 1 ) {
output8bit = false;
}
else {
output8bit = true; /* 0 or 2 */
}
break;
default:
break;
}
break;
case TSTATE_CSI_DOLLAR:
term_state = TSTATE_DATA;
switch ( c ) {
case '}':
statusmode = DCEvars[0];
break;
case '~':
break;
default:
break;
}
break;
case TSTATE_CSI:
term_state = TSTATE_DATA;
switch ( c ) {
case '"':
term_state = TSTATE_CSI_TICKS;
break;
case '$':
term_state = TSTATE_CSI_DOLLAR;
break;
case '!':
term_state = TSTATE_CSI_EX;
break;
case '?':
DCEvar = 0;
DCEvars[0] = 0;
term_state = TSTATE_DCEQ;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + ( (int) c ) - 48;
term_state = TSTATE_CSI;
break;
case ';':
DCEvar++;
DCEvars[DCEvar] = 0;
term_state = TSTATE_CSI;
break;
case 'c':/* send primary device attributes */
/* send (ESC[?61c) */
String subcode = "";
if ( terminalID.equals( "vt320" ) )
subcode = "63;";
if ( terminalID.equals( "vt220" ) )
subcode = "62;";
if ( terminalID.equals( "vt100" ) )
subcode = "61;";
write( ( (char) ESC ) + "[?" + subcode + "1;2c", false );
flush();
break;
case '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;
}
break;
case 'h':
switch ( DCEvars[0] ) {
case 4:
insertmode = 1;
break;
case 20:
sendcrlf = true;
break;
default:
break;
}
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:
break;
case 4:
break;
case 5:
break;
default:
}
break;
case 'l':
switch ( DCEvars[0] ) {
case 4:
insertmode = 0;
break;
case 20:
sendcrlf = false;
break;
default:
break;
}
break;
case 'A': // CUU
{
int limit;
/* FIXME: xterm only cares about 0 and topmargin */
if ( R > bm )
limit = bm + 1;
else if ( R >= tm ) {
limit = tm;
}
else
limit = 0;
if ( DCEvars[0] == 0 )
R--;
else
R -= DCEvars[0];
if ( R < limit )
R = limit;
break;
}
case 'B': // CUD
/* cursor down n (1) times */
{
int limit;
if ( R < tm )
limit = tm - 1;
else if ( R <= bm ) {
limit = bm;
}
else
limit = rows - 1;
if ( DCEvars[0] == 0 )
R++;
else
R += DCEvars[0];
if ( R > limit )
R = limit;
break;
}
case 'C':
if ( DCEvars[0] == 0 )
C++;
else
C += DCEvars[0];
if ( C > columns - 1 )
C = columns - 1;
break;
case 'd': // CVA
R = DCEvars[0];
break;
case 'D':
if ( DCEvars[0] == 0 )
C--;
else
C -= DCEvars[0];
if ( C < 0 )
C = 0;
break;
case 'r': // DECSTBM
if ( DCEvar > 0 ) // Ray: Any argument is optional
{
R = DCEvars[1] - 1;
if ( R < 0 )
R = rows - 1;
else if ( R >= rows ) {
R = rows - 1;
}
}
else
R = rows - 1;
setBottomMargin( R );
if ( R >= DCEvars[0] ) {
R = DCEvars[0] - 1;
if ( R < 0 )
R = 0;
}
setTopMargin( R );
_SetCursor( 0, 0 );
break;
case 'G': /* CUP / cursor absolute column */
C = DCEvars[0];
break;
case 'H': /* CUP / cursor position */
/* gets 2 arguments */
_SetCursor( DCEvars[0] - 1, DCEvars[1] - 1 );
break;
case 'f': /* move cursor 2 */
/* gets 2 arguments */
R = DCEvars[0] - 1;
C = DCEvars[1] - 1;
if ( C < 0 )
C = 0;
if ( R < 0 )
R = 0;
break;
case 'S': /* ind aka 'scroll forward' */
if ( DCEvars[0] == 0 )
insertLine( rows - 1, SCROLL_UP );
else
insertLine( rows - 1, DCEvars[0], SCROLL_UP );
break;
case 'L':
/* insert n lines */
if ( DCEvars[0] == 0 )
insertLine( R, SCROLL_DOWN );
else
insertLine( R, DCEvars[0], SCROLL_DOWN );
break;
case 'T': /* 'ri' aka scroll backward */
if ( DCEvars[0] == 0 )
insertLine( 0, SCROLL_DOWN );
else
insertLine( 0, DCEvars[0], SCROLL_DOWN );
break;
case 'M':
if ( DCEvars[0] == 0 )
deleteLine( R );
else
for ( int i = 0; i < DCEvars[0]; i++ )
deleteLine( R );
break;
case '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;
}
break;
case '@':
for ( int i = 0; i < DCEvars[0]; i++ )
insertChar( C, R, ' ', attributes );
break;
case 'X': {
int toerase = DCEvars[0];
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 ( DCEvars[0] == 0 )
DCEvars[0] = 1;
for ( int i = 0; i < DCEvars[0]; i++ )
deleteChar( C, R );
break;
case 'n':
switch ( DCEvars[0] ) {
case 5: /* malfunction? No malfunction. */
writeSpecial( ( (char) ESC ) + "[0n" );
flush();
break;
case 6:
// DO NOT offset R and C by 1! (checked against
// /usr/X11R6/bin/resize
// FIXME check again.
// FIXME: but vttest thinks different???
writeSpecial( ( (char) ESC ) + "[" + R + ";" + C + "R" );
flush();
break;
default:
break;
}
break;
case 's': /* DECSC - save cursor */
Sc = C;
Sr = R;
Sa = attributes;
break;
case 'u': /* DECRC - restore cursor */
C = Sc;
R = Sr;
attributes = Sa;
break;
case 'm': /* attributes as color, bold , blink, */
if ( DCEvar == 0 && DCEvars[0] == 0 )
attributes = 0;
for ( int i = 0; i <= DCEvar; i++ ) {
switch ( DCEvars[i] ) {
case 0:
if ( DCEvar > 0 ) {
if ( terminalID.equals( "scoansi" ) ) {
attributes &= COLOR; /*
* Keeps color.
* Strange but
* true.
*/
}
else {
attributes = 0;
}
}
break;
case 1:
attributes |= BOLD;
attributes &= ~LOW;
break;
case 2:
/* SCO color hack mode */
if ( terminalID.equals( "scoansi" ) && ( ( DCEvar - i ) >= 2 ) ) {
int ncolor;
attributes &= ~( COLOR | BOLD );
ncolor = DCEvars[i + 1];
if ( ( ncolor & 8 ) == 8 )
attributes |= BOLD;
ncolor = ( ( ncolor & 1 ) << 2 ) | ( ncolor & 2 ) | ( ( ncolor & 4 ) >> 2 );
attributes |= ( ( ncolor ) + 1 ) << 4;
ncolor = DCEvars[i + 2];
ncolor = ( ( ncolor & 1 ) << 2 ) | ( ncolor & 2 ) | ( ( ncolor & 4 ) >> 2 );
attributes |= ( ( ncolor ) + 1 ) << 8;
i += 2;
}
else {
attributes |= LOW;
}
break;
case 4:
attributes |= UNDERLINE;
break;
case 7:
attributes |= INVERT;
break;
case 5: /* blink on */
break;
/*
* 10 - ANSI X3.64-1979, select primary font,
* don't display control chars, don't set bit 8
* on output
*/
case 10:
gl = 0;
usedcharsets = true;
break;
/*
* 11 - ANSI X3.64-1979, select second alt.
* font, display control chars, set bit 8 on
* output
*/
case 11: /* SMACS , as */
case 12:
gl = 1;
usedcharsets = true;
break;
case 21: /* normal intensity */
attributes &= ~( LOW | BOLD );
break;
case 25: /* blinking off */
break;
case 27:
attributes &= ~INVERT;
break;
case 24:
attributes &= ~UNDERLINE;
break;
case 22:
attributes &= ~BOLD;
break;
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
attributes &= ~COLOR_FG;
attributes |= ( ( DCEvars[i] - 30 ) + 1 ) << 4;
break;
case 39:
attributes &= ~COLOR_FG;
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
attributes &= ~COLOR_BG;
attributes |= ( ( DCEvars[i] - 40 ) + 1 ) << 8;
break;
case 49:
attributes &= ~COLOR_BG;
break;
default:
break;
}
}
break;
default:
break;
}
break;
default:
term_state = TSTATE_DATA;
break;
}
if ( C > columns )
C = columns;
if ( R > rows )
R = rows;
if ( C < 0 )
C = 0;
if ( R < 0 )
R = 0;
if ( doshowcursor )
setCursorPosition( C, R );
markLine( R, 1 );
}
/* hard reset the terminal */
public void reset() {
gx[0] = 'B';
gx[1] = '0';
gx[2] = 'B';
gx[3] = 'B';
gl = 0; // default GL to G0
gr = 1; // default GR to G1
/* reset tabs */
int nw = width;
if ( nw < 132 )
nw = 132;
Tabs = new byte[nw];
for ( int i = 0; i < nw; i += 8 ) {
Tabs[i] = 1;
}
/* FIXME: */
term_state = TSTATE_DATA;
}
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
public boolean showcursor = true;
public 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;
/** 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;
public final static int COLOR = 0xff0;
public final static int COLOR_FG = 0xf0;
public final static int COLOR_BG = 0xf00;
/**
* 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 #NORMAL
* @see #insertChar
* @see #deleteChar
* @see #redraw
*/
public void putChar( int c, int l, char ch, int attributes ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
charArray[screenBase + l][c] = ch;
charAttributes[screenBase + l][c] = attributes;
markLine( l, 1 );
}
/**
* 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 ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
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 ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
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 #NORMAL
* @see #putChar
* @see #deleteChar
* @see #redraw
*/
public void insertChar( int c, int l, char ch, int attributes ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
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 ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
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 #NORMAL
* @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 #NORMAL
* @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 void insertLine( int l, int n, boolean scrollDown ) {
l = checkBounds( l, 0, height - 1 );
char cbuf[][] = null;
int abuf[][] = null;
int offset = 0;
int oldBase = screenBase;
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 );
}
cbuf = new char[bottom - l - ( n - 1 )][width];
abuf = new int[bottom - l - ( n - 1 )][width];
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;
bufSize = maxBufSize;
screenBase = maxBufSize - height - 1;
windowBase = screenBase;
}
else {
scrollMarker += n;
screenBase += n;
windowBase += n;
bufSize += n;
}
cbuf = new char[bufSize][width];
abuf = new int[bufSize][width];
}
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, screenBase, top );
System.arraycopy( charAttributes, oldBase, abuf, screenBase, 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
// Telnet.console.println( "scrolling up line:" );
// Telnet.console.println( new String( charArray[screenBase+top]
// ));
// ERROR for mobile phones
// Telnet.console.println( "arraycopy: " );
// Telnet.console.println( "len:" + (l - top - (n - 1)));
// Telnet.console.println( "from:" + (oldBase + top + n));
// Telnet.console.println( "to:" + (screenBase + top));
/*
* System.arraycopy(charArray, oldBase + top + n, cbuf,
* screenBase + top, l - top - (n - 1));
* System.arraycopy(charAttributes, oldBase + top + n, abuf,
* screenBase + top, l - top - (n - 1));
*/
// this works fine RADEK
for ( int i = 0; i < l - top - ( n - 1 ); i++ ) {
cbuf[screenBase + top + i] = charArray[oldBase + top + n + i];
abuf[screenBase + top + i] = charAttributes[oldBase + top + n + i];
}
//
// copy the all lines next to the inserted to the new buffer
if ( l < height - 1 ) {
System.arraycopy( charArray, oldBase + l + 1, cbuf, screenBase + l + 1, ( height - 1 ) - l );
System.arraycopy( charAttributes, oldBase + l + 1, abuf, screenBase + 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
//#ifndef simplevt320
/*
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( "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" );
*/
//#endif
}
}
// this is a little helper to mark the scrolling
scrollMarker -= n;
for ( int i = 0; i < n; i++ ) {
cbuf[( screenBase + l ) + ( scrollDown ? i : -i )] = new char[width];
abuf[( screenBase + l ) + ( scrollDown ? i : -i )] = new int[width];
}
charArray = cbuf;
charAttributes = abuf;
if ( scrollDown ) {
markLine( l, bottom - l + 1 );
}
else {
markLine( top, l - top + 1 );
// System.out.println( "14:" + new String( charArray[14]) );
// System.out.println( "15:" + new String( charArray[15]) );
/*
* FIXME: needs to be in VDU if(scrollBar != null)
* scrollBar.setValues(windowBase, height, 0, bufSize);
*/
}
}
/**
* 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 ) {
l = checkBounds( l, 0, height - 1 );
int bottom = ( l > bottomMargin ? height - 1 : ( l < topMargin ? topMargin : bottomMargin + 1 ) );
System.arraycopy( charArray, screenBase + l + 1, charArray, screenBase + l, bottom - l - 1 );
System.arraycopy( charAttributes, screenBase + l + 1, charAttributes, screenBase + l, bottom - l - 1 );
charArray[screenBase + bottom - 1] = new char[width];
charAttributes[screenBase + bottom - 1] = new int[width];
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 ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
char cbuf[] = new char[w];
int abuf[] = new int[w];
for ( int i = 0; i < w; i++ ) {
abuf[i] = curAttr;
}
for ( int i = 0; i < h && l + i < height; i++ ) {
System.arraycopy( cbuf, 0, charArray[screenBase + l + i], c, w );
System.arraycopy( abuf, 0, charAttributes[screenBase + l + i], c, w );
}
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 ) {
c = checkBounds( c, 0, width - 1 );
l = checkBounds( l, 0, height - 1 );
char cbuf[] = new char[w];
int abuf[] = new int[w];
for ( int i = 0; i < h && l + i < height; i++ ) {
System.arraycopy( cbuf, 0, charArray[screenBase + l + i], c, w );
System.arraycopy( abuf, 0, charAttributes[screenBase + l + i], c, w );
}
markLine( l, h );
}
/**
* Sets whether the cursor is visible or not.
*
* @param doshow
*/
public void showCursor( boolean doshow ) {
if ( doshow != showcursor ) {
markLine( cursorY, 1 );
}
showcursor = doshow;
}
/**
* Puts the cursor at the specified position.
*
* @param c
* column
* @param l
* line
*/
public void setCursorPosition( int c, int l ) {
cursorX = checkBounds( c, 0, width - 1 );
cursorY = checkBounds( l, 0, height - 1 );
markLine( cursorY, 1 );
}
/**
* 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 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 - 1 ) {
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 - 1 ) {
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 ) {
char cbuf[][];
int abuf[][];
int bsize = bufSize;
if ( w < 1 || h < 1 ) {
return;
}
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];
if ( charArray != null && charAttributes != null ) {
for ( int i = 0; i < bsize && i < bufSize; i++ ) {
System.arraycopy( charArray[i], 0, cbuf[i], 0, w < width ? w : width );
System.arraycopy( charAttributes[i], 0, abuf[i], 0, w < width ? w : width );
}
}
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());
*/
}
/**
* 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 ) {
l = checkBounds( l, 0, height - 1 );
for ( int i = 0; ( i < n ) && ( l + i < height ); i++ ) {
update[l + i + 1] = true;
}
}
private int checkBounds( int value, int lower, int upper ) {
if ( value < lower ) {
return lower;
}
if ( value > upper ) {
return upper;
}
return value;
}
/** a generic display that should redraw on demand */
protected Redrawable display;
public void setDisplay(Redrawable display) {
this.display = display;
}
/**
* Trigger a redraw on the display.
*/
protected void redraw() {
if ( display != null ) {
display.redraw();
}
}
}