这里有一些我正在努力工作的代码。基本上我需要保持进程打开,并在单个会话中提供新命令。一旦发出“exit”字符串命令,该过程就应该完成。感谢帮助......
Process process;
ArrayList<String>command;
ProcessBuilder builder;
Map<String, String> environ;
BufferedWriter bw;
BufferedReader br;
BufferedReader buffErrorStreamReader;
....
try
{
command = new ArrayList<String>();
command.add("cmd.exe");
command.add("/c");
//command.add(currentLine);
builder = new ProcessBuilder(command);
environ = builder.environment();
builder.directory(new File("C://"));
process = builder.start();
}catch(Exception e)
{
System.out.println(e);
}
//Get a System.in Stream
OutputStream output = process.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(output);
bw = new BufferedWriter(osw);
//Get a System.out Stream
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
//Get a System.err Stream
InputStream errorStream = process.getErrorStream();
InputStreamReader errorStreamReader = new InputStreamReader(errorStream);
buffErrorStreamReader = new BufferedReader(errorStreamReader);
....
//Read the command from my text component terminal
String currentLine = getCurrentLine();
///pass command to pipe input
bw.write(currentLine);
System.out.println("wrote: "+currentLine);
///print response
String line;
while ((line = br.readLine()) != null)
{
System.out.println(line);
//term.println(line);
}
///print any error response
String errorLine;
while ((errorLine = buffErrorStreamReader.readLine()) != null)
{
System.out.println(errorLine);
//term.println(errorLine);
}
答案 0 :(得分:0)
您正在读取错误流和输入流,直到EOS,直到流程退出时才会发生(或者,很少有我在30多年前从未见过它,关闭stdout和stderr)。通常的做法是(a)合并错误和输出流和/或(b)在单独的线程中读取/它们,这样在这种情况下,您可以继续从其源输入输入,而不必担心产生的输出任何,在外部过程中你不能太了解的事物的本质。
答案 1 :(得分:0)
我的完整代码正在运行。我有一个终端从画布上的当前行获取命令。然后它组装一个进程构建器:“cmd.exe”,“/ c”和“当前行的命令字符串”参数。最后,它获取构建器环境并设置构建器目录。然后它启动该过程并获取该过程的输入和错误流。然后它将这些响应打印到我的画布终端。但是,我的方法的问题是我正在为每个进程打开一个新的cmd.exe(dos命令提示符)。所以基本上,它是一个非交互式终端,因为在命令提交(新进程)之间没有建立会话。该过程只接受命令,打印输出并每次终止。所以我的问题是如何实现交互式终端会话。我已成功实现了通过保存当前路径并使用builder.directory方法将其传递给新进程来更改目录的功能。也可以使用builder.environment对环境变量执行相同的操作(但我无法弄清楚)。这会给人一种真实会话的印象。我也尝试了流的线程,它确实有效。但是我必须做错了,因为在线程打印命令响应后进程终止。
答案 2 :(得分:0)
以下是我的终端的代码,分为两部分。我正在谈论的代码位于VK.ENTER键的switch语句中。
NB。如果要更改目录,它将仅适用于absoulute路径。例如用户目录中的“cd C:// Users / Aubrey /”而不是“cd / Aubrey”!!!
/*
* Terminal.java - A convienence console.
*
* http://www.splashportal.net
* 30/09/2012
*/
package terminal;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import javax.swing.JScrollPane;
public class Terminal extends Canvas
{
static final long serialVersionUID = 5479170142892558288L;
public static int WIDTH = 80, HEIGHT = 200;
static Process process;
public static final Color
WHITE = new Color(0xffffff),
RED = new Color(0xff0000),
GREEN = new Color(0x00cc00),
BROWN = new Color(0x996600),
BLUE = new Color(0x0000ff),
DARK_GREEN = new Color(0x009900),
DARK_BLUE = new Color(0x000099),
LIGHT_GREY = new Color(0x999999),
DARK_GREY = new Color(0x666666),
CYAN = new Color(0x00ffff),
DARK_CYAN = new Color(0x009999),
DARK_YELLOW = new Color(0x999900),
MAGENTA = new Color(0xff00ff),
YELLOW = new Color(0xffff00),
PURPLE = new Color(0x990099),
BLACK = new Color(0x000000);
private static final Color[] COLORS = {
WHITE , // 0 @
RED , // 1 A
GREEN , // 2 B
BROWN , // 3 C
BLUE , // 4 D
DARK_GREEN , // 5 E
DARK_BLUE , // 6 F
LIGHT_GREY , // 7 G
DARK_GREY , // 8 H
CYAN , // 9 I
DARK_CYAN , // 10 J
DARK_YELLOW , // 11 K
MAGENTA , // 12 L
YELLOW , // 13 M
PURPLE , // 14 N
BLACK , // 15 O
};
public static final int EFFECTS_UNDERLINE = 1;
private static final int
ESC_NORMAL = 0,
ESC_ESCAPE = 1,
ESC_POS_Y = 2,
ESC_POS_X = 3,
ESC_FGCOLOR = 4,
ESC_BGCOLOR = 5;
static boolean isBreak=false;
static int heightCounter;
static ArrayList lines;
static Terminal term;
static Frame f;
static File startPath;
public static Color getColor(int i)
{
return COLORS[i & 0x0f];
}
static String newPath = System.getenv("temp");
public static void main(String[] args)
{
f = new Frame("Terminal Test");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
f.dispose();
}
} );
term = new Terminal();
//add buffer_ image to a scrollpane somehow?
scrollPane = new ScrollPane();
scrollPane.add(term, buffer_);
// disabling forward focus traversal allows TAB to reach the component
term.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
Collections.EMPTY_SET);
term.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
// handle special keys
switch(ke.getKeyCode()) {
case KeyEvent.VK_UP:
term.print("\033A");
term.repaint();
break;
case KeyEvent.VK_DOWN:
term.print("\033B");
term.repaint();
break;
case KeyEvent.VK_RIGHT:
term.print("\033C");
term.repaint();
break;
case KeyEvent.VK_LEFT:
term.print("\033D");
term.repaint();
break;
case KeyEvent.VK_ENTER:
//flag set to block printing of ">>" prompt
isR=true;
try{
String currentLine = getCurrentLine();
ArrayList<String>command = new ArrayList<String>();
command.add("cmd.exe");
command.add("/c");
command.add(currentLine);
System.out.println("Line-IN: "+currentLine);
ProcessBuilder builder = new ProcessBuilder(command);
Map<String, String> environ = builder.environment();
if (currentLine.startsWith("cd")){
//startPath = new File(".").getAbsoluteFile();
//if an absolute path is specified and exists
if(new File(currentLine.substring(3)).exists())
newPath=currentLine.substring(3);
System.out.println("Directory : "+new File(newPath));
builder.directory(new File(newPath));
process = builder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
InputStream errorStream = process.getErrorStream();
InputStreamReader errorStreamReader = new InputStreamReader(errorStream);
BufferedReader buffErrorStreamReader = new BufferedReader(errorStreamReader);
String line;
//term.println("");
while ((line = br.readLine()) != null) {
System.out.println(line);
term.println(line);
}
String errorLine;
term.println("");
while ((errorLine = buffErrorStreamReader.readLine()) != null) {
//System.out.println(line);
term.println(errorLine);
}
buffErrorStreamReader.close();
br.close();
//not sure how to use this method to allow for an interactive prompt?
//for example a "dir /p" command should allow the output to be paged per keypress!
process.waitFor();
//flags set to allow printing of ">>" prompt
isR=false;
isNew=true;
System.out.println("Program terminated!");
}else if(currentLine.startsWith("exit")||currentLine.startsWith("quit")){
System.exit(0);
}else if(currentLine.startsWith("dir /p")){
//try using dos batch?
System.out.println("page...");
command = new ArrayList<String>();
command.add("cmd.exe");
command.add("dir");
builder.directory(new File(newPath));
process = builder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
//write out to a FLAT FILE.
File temp = new File("temp");
PrintWriter tempOut = new PrintWriter(new FileWriter(temp));
while ((line = br.readLine()) != null) {
System.out.println(line);
tempOut.println(line);
}
//not sure how to use this method to allow for an interactive prompt?
//for example a "dir /p" command should allow the output to be paged per keypress!
process.waitFor();
//flags set to allow printing of ">>" prompt
br.close();
tempOut.flush();
tempOut.close();
captureLines();
int index = 0;
printPage(index);
isR=false;
isNew=true;
System.out.println("Program terminated!");
}else
{
builder.directory(new File(newPath));
process = builder.start();
Thread t = new Thread() {
public void run() {
try{
System.out.println("blah");
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
InputStream errorStream = process.getErrorStream();
InputStreamReader errorStreamReader = new InputStreamReader(errorStream);
BufferedReader buffErrorStreamReader = new BufferedReader(errorStreamReader);
String line;
//term.println("");
while ((line = br.readLine()) != null) {
//System.out.println(line);
term.println(line);
}
String errorLine;
//term.println("");
while ((errorLine = buffErrorStreamReader.readLine()) != null) {
//System.out.println(line);
term.println(errorLine);
}
buffErrorStreamReader.close();
br.close();
//not sure how to use this method to allow for an interactive prompt?
//for example a "dir /p" command should allow the output to be paged per keypress!
process.waitFor();
//flags set to allow printing of ">>" prompt
isR=false;
isNew=true;
term.println("");
}catch(Exception e){System.out.println(e);}
}
};
t.start();
System.out.println("Program terminated!");
}
}catch(Exception e){System.out.println(e);}
}
}
public void keyTyped(KeyEvent ke) {
char c = ke.getKeyChar();
if( c == KeyEvent.CHAR_UNDEFINED ) {
// handle special keys
switch(ke.getKeyCode()) {
case KeyEvent.VK_TAB:
c = '\t';
break;
case KeyEvent.VK_ESCAPE:
c = (char)27;
break;
}
}
if( c != KeyEvent.CHAR_UNDEFINED ) {
term.print(c);
term.repaint();
}
}
} );
f.add(scrollPane, BorderLayout.CENTER);
term.validate();
scrollPane.setSize(598, 316);
//f.setSize(700, 400);
f.pack();
f.setVisible(true);
term.println(DARK_GREY, WHITE, "vTerminal");
//term.println(DARK_GREY, WHITE, ">>");
term.requestFocus();
}
private int tileWidth_ = 8;
private int tileHeight_ = 12;
private static TerminalLine[] line_;
private int xCursor_;
private static int yCursor_;
private int xCursorSave_;
private int yCursorSave_;
private boolean wrap_ = true;
private boolean scroll_ = true;
private boolean cursorVisible_ = true;
private int tab_ = 8;
private int xOffset_ = 0;
private int yOffset_ = 0;
private int escapeMode_ = ESC_NORMAL;
/** First character held in an ESC Y Position Cursor command. */
private int escapeHold_ = -1;
private boolean reverseVideo_;
private byte effects_;
private static Image buffer_;
private static ScrollPane scrollPane;
private static Boolean isNew = false;
private static Boolean isR = false;
答案 3 :(得分:0)
//工作代码的第二部分
/** Creates a new terminal. */
public Terminal()
{
line_ = new TerminalLine[HEIGHT];
for(int y = 0; y < HEIGHT; ++y) {
line_[y] = new TerminalLine(WIDTH);
}
setBackground(DARK_GREY);
setForeground(LIGHT_GREY);
setFont( new Font("Monospaced", Font.PLAIN, 12) );
clearScreen();
}
public static void captureLines(){
String line;
try{
heightCounter=Terminal.HEIGHT;
BufferedReader tempIn = new BufferedReader(new FileReader("temp"));
term.println("");
lines = new ArrayList();
while((line = tempIn.readLine())!=null)
{
lines.add(line);
}
tempIn.close();
}catch(Exception e){System.out.println(e);}
return;
}
public static void printPage(int index){
try{
if(index<lines.size()){
for (int i=0; i<25; i++){
if(index==lines.size())
return;
//System.out.println(index+" "+lines.get(index));
term.println(lines.get(index).toString());
index++;
}Thread.sleep(500);
printPage(index);
}else{return;}
}catch(Exception e){System.out.println(e);}
}
public static String getCurrentLine(){
TerminalLine currentLine = line_[getYCursor()];
String command="";
for(char c: currentLine.data){
command+= c;
}
String outString = command.substring(2);
return (outString.trim());
}
public synchronized void clearScreen()
{
for(int y = 0; y < HEIGHT; ++y) {
clearLine(y);
}
repaint();
}
public synchronized void clearLine(int line)
{
clearLine(line, 0, WIDTH-1);
}
public synchronized void clearLine(int y, int x0, int x1)
{
Color bg = getBackground();
Color fg = getForeground();
TerminalLine line = line_[y];
for(int x = x0; x <= x1; ++x) {
line.data[x] = ' ';
line.bgColor[x] = bg;
line.fgColor[x] = fg;
line.effects[x] = 0;
}
}
public synchronized boolean getCursorVisible()
{ return cursorVisible_; }
public synchronized char getData(int x, int y)
{
return line_[y].data[x];
}
public synchronized Color getBgColor(int x, int y)
{
return line_[y].bgColor[x];
}
public synchronized byte getEffects(int x, int y)
{
return line_[y].effects[x];
}
public synchronized Color getFgColor(int x, int y)
{
return line_[y].fgColor[x];
}
public synchronized Dimension getMaximumSize()
{
return getPreferredSize();
}
public synchronized Dimension getMinimumSize()
{
return getPreferredSize();
}
public synchronized Dimension getPreferredSize()
{
return new Dimension(WIDTH * tileWidth_, HEIGHT * tileHeight_);
}
public boolean getReverseVideo()
{ return reverseVideo_; }
public synchronized boolean getScroll()
{ return scroll_; }
public synchronized int getTab()
{ return tab_; }
public int getTileWidth()
{ return tileWidth_; }
public int getTileHeight()
{ return tileHeight_; }
public synchronized int getXOffset()
{ return xOffset_; }
public synchronized int getYOffset()
{ return yOffset_; }
public synchronized int getXCursor()
{ return xCursor_; }
public static synchronized int getYCursor()
{ return yCursor_; }
public synchronized void gotoxy(int x, int y)
{
xCursor_ = x;
yCursor_ = y;
}
public synchronized void print(String s)
{
print(null, null, s);
}
public synchronized void print(Color bg, Color fg, String s)
{
for(int i = 0, len = s.length(); i < len; ++i) {
print(bg, fg, s.charAt(i) );
}
repaint();
}
public synchronized void print(char c)
{
print(null, null, c);
}
public synchronized void print(Color bg, Color fg, char c)
{
if( escapeMode_ == ESC_NORMAL ) {
switch(c) {
case 7: // 7 = BEL, bell
bell();
break;
case '\b': // 8 = BS, backspace
--xCursor_;
break;
case '\t': // 9 = HT, tab
xCursor_ = ((xCursor_ + tab_) / tab_) * tab_;
break;
case '\n': // 10 = LF, newline
xCursor_ = 0;
++yCursor_;
//flag set to allow printing of ">>" prompt
isNew=true;
break;
case 11: // 11 = VT, vertical tab
case '\f': // 12 = FF, form feed
++yCursor_;
break;
case '\r': // 13 = CR, ignored because Java's newline is \n
break;
case 27: // 27 = ESC, enters escape mode
escapeMode_ = ESC_ESCAPE;
break;
case 127: { // 127 = DEL, right-delete
int yc = yCursor_;
TerminalLine line = line_[yc];
for(int x = xCursor_; x < WIDTH-1; ++x) {
line.setData(x, line.bgColor[x+1], line.fgColor[x+1],
line.data[x+1], line.effects[x+1] );
}
setData(WIDTH-1, yc, null, null, ' ');
break;
}
default:
if( c < 32 ) {
// unknown control character
bell();
} else {
setData(xCursor_, yCursor_, bg, fg, c);
++xCursor_;
}
}
} else {
escapeMode_ = doEscape(c);
}
// wrap cursor
if( xCursor_ < 0 ) {
if( wrap_ ) {
xCursor_ = WIDTH-1;
--yCursor_;
} else {
xCursor_ = 0;
}
} else if( xCursor_ >= WIDTH ) {
if( wrap_ ) {
xCursor_ = 0;
++yCursor_;
} else {
xCursor_ = WIDTH-1;
}
}
if( yCursor_ < 0 ) {
if( scroll_ ) {
scrollDown(0);
}
yCursor_ = 0;
} else if( yCursor_ >= HEIGHT ) {
if( scroll_ ) {
scrollUp(0);
}
yCursor_ = HEIGHT-1;
}
//cool flags here to print ">>" prompt: 1. when there is new line and 2. when the isR flag has detected the end of printing in the return event.
if(isR){
isNew=false;
}
if(isNew){
isNew=false;
print(DARK_GREY, YELLOW, ">>");
}
}
public synchronized void scrollDown(int topline)
{
// scroll down, exposing a blank line at top
// don't waste the existing array, recycle it.
TerminalLine line0 = line_[HEIGHT-1];
// move all lines down
for(int y = HEIGHT-1; y > topline; --y) {
line_[y] = line_[y-1];
}
// put it at the top
line_[topline] = line0;
clearLine(topline);
}
public synchronized void scrollUp(int topline)
{
// scroll up, exposing a blank line at bottom
// don't waste the existing array, recycle it.
TerminalLine line0 = line_[topline];
// move all lines up
for(int y = topline; y < HEIGHT-1; ++y) {
line_[y] = line_[y+1];
}
// put it at the end
line_[HEIGHT-1] = line0;
clearLine(HEIGHT-1);
}
private int doEscape(char c)
{
switch(escapeMode_) {
case ESC_NORMAL:
throw new IllegalStateException();
case ESC_ESCAPE:
// handled below
break;
case ESC_POS_Y:
escapeHold_ = Math.max(0, Math.min(HEIGHT-1, (int)(c - 32)));
return ESC_POS_X;
case ESC_POS_X:
yCursor_ = escapeHold_;
xCursor_ = Math.max(0, Math.min(WIDTH-1, (int)(c - 32)));
return ESC_NORMAL;
case ESC_FGCOLOR:
setForeground( getColor( (int)c ) );
return ESC_NORMAL;
case ESC_BGCOLOR:
setBackground( getColor( (int)c ) );
return ESC_NORMAL;
default:
throw new IllegalStateException("Unknown escape mode "+escapeMode_);
}
switch(c) {
case 24: // 24 = CAN, cancel escape
case 26: // 26 = SUB, cancel escape
case 27: // 27 = ESC, cancel escape
return ESC_NORMAL;
case 'A': // Cursor Up
if( yCursor_ > 0 ) {
--yCursor_;
}
return ESC_NORMAL;
case 'B': // Cursor Down
if( yCursor_ < HEIGHT-1 ) {
++yCursor_;
}
return ESC_NORMAL;
case 'C': // Cursor Forward
if( xCursor_ < WIDTH-1 ) {
++xCursor_;
}
return ESC_NORMAL;
case 'D': // Cursor Backward
if( xCursor_ > 0 ) {
--xCursor_;
}
return ESC_NORMAL;
case 'E': // Clear Screen, Home Cursor
clearScreen();
xCursor_ = 0;
yCursor_ = 0;
return ESC_NORMAL;
case 'H': // Home Cursor
xCursor_ = 0;
yCursor_ = 0;
return ESC_NORMAL;
case 'I': // Reverse Index
--yCursor_;
return ESC_NORMAL;
case 'J': // Erase to End of Page
clearLine(yCursor_, xCursor_, WIDTH-1);
for(int y = yCursor_+1; y < HEIGHT; ++y) {
clearLine(y);
}
return ESC_NORMAL;
case 'K': // Erase to End of Line
clearLine(yCursor_, xCursor_, WIDTH-1);
return ESC_NORMAL;
case 'L': // Insert Line
scrollDown(yCursor_);
xCursor_ = 0;
return ESC_NORMAL;
case 'M': // Delete Line
scrollUp(yCursor_);
xCursor_ = 0;
return ESC_NORMAL;
case 'N': { // Delete Character
int yc = yCursor_;
TerminalLine line = line_[yc];
for(int x = xCursor_; x < WIDTH-1; ++x) {
line.setData(x, line.bgColor[x+1], line.fgColor[x+1],
line.data[x+1], line.effects[x+1] );
}
setData(WIDTH-1, yc, null, null, ' ');
break;
}
case 'Y': // Position Cursor
return ESC_POS_Y;
case 'b': // Set Foreground Color
return ESC_FGCOLOR;
case 'c': // Set Background Color
return ESC_BGCOLOR;
case 'd': { // Erase from Beginning of Display
int xc = xCursor_, yc = yCursor_;
clearLine(yc, 0, xc);
for(int y = 0; y < yc; ++y) {
clearLine(y);
}
return ESC_NORMAL;
}
case 'j': // Save Cursor Position
xCursorSave_ = xCursor_;
yCursorSave_ = yCursor_;
return ESC_NORMAL;
case 'k': // Restore Cursor Position
xCursor_ = xCursorSave_;
yCursor_ = yCursorSave_;
return ESC_NORMAL;
case 'l': // Erase Entire Line
clearLine(yCursor_);
xCursor_ = 0;
return ESC_NORMAL;
case 'm': // Enable Cursor
cursorVisible_ = true;
return ESC_NORMAL;
case 'n': // Disable Cursor
cursorVisible_ = false;
return ESC_NORMAL;
case 'o': // Erase from Beginning of Line
clearLine(yCursor_, 0, xCursor_);
return ESC_NORMAL;
case 'p': // Enable Reverse Video
reverseVideo_ = true;
return ESC_NORMAL;
case 'q': // Disable Reverse Video
reverseVideo_ = false;
return ESC_NORMAL;
case 'r': // Enable Underlining
effects_ |= EFFECTS_UNDERLINE;
return ESC_NORMAL;
case 'u': // Disable Underlining
effects_ &= ~EFFECTS_UNDERLINE;
return ESC_NORMAL;
case 'v': // Enable Wrapping
wrap_ = true;
return ESC_NORMAL;
case 'w': // Disable Wrapping
wrap_ = false;
return ESC_NORMAL;
}
// unknown escape code
bell();
return ESC_NORMAL;
}
public synchronized void println(String s)
{
println(null, null, s);
}
public synchronized void println(Color bg, Color fg, String s)
{
print(bg, fg, s);
print(bg, fg, '\n');
repaint();
}
public synchronized void setCursorVisible(boolean c)
{ cursorVisible_ = c; }
public synchronized void setData(int x, int y, char c)
{
setData(x, y, null, null, c);
}
public synchronized void setData(int x, int y, Color bg, Color fg, char c)
{
setData(x, y, bg, fg, c, effects_);
}
public synchronized void setData(int x, int y, Color bg, Color fg, char c, byte effects)
{
if( bg == null ) {
bg = getBackground();
}
if( fg == null ) {
fg = getForeground();
}
if( reverseVideo_ ) {
Color tmp = bg;
bg = fg;
fg = tmp;
}
TerminalLine line = line_[y];
line.data[x] = c;
line.bgColor[x] = bg;
line.fgColor[x] = fg;
line.effects[x] = effects;
}
public synchronized void setBgColor(int x, int y, Color b)
{
line_[y].bgColor[x] = b;
}
public synchronized void setEffects(int x, int y, byte e)
{
line_[y].effects[x] = e;
}
public synchronized void setFgColor(int x, int y, Color f)
{
line_[y].fgColor[x] = f;
}
public void setFont(Font font)
{
super.setFont(font);
FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
tileWidth_ = fm.charWidth('W');
tileHeight_ = fm.getHeight() - fm.getDescent();
xOffset_ = 0;
yOffset_ = -fm.getDescent();
//System.out.println("tile "+tileWidth_+"x"+tileHeight_+", offset="+xOffset_+","+yOffset_);
}
public void setReverseVideo(boolean r)
{ reverseVideo_ = r; }
public synchronized void setScroll(boolean s)
{ scroll_ = s; }
public synchronized void setTab(int t)
{ tab_ = t; }
public void setTileSize(int w, int h)
{
tileWidth_ = w;
tileHeight_ = h;
buffer_ = null;
}
public synchronized void setXOffset(int x)
{ xOffset_ = x; }
public synchronized void setYOffset(int y)
{ yOffset_ = y; }
public synchronized void setXCursor(int x)
{ xCursor_ = x; }
public synchronized void setYCursor(int y)
{ yCursor_ = y; }
public synchronized void paint(Graphics g)
{
if( buffer_ != null ) {
g.drawImage(buffer_, 0, 0, null);
}
}
public synchronized void update(Graphics gg)
{
if( buffer_ == null ) {
Dimension d = getPreferredSize();
buffer_ = createImage(d.width, d.height);
if( buffer_ == null ) {
repaint(100L); //wtf?
return;
}
}
Graphics g = buffer_.getGraphics();
g.setFont( getFont() );
FontMetrics fm = g.getFontMetrics();
char[] cbuf = new char[1]; // for drawChars
for(int y = 0; y < HEIGHT; ++y) {
int sy = y * tileHeight_;
TerminalLine line = line_[y];
for(int x = 0; x < WIDTH; ++x) {
int sx = x * tileWidth_;
// background
g.setColor( line.bgColor[x] );
g.fillRect(sx, sy, tileWidth_, tileHeight_);
// character
g.setColor( line.fgColor[x] );
cbuf[0] = line.data[x];
g.drawChars(cbuf, 0, 1, sx + xOffset_,
sy + fm.getAscent() + yOffset_);
// effects
if( (line.effects[x] & EFFECTS_UNDERLINE) != 0 ) {
g.drawLine(sx, sy+tileHeight_-1,
sx+tileWidth_-1, sy+tileHeight_-1);
}
// borders for testing
//g.drawLine(sx, sy, sx+tileWidth_-1, sy);
//g.drawLine(sx, sy, sx, sy+tileHeight_-1);
}
}
if( cursorVisible_ ) {
Color bg = getBgColor(xCursor_, yCursor_);
if( bg == BLACK ) {
bg = WHITE;
}
g.setXORMode(bg);
g.fillRect(xCursor_ * tileWidth_, yCursor_ * tileHeight_,
tileWidth_, tileHeight_);
g.setPaintMode();
}
paint(gg);
}
}
class TerminalLine
{
public Color[] bgColor;
public Color[] fgColor;
public char[] data;
public byte[] effects;
public TerminalLine(int width)
{
bgColor = new Color[width];
fgColor = new Color[width];
data = new char[width];
effects = new byte[width];
}
public void setData(int x, Color bg, Color fg, char c, byte e)
{
data[x] = c;
bgColor[x] = bg;
fgColor[x] = fg;
effects[x] = e;
}
}