telnetcanvas.java
来自「j2me学习 简单例子」· Java 代码 · 共 822 行 · 第 1/2 页
JAVA
822 行
/* License
*
* Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package example.term.telnetfont;
import java.io.IOException;
import java.io.OutputStream;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Font;
/**
* Canvas that renders an ANSI character stream and
* sends any user input to the specified output stream.
*/
public class TelnetCanvas extends Canvas
{
private CustomFont font;
private short fontHeight;
private short fontWidth;
private short rows;
private short columns;
private int scrollX;
private int scrollY;
private short insetX;
private short insetY;
private byte[] buffer;
private int cursor;
private int savedCursor;
private int bound; // outer bound: max extent of cursor
private OutputStream output;
/**
* The first element in this array is the logical size,
* which is the index at which the next byte should be
* placed. (Kind of like Pascal.)
* The array itself may be longer than the length used.
*/
private char[] argbuf;
private byte state;
private boolean highlight;
private boolean scrolling;
private byte[] move = new byte[] { 27, '[', 0 };
private static final byte NORMAL_STATE = 0;
private static final byte ESCAPE_STATE = 1;
private static final byte PARAMS_STATE= 2;
/**
* Default constructor creates a new telnet canvas.
*/
public TelnetCanvas()
{
int width = getWidth();
int height = getHeight();
// get font and metrics
font = CustomFont.getFont(
"/mono.png", // the font definition file
Font.SIZE_SMALL, // ignored
Font.STYLE_PLAIN ); // no styling
fontHeight = (short) font.getHeight();
fontWidth = (short) font.stringWidth( "w" ); // it's monospaced
// calculate how many rows and columns we can display
columns = (short) ( width / fontWidth );
rows = (short) ( height / fontHeight );
// divide any extra space evenly around edges of screen
insetX = (short) ( ( width - columns*fontWidth ) / 2 );
insetY = (short) ( ( height - rows*fontHeight ) / 2 );
// initialize state
reset();
scrolling = false;
// ansi arg parsing state
argbuf = new char[2];
state = 0;
highlight = false;
}
/**
* Returns the number of rows that fit on screen.
*/
public int getRows()
{
return rows;
}
/**
* Returns the number of columns that fit on screen.
*/
public int getColumns()
{
return columns;
}
/**
* Returns the supported terminal emulation type.
*/
public String getTerminalType()
{
return "ansi";
}
/**
* Resets the display to its initial state.
*/
public void reset()
{
buffer = new byte[rows*columns*4]; // start with 4 screens of buffer
cursor = 0;
bound = rows * columns;
savedCursor = -1;
scrollX = 0;
scrollY = 0;
}
/**
* Returns whether the terminal is in "scroll-lock" mode:
* arrow keys will scroll the local display instead of
* being sent to the remote host.
*/
public boolean isScrolling()
{
return scrolling;
}
/**
* Sets whether the terminal is in "scroll-lock" mode:
* arrow keys will scroll the local display instead of
* being sent to the remote host.
*/
public void setScrolling( boolean isScrolling )
{
scrolling = isScrolling;
}
/**
* Sets the output stream used to receive user input.
*/
public void setOutputStream( OutputStream stream )
{
output = stream;
}
/**
* Sends the specified byte to the output stream.
* If no output stream is set, does nothing.
*/
public void send( byte b )
{
if ( output == null ) return;
try
{
output.write( b );
output.flush();
}
catch ( IOException exc )
{
System.err.println( "Error on send: " + exc );
}
}
/**
* Sends the specified bytes to the output stream.
* If no output stream is set, does nothing.
*/
public void send( byte b[] )
{
if ( output == null ) return;
try
{
output.write( b );
output.flush();
}
catch ( IOException exc )
{
System.err.println( "Error on send data: " + exc );
}
}
/**
* Appends the specified ascii string - no unicode allowed.
*/
public void receive( String inString )
{
receive( inString.toCharArray() );
}
/**
* Appends the specified ascii character array - no unicode allowed.
*/
public void receive( char[] c )
{
for ( int i = 0; i < c.length; i++ ) receive( (byte) c[i] );
}
/**
* Appends the specified ascii bytes to the output.
*/
public void receive( byte[] b )
{
for ( int i = 0; i < b.length; i++ ) receive( b[i] );
}
/**
* Appends the specified ascii byte to the output.
*/
public void receive( byte b )
{
// ignore nulls
if ( b == 0 ) return;
if ( state == PARAMS_STATE )
{
// if still receiving parameters
if ( b < 64 )
{
argbuf[0]++;
// grow if needed
if ( argbuf[0] == argbuf.length )
{
char[] tmp = new char[ argbuf.length * 2 ];
System.arraycopy( argbuf, 0, tmp, 0, argbuf.length );
argbuf = tmp;
}
argbuf[ argbuf[0] ] = (char) b;
}
else // final byte: process the command
{
processCommand( b );
// reset for next command
argbuf[0] = 0;
state = NORMAL_STATE;
}
}
else
if ( state == ESCAPE_STATE )
{
// if a valid escape sequence
if ( b == '[' )
{
state = PARAMS_STATE;
}
else // not an escape sequence
{
// allow escape to pass through
state = NORMAL_STATE;
processData( (byte) 27 );
processData( b );
}
}
else // NORMAL_STATE
{
if ( b == 27 )
{
state = ESCAPE_STATE;
}
else
{
processData( b );
}
}
}
/**
* Appends the specified byte to the display buffer.
*/
protected void processData( byte b )
{
// grow buffer as needed
if ( cursor + columns > buffer.length )
{
try
{
// expand by sixteen screenfuls at a time
byte[] tmp = new byte[ buffer.length + rows*columns*16 ];
System.arraycopy( buffer, 0, tmp, 0, buffer.length );
buffer = tmp;
}
catch ( OutOfMemoryError e )
{
// no more memory to grow: just clear half and reuse the existing buffer
System.err.println( "Could not allocate buffer larger than: " + buffer.length );
int i, half = buffer.length / 2;
for ( i = 0; i < half; i++ ) buffer[i] = buffer[i+half];
for ( i = half; i < buffer.length; i++ ) buffer[i] = 0;
int oldLastScreen = calcLastVisibleScreen();
cursor = cursor - half; // start from last input
if ( scrollY == oldLastScreen ) scrollY = calcLastVisibleScreen();
}
}
// start with the last screen containing the cursor
int offsetY = calcLastVisibleScreen();
switch ( b )
{
case 8: // back space
cursor--;
break;
case 10: // line feed
cursor = cursor + columns - ( cursor % columns );
break;
case 13: // carriage return
cursor = cursor - ( cursor % columns );
break;
default:
if ( b > 31 )
{
// only show visible characters
buffer[cursor++] = b;
}
// ignore all others
}
// increment bound if necessary
while ( cursor > bound ) bound += columns;
// if the user has scrolled back, don't lose
// their position when new input comes in
int newY = calcLastVisibleScreen();
if ( newY != offsetY && offsetY == scrollY )
{
// otherwise, make the latest input visible
scrollY = (short) newY;
}
repaint();
}
/**
* Executes the specified ANSI command, obtaining arguments
* as needed from the getArgument() and getArgumentCount() methods.
*/
protected void processCommand( byte command )
{ //System.out.println( "processCommand: " + (char) command + " : " + new String( argbuf, 1, argbuf[0] ) );
try
{
int arg = 0;
switch ( command )
{
case 'H': // cursor position to x, y or home
case 'f': // cursor position to x, y or home
if ( argbuf[0] > 0 )
{
cursor = bound-1 - ((rows-getArgument( 0 ))*columns) - (columns-getArgument( 1 ));
}
else
{ // return to top-left position
cursor = bound - ( rows * columns );
}
break;
case 'A': // cursor up by x
if ( argbuf[0] == 0 )
{
cursor = cursor - columns;
}
else
{
cursor = cursor - columns * getArgument( 0 );
}
break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?