telnetcanvas.java

来自「j2me学习 简单例子」· Java 代码 · 共 818 行 · 第 1/2 页

JAVA
818
字号
/* 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.telnetui;

 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 Font 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 = Font.getFont( 
            Font.FACE_MONOSPACE, Font.STYLE_PLAIN, Font.SIZE_SMALL ); 
        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;
                
                case 'B': // cursor down by x

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?