import jexer.bits.Color;
import jexer.bits.Cell;
import jexer.bits.CellAttributes;
+import jexer.io.ReadTimeoutException;
+import jexer.io.TimeoutInputStream;
import static jexer.TKeypress.*;
/**
- * This implements a complex ANSI ECMA-48/ISO 6429/ANSI X3.64 type consoles,
+ * This implements a complex ECMA-48/ISO 6429/ANSI X3.64 type console,
* including a scrollback buffer.
*
* <p>
return "\033[?6c";
case VT220:
+ case XTERM:
// "I am a VT220" - 7 bit version
if (!s8c1t) {
return "\033[?62;1;6c";
}
// "I am a VT220" - 8 bit version
return "\u009b?62;1;6c";
- case XTERM:
- // "I am a VT100 with advanced video option" (often VT102)
- return "\033[?1;2c";
default:
throw new IllegalArgumentException("Invalid device type: " + type);
}
*/
public final void close() {
- // Synchronize so we don't stomp on the reader thread.
- synchronized (this) {
-
- // Close the input stream
- switch (type) {
- case VT100:
- case VT102:
- case VT220:
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- // SQUASH
- }
- inputStream = null;
- }
- break;
- case XTERM:
- if (input != null) {
- try {
- input.close();
- } catch (IOException e) {
- // SQUASH
- }
- input = null;
- inputStream = null;
- }
- break;
+ // Tell the reader thread to stop looking at input. It will close
+ // the input streams.
+ if (stopReaderThread == false) {
+ stopReaderThread = true;
+ try {
+ readerThread.join(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
}
+ }
- // Tell the reader thread to stop looking at input.
- if (stopReaderThread == false) {
- stopReaderThread = true;
+ // Now close the output stream.
+ switch (type) {
+ case VT100:
+ case VT102:
+ case VT220:
+ if (outputStream != null) {
try {
- readerThread.join();
- } catch (InterruptedException e) {
- e.printStackTrace();
+ outputStream.close();
+ } catch (IOException e) {
+ // SQUASH
}
+ outputStream = null;
}
-
- // Close the output stream.
- switch (type) {
- case VT100:
- case VT102:
- case VT220:
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- // SQUASH
- }
- outputStream = null;
+ break;
+ case XTERM:
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ // SQUASH
}
- break;
- case XTERM:
- if (output != null) {
- try {
- output.close();
- } catch (IOException e) {
- // SQUASH
- }
- output = null;
+ outputStream = null;
+ }
+ if (output != null) {
+ try {
+ output.close();
+ } catch (IOException e) {
+ // SQUASH
}
- break;
- default:
- throw new IllegalArgumentException("Invalid device type: "
- + type);
+ output = null;
}
- } // synchronized (this)
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid device type: " +
+ type);
+ }
}
/**
/**
* The terminal's raw InputStream. This is used for type != XTERM.
*/
- private volatile InputStream inputStream;
+ private volatile TimeoutInputStream inputStream;
/**
* The terminal's output. For type == XTERM, this wraps an
display = new LinkedList<DisplayLine>();
this.type = type;
- this.inputStream = inputStream;
+ if (inputStream instanceof TimeoutInputStream) {
+ this.inputStream = (TimeoutInputStream)inputStream;
+ } else {
+ this.inputStream = new TimeoutInputStream(inputStream, 2000);
+ }
if (type == DeviceType.XTERM) {
- this.input = new InputStreamReader(inputStream, "UTF-8");
+ this.input = new InputStreamReader(this.inputStream, "UTF-8");
this.output = new OutputStreamWriter(outputStream, "UTF-8");
this.outputStream = null;
} else {
*/
private void dsr() {
boolean decPrivateModeFlag = false;
+ int row = currentState.cursorY;
for (int i = 0; i < collectBuffer.length(); i++) {
if (collectBuffer.charAt(i) == '?') {
case 6:
// Request cursor position. Respond with current position.
+ if (currentState.originMode == true) {
+ row -= scrollRegionTop;
+ }
String str = "";
if (((type == DeviceType.VT220) || (type == DeviceType.XTERM))
&& (s8c1t == true)
) {
- str = String.format("\u009b%d;%dR",
- currentState.cursorY + 1, currentState.cursorX + 1);
+ str = String.format("\u009b%d;%dR", row + 1,
+ currentState.cursorX + 1);
} else {
- str = String.format("\033[%d;%dR",
- currentState.cursorY + 1, currentState.cursorX + 1);
+ str = String.format("\033[%d;%dR", row + 1,
+ currentState.cursorX + 1);
}
// Send string directly to remote side
while (!done && !stopReaderThread) {
try {
int n = inputStream.available();
+
// System.err.printf("available() %d\n", n); System.err.flush();
if (utf8) {
if (readBufferUTF8.length < n) {
// The buffer wasn't big enough, make it huger
- int newSizeHalf = Math.max(readBufferUTF8.length, n);
+ int newSizeHalf = Math.max(readBufferUTF8.length,
+ n);
readBufferUTF8 = new char[newSizeHalf * 2];
}
readBuffer = new byte[newSizeHalf * 2];
}
}
+ if (n == 0) {
+ try {
+ Thread.sleep(2);
+ } catch (InterruptedException e) {
+ // SQUASH
+ }
+ continue;
+ }
int rc = -1;
- if (utf8) {
- rc = input.read(readBufferUTF8, 0,
- readBufferUTF8.length);
- } else {
- rc = inputStream.read(readBuffer, 0,
- readBuffer.length);
+ try {
+ if (utf8) {
+ rc = input.read(readBufferUTF8, 0,
+ readBufferUTF8.length);
+ } else {
+ rc = inputStream.read(readBuffer, 0,
+ readBuffer.length);
+ }
+ } catch (ReadTimeoutException e) {
+ rc = 0;
}
+
// System.err.printf("read() %d\n", rc); System.err.flush();
if (rc == -1) {
// This is EOF
} else {
ch = readBuffer[i];
}
- // Don't step on UI events
+
synchronized (this) {
+ // Don't step on UI events
consume((char)ch);
}
}
e.printStackTrace();
done = true;
}
+
} // while ((done == false) && (stopReaderThread == false))
// Let the rest of the world know that I am done.
stopReaderThread = true;
+ try {
+ inputStream.cancelRead();
+ inputStream.close();
+ inputStream = null;
+ } catch (IOException e) {
+ // SQUASH
+ }
+ try {
+ input.close();
+ input = null;
+ } catch (IOException e) {
+ // SQUASH
+ }
+
// System.err.println("*** run() exiting..."); System.err.flush();
}