X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Ftterminal%2FECMA48.java;h=d148b39ba00e8d88d906bb9b998e73564903229b;hb=3633816889a62bb395ff68f9219dcd26d600c870;hp=41a5f4dc6a23ca2edcfd93689bd084b83ceea446;hpb=34a42e784bf1238c6bb2847c52d7c841fcfdef5f;p=fanfix.git diff --git a/src/jexer/tterminal/ECMA48.java b/src/jexer/tterminal/ECMA48.java index 41a5f4d..d148b39 100644 --- a/src/jexer/tterminal/ECMA48.java +++ b/src/jexer/tterminal/ECMA48.java @@ -43,10 +43,11 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import jexer.TKeypress; +import jexer.event.TMouseEvent; import jexer.bits.Color; import jexer.bits.Cell; import jexer.bits.CellAttributes; -import jexer.TKeypress; import static jexer.TKeypress.*; /** @@ -58,6 +59,11 @@ import static jexer.TKeypress.*; * caveats: * *

+ * - The vttest scenario for VT220 8-bit controls (11.1.2.3) reports a + * failure with XTERM. This is due to vttest failing to decode the UTF-8 + * stream. + * + *

* - Smooth scrolling, printing, keyboard locking, keyboard leds, and tests * from VT100 are not supported. * @@ -142,24 +148,26 @@ public class ECMA48 implements Runnable { /** * Return the proper TERM environment variable for this device type. * - * @return "TERM=vt100", "TERM=xterm", etc. + * @param deviceType DeviceType.VT100, DeviceType, XTERM, etc. + * @return "vt100", "xterm", etc. */ - public String deviceTypeTerm() { - switch (type) { + public static String deviceTypeTerm(final DeviceType deviceType) { + switch (deviceType) { case VT100: - return "TERM=vt100"; + return "vt100"; case VT102: - return "TERM=vt102"; + return "vt102"; case VT220: - return "TERM=vt220"; + return "vt220"; case XTERM: - return "TERM=xterm"; + return "xterm"; default: - throw new IllegalArgumentException("Invalid device type: " + type); + throw new IllegalArgumentException("Invalid device type: " + + deviceType); } } @@ -168,27 +176,27 @@ public class ECMA48 implements Runnable { * about UTF-8, the others are defined by their standard to be either * 7-bit or 8-bit characters only. * + * @param deviceType DeviceType.VT100, DeviceType, XTERM, etc. * @param baseLang a base language without UTF-8 flag such as "C" or * "en_US" * @return "LANG=en_US", "LANG=en_US.UTF-8", etc. */ - public String deviceTypeLang(final String baseLang) { - switch (type) { + public static String deviceTypeLang(final DeviceType deviceType, + final String baseLang) { - case VT100: - return "LANG=" + baseLang; + switch (deviceType) { + case VT100: case VT102: - return "LANG=" + baseLang; - case VT220: - return "LANG=" + baseLang; + return baseLang; case XTERM: - return "LANG=" + baseLang + ".UTF-8"; + return baseLang + ".UTF-8"; default: - throw new IllegalArgumentException("Invalid device type: " + type); + throw new IllegalArgumentException("Invalid device type: " + + deviceType); } } @@ -249,8 +257,34 @@ public class ECMA48 implements Runnable { // Synchronize so we don't stomp on the reader thread. synchronized (this) { - // Tell the reader thread to stop looking at input. It will - // close the input stream as it exits. + // 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. if (stopReaderThread == false) { stopReaderThread = true; try { @@ -294,7 +328,7 @@ public class ECMA48 implements Runnable { /** * When true, the reader thread is expected to exit. */ - private boolean stopReaderThread = false; + private volatile boolean stopReaderThread = false; /** * The reader thread. @@ -329,7 +363,7 @@ public class ECMA48 implements Runnable { /** * The scrollback buffer characters + attributes. */ - private List scrollback; + private volatile List scrollback; /** * Get the scrollback buffer. @@ -343,7 +377,7 @@ public class ECMA48 implements Runnable { /** * The raw display buffer characters + attributes. */ - private List display; + private volatile List display; /** * Get the display buffer. @@ -467,6 +501,35 @@ public class ECMA48 implements Runnable { G3_GL } + /** + * XTERM mouse reporting protocols. + */ + private enum MouseProtocol { + OFF, + X10, + NORMAL, + BUTTONEVENT, + ANYEVENT + } + + /** + * Which mouse protocol is active. + */ + private MouseProtocol mouseProtocol = MouseProtocol.OFF; + + /** + * XTERM mouse reporting encodings. + */ + private enum MouseEncoding { + X10, + UTF8 + } + + /** + * Which mouse encoding is active. + */ + private MouseEncoding mouseEncoding = MouseEncoding.X10; + /** * Physical display width. We start at 80x24, but the user can resize us * bigger/smaller. @@ -572,12 +635,6 @@ public class ECMA48 implements Runnable { return screenTitle; } - /** - * Array of flags that have come in, e.g. '?' (DEC private mode), '=', - * '>' (<), ... - */ - private List csiFlags; - /** * Parameter characters being collected. */ @@ -586,7 +643,7 @@ public class ECMA48 implements Runnable { /** * Non-csi collect buffer. */ - private List collectBuffer; + private StringBuilder collectBuffer; /** * When true, use the G1 character set. @@ -770,8 +827,7 @@ public class ECMA48 implements Runnable { */ private void toGround() { csiParams.clear(); - csiFlags.clear(); - collectBuffer.clear(); + collectBuffer = new StringBuilder(8); scanState = ScanState.GROUND; } @@ -818,6 +874,10 @@ public class ECMA48 implements Runnable { s8c1t = false; printerControllerMode = false; + // XTERM + mouseProtocol = MouseProtocol.OFF; + mouseEncoding = MouseEncoding.X10; + // Tab stops resetTabStops(); @@ -845,9 +905,7 @@ public class ECMA48 implements Runnable { assert (inputStream != null); assert (outputStream != null); - csiFlags = new ArrayList(); csiParams = new ArrayList(); - collectBuffer = new ArrayList(); tabStops = new ArrayList(); scrollback = new LinkedList(); display = new LinkedList(); @@ -1031,6 +1089,98 @@ public class ECMA48 implements Runnable { } } + /** + * Translate the mouse event to a VT100, VT220, or XTERM sequence and + * send to the remote side. + * + * @param mouse mouse event received from the local user + */ + public void mouse(final TMouseEvent mouse) { + + /* + System.err.printf("mouse(): protocol %s encoding %s mouse %s\n", + mouseProtocol, mouseEncoding, mouse); + */ + + if (mouseEncoding != MouseEncoding.UTF8) { + // We will support X10 but only for (160,94) and smaller. + if ((mouse.getX() >= 160) || (mouse.getY() >= 94)) { + return; + } + } + + switch (mouseProtocol) { + + case OFF: + // Do nothing + return; + + case X10: + // Only report button presses + if (mouse.getType() != TMouseEvent.Type.MOUSE_DOWN) { + return; + } + break; + + case NORMAL: + // Only report button presses and releases + if ((mouse.getType() != TMouseEvent.Type.MOUSE_DOWN) + && (mouse.getType() != TMouseEvent.Type.MOUSE_UP) + ) { + return; + } + break; + + case BUTTONEVENT: + /* + * Only report button presses, button releases, and motions that + * have a button down (i.e. drag-and-drop). + */ + if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { + if (!mouse.getMouse1() + && !mouse.getMouse2() + && !mouse.getMouse3() + && !mouse.getMouseWheelUp() + && !mouse.getMouseWheelDown() + ) { + return; + } + } + break; + + case ANYEVENT: + // Report everything + break; + } + + // Now encode the event + StringBuilder sb = new StringBuilder(6); + sb.append((char) 0x1B); + sb.append('['); + sb.append('M'); + if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { + sb.append((char) (0x03 + 32)); + } else if (mouse.getMouse1()) { + sb.append((char) (0x00 + 32)); + } else if (mouse.getMouse2()) { + sb.append((char) (0x01 + 32)); + } else if (mouse.getMouse3()) { + sb.append((char) (0x02 + 32)); + } else if (mouse.getMouseWheelUp()) { + sb.append((char) (0x04 + 64)); + } else if (mouse.getMouseWheelDown()) { + sb.append((char) (0x05 + 64)); + } else { + sb.append((char) (0x03 + 32)); + } + + sb.append((char) (mouse.getX() + 33)); + sb.append((char) (mouse.getY() + 33)); + + // System.err.printf("Would write: \'%s\'\n", sb.toString()); + writeRemote(sb.toString()); + } + /** * Translate the keyboard press to a VT100, VT220, or XTERM sequence and * send to the remote side. @@ -1907,7 +2057,7 @@ public class ECMA48 implements Runnable { * @param ch character to save */ private void collect(final char ch) { - collectBuffer.add(new Character(ch)); + collectBuffer.append(ch); } /** @@ -1974,9 +2124,10 @@ public class ECMA48 implements Runnable { */ private void setToggle(final boolean value) { boolean decPrivateModeFlag = false; - for (Character ch: collectBuffer) { - if (ch == '?') { + for (int i = 0; i < collectBuffer.length(); i++) { + if (collectBuffer.charAt(i) == '?') { decPrivateModeFlag = true; + break; } } @@ -2230,6 +2381,58 @@ public class ECMA48 implements Runnable { break; + case 1000: + if ((type == DeviceType.XTERM) + && (decPrivateModeFlag == true) + ) { + // Mouse: normal tracking mode + if (value == true) { + mouseProtocol = MouseProtocol.NORMAL; + } else { + mouseProtocol = MouseProtocol.OFF; + } + } + break; + + case 1002: + if ((type == DeviceType.XTERM) + && (decPrivateModeFlag == true) + ) { + // Mouse: normal tracking mode + if (value == true) { + mouseProtocol = MouseProtocol.BUTTONEVENT; + } else { + mouseProtocol = MouseProtocol.OFF; + } + } + break; + + case 1003: + if ((type == DeviceType.XTERM) + && (decPrivateModeFlag == true) + ) { + // Mouse: Any-event tracking mode + if (value == true) { + mouseProtocol = MouseProtocol.ANYEVENT; + } else { + mouseProtocol = MouseProtocol.OFF; + } + } + break; + + case 1005: + if ((type == DeviceType.XTERM) + && (decPrivateModeFlag == true) + ) { + // Mouse: UTF-8 coordinates + if (value == true) { + mouseEncoding = MouseEncoding.UTF8; + } else { + mouseEncoding = MouseEncoding.X10; + } + } + break; + default: break; @@ -2651,9 +2854,10 @@ public class ECMA48 implements Runnable { boolean honorProtected = false; boolean decPrivateModeFlag = false; - for (Character ch: collectBuffer) { - if (ch == '?') { + for (int i = 0; i < collectBuffer.length(); i++) { + if (collectBuffer.charAt(i) == '?') { decPrivateModeFlag = true; + break; } } @@ -2690,9 +2894,10 @@ public class ECMA48 implements Runnable { boolean honorProtected = false; boolean decPrivateModeFlag = false; - for (Character ch: collectBuffer) { - if (ch == '?') { + for (int i = 0; i < collectBuffer.length(); i++) { + if (collectBuffer.charAt(i) == '?') { decPrivateModeFlag = true; + break; } } @@ -3032,21 +3237,16 @@ public class ECMA48 implements Runnable { private void da() { int extendedFlag = 0; int i = 0; - Character [] chars = collectBuffer.toArray(new Character[0]); - StringBuilder args = new StringBuilder(); - for (int j = 1; j < chars.length; j++) { - args.append(chars[j]); - } - - if (chars.length > 0) { - if (chars[0] == '>') { + if (collectBuffer.length() > 0) { + String args = collectBuffer.substring(1); + if (collectBuffer.charAt(0) == '>') { extendedFlag = 1; - if (chars.length >= 2) { + if (collectBuffer.length() >= 2) { i = Integer.parseInt(args.toString()); } - } else if (chars[0] == '=') { + } else if (collectBuffer.charAt(0) == '=') { extendedFlag = 2; - if (chars.length >= 2) { + if (collectBuffer.length() >= 2) { i = Integer.parseInt(args.toString()); } } else { @@ -3107,17 +3307,31 @@ public class ECMA48 implements Runnable { * DECSTBM - Set top and bottom margins. */ private void decstbm() { - int top = getCsiParam(0, 1, 1, height) - 1; - int bottom = getCsiParam(1, height, 1, height) - 1; + boolean decPrivateModeFlag = false; - if (top > bottom) { - top = bottom; + for (int i = 0; i < collectBuffer.length(); i++) { + if (collectBuffer.charAt(i) == '?') { + decPrivateModeFlag = true; + break; + } } - scrollRegionTop = top; - scrollRegionBottom = bottom; + if (decPrivateModeFlag) { + // This could be restore DEC private mode values. + // Ignore it. + } else { + // DECSTBM + int top = getCsiParam(0, 1, 1, height) - 1; + int bottom = getCsiParam(1, height, 1, height) - 1; - // Home cursor - cursorPosition(0, 0); + if (top > bottom) { + top = bottom; + } + scrollRegionTop = top; + scrollRegionBottom = bottom; + + // Home cursor + cursorPosition(0, 0); + } } /** @@ -3185,9 +3399,10 @@ public class ECMA48 implements Runnable { private void dsr() { boolean decPrivateModeFlag = false; - for (Character ch: collectBuffer) { - if (ch == '?') { + for (int i = 0; i < collectBuffer.length(); i++) { + if (collectBuffer.charAt(i) == '?') { decPrivateModeFlag = true; + break; } } @@ -3394,9 +3609,10 @@ public class ECMA48 implements Runnable { */ private void printerFunctions() { boolean decPrivateModeFlag = false; - for (Character ch: collectBuffer) { - if (ch == '?') { + for (int i = 0; i < collectBuffer.length(); i++) { + if (collectBuffer.charAt(i) == '?') { decPrivateModeFlag = true; + break; } } @@ -3454,15 +3670,12 @@ public class ECMA48 implements Runnable { */ private void oscPut(final char xtermChar) { // Collect first - collectBuffer.add(new Character(xtermChar)); + collectBuffer.append(xtermChar); // Xterm cases... if (xtermChar == 0x07) { - Character [] chars = collectBuffer.toArray(new Character[0]); - StringBuilder args = new StringBuilder(); - for (int j = 0; j < chars.length - 1; j++) { - args.append(chars[j]); - } + String args = collectBuffer.substring(0, + collectBuffer.length() - 1); String [] p = args.toString().split(";"); if (p.length > 0) { if ((p[0].equals("0")) || (p[0].equals("2"))) { @@ -3934,150 +4147,150 @@ public class ECMA48 implements Runnable { if ((ch >= 0x30) && (ch <= 0x7E)) { switch (ch) { case '0': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> Special graphics currentState.g0Charset = CharacterSet.DRAWING; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> Special graphics currentState.g1Charset = CharacterSet.DRAWING; } if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> Special graphics currentState.g2Charset = CharacterSet.DRAWING; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> Special graphics currentState.g3Charset = CharacterSet.DRAWING; } } break; case '1': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> Alternate character ROM standard character set currentState.g0Charset = CharacterSet.ROM; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> Alternate character ROM standard character set currentState.g1Charset = CharacterSet.ROM; } break; case '2': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> Alternate character ROM special graphics currentState.g0Charset = CharacterSet.ROM_SPECIAL; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> Alternate character ROM special graphics currentState.g1Charset = CharacterSet.ROM_SPECIAL; } break; case '3': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '#')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '#')) { // DECDHL - Double-height line (top half) dechdl(true); } break; case '4': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '#')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '#')) { // DECDHL - Double-height line (bottom half) dechdl(false); } if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> DUTCH currentState.g0Charset = CharacterSet.NRC_DUTCH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> DUTCH currentState.g1Charset = CharacterSet.NRC_DUTCH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> DUTCH currentState.g2Charset = CharacterSet.NRC_DUTCH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> DUTCH currentState.g3Charset = CharacterSet.NRC_DUTCH; } } break; case '5': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '#')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '#')) { // DECSWL - Single-width line decswl(); } if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> FINNISH currentState.g0Charset = CharacterSet.NRC_FINNISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> FINNISH currentState.g1Charset = CharacterSet.NRC_FINNISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> FINNISH currentState.g2Charset = CharacterSet.NRC_FINNISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> FINNISH currentState.g3Charset = CharacterSet.NRC_FINNISH; } } break; case '6': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '#')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '#')) { // DECDWL - Double-width line decdwl(); } if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> NORWEGIAN currentState.g0Charset = CharacterSet.NRC_NORWEGIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> NORWEGIAN currentState.g1Charset = CharacterSet.NRC_NORWEGIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> NORWEGIAN currentState.g2Charset = CharacterSet.NRC_NORWEGIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> NORWEGIAN currentState.g3Charset = CharacterSet.NRC_NORWEGIAN; } @@ -4087,31 +4300,31 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> SWEDISH currentState.g0Charset = CharacterSet.NRC_SWEDISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> SWEDISH currentState.g1Charset = CharacterSet.NRC_SWEDISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> SWEDISH currentState.g2Charset = CharacterSet.NRC_SWEDISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> SWEDISH currentState.g3Charset = CharacterSet.NRC_SWEDISH; } } break; case '8': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '#')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '#')) { // DECALN - Screen alignment display decaln(); } @@ -4124,23 +4337,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> DEC_SUPPLEMENTAL currentState.g0Charset = CharacterSet.DEC_SUPPLEMENTAL; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> DEC_SUPPLEMENTAL currentState.g1Charset = CharacterSet.DEC_SUPPLEMENTAL; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> DEC_SUPPLEMENTAL currentState.g2Charset = CharacterSet.DEC_SUPPLEMENTAL; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> DEC_SUPPLEMENTAL currentState.g3Charset = CharacterSet.DEC_SUPPLEMENTAL; } @@ -4150,23 +4363,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> SWISS currentState.g0Charset = CharacterSet.NRC_SWISS; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> SWISS currentState.g1Charset = CharacterSet.NRC_SWISS; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> SWISS currentState.g2Charset = CharacterSet.NRC_SWISS; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> SWISS currentState.g3Charset = CharacterSet.NRC_SWISS; } @@ -4177,52 +4390,52 @@ public class ECMA48 implements Runnable { case '@': break; case 'A': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> United Kingdom set currentState.g0Charset = CharacterSet.UK; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> United Kingdom set currentState.g1Charset = CharacterSet.UK; } if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> United Kingdom set currentState.g2Charset = CharacterSet.UK; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> United Kingdom set currentState.g3Charset = CharacterSet.UK; } } break; case 'B': - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> ASCII set currentState.g0Charset = CharacterSet.US; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> ASCII set currentState.g1Charset = CharacterSet.US; } if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> ASCII currentState.g2Charset = CharacterSet.US; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> ASCII currentState.g3Charset = CharacterSet.US; } @@ -4232,23 +4445,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> FINNISH currentState.g0Charset = CharacterSet.NRC_FINNISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> FINNISH currentState.g1Charset = CharacterSet.NRC_FINNISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> FINNISH currentState.g2Charset = CharacterSet.NRC_FINNISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> FINNISH currentState.g3Charset = CharacterSet.NRC_FINNISH; } @@ -4260,23 +4473,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> NORWEGIAN currentState.g0Charset = CharacterSet.NRC_NORWEGIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> NORWEGIAN currentState.g1Charset = CharacterSet.NRC_NORWEGIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> NORWEGIAN currentState.g2Charset = CharacterSet.NRC_NORWEGIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> NORWEGIAN currentState.g3Charset = CharacterSet.NRC_NORWEGIAN; } @@ -4286,8 +4499,8 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ' ')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ' ')) { // S7C1T s8c1t = false; } @@ -4297,8 +4510,8 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ' ')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ' ')) { // S8C1T s8c1t = true; } @@ -4308,23 +4521,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> SWEDISH currentState.g0Charset = CharacterSet.NRC_SWEDISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> SWEDISH currentState.g1Charset = CharacterSet.NRC_SWEDISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> SWEDISH currentState.g2Charset = CharacterSet.NRC_SWEDISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> SWEDISH currentState.g3Charset = CharacterSet.NRC_SWEDISH; } @@ -4337,23 +4550,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> GERMAN currentState.g0Charset = CharacterSet.NRC_GERMAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> GERMAN currentState.g1Charset = CharacterSet.NRC_GERMAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> GERMAN currentState.g2Charset = CharacterSet.NRC_GERMAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> GERMAN currentState.g3Charset = CharacterSet.NRC_GERMAN; } @@ -4369,23 +4582,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> FRENCH_CA currentState.g0Charset = CharacterSet.NRC_FRENCH_CA; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> FRENCH_CA currentState.g1Charset = CharacterSet.NRC_FRENCH_CA; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> FRENCH_CA currentState.g2Charset = CharacterSet.NRC_FRENCH_CA; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> FRENCH_CA currentState.g3Charset = CharacterSet.NRC_FRENCH_CA; } @@ -4395,23 +4608,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> FRENCH currentState.g0Charset = CharacterSet.NRC_FRENCH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> FRENCH currentState.g1Charset = CharacterSet.NRC_FRENCH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> FRENCH currentState.g2Charset = CharacterSet.NRC_FRENCH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> FRENCH currentState.g3Charset = CharacterSet.NRC_FRENCH; } @@ -4428,23 +4641,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> ITALIAN currentState.g0Charset = CharacterSet.NRC_ITALIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> ITALIAN currentState.g1Charset = CharacterSet.NRC_ITALIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> ITALIAN currentState.g2Charset = CharacterSet.NRC_ITALIAN; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> ITALIAN currentState.g3Charset = CharacterSet.NRC_ITALIAN; } @@ -4454,23 +4667,23 @@ public class ECMA48 implements Runnable { if ((type == DeviceType.VT220) || (type == DeviceType.XTERM)) { - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '(')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '(')) { // G0 --> SPANISH currentState.g0Charset = CharacterSet.NRC_SPANISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == ')')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == ')')) { // G1 --> SPANISH currentState.g1Charset = CharacterSet.NRC_SPANISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '*')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '*')) { // G2 --> SPANISH currentState.g2Charset = CharacterSet.NRC_SPANISH; } - if ((collectBuffer.size() == 1) - && (collectBuffer.get(0) == '+')) { + if ((collectBuffer.length() == 1) + && (collectBuffer.charAt(0) == '+')) { // G3 --> SPANISH currentState.g3Charset = CharacterSet.NRC_SPANISH; } @@ -5114,13 +5327,13 @@ public class ECMA48 implements Runnable { case 'p': if (((type == DeviceType.VT220) || (type == DeviceType.XTERM)) - && (collectBuffer.get(collectBuffer.size() - 1) == '\"') + && (collectBuffer.charAt(collectBuffer.length() - 1) == '\"') ) { // DECSCL - compatibility level decscl(); } if ((type == DeviceType.XTERM) - && (collectBuffer.get(collectBuffer.size() - 1) == '!') + && (collectBuffer.charAt(collectBuffer.length() - 1) == '!') ) { // DECSTR - Soft terminal reset decstr(); @@ -5129,7 +5342,7 @@ public class ECMA48 implements Runnable { case 'q': if (((type == DeviceType.VT220) || (type == DeviceType.XTERM)) - && (collectBuffer.get(collectBuffer.size() - 1) == '\"') + && (collectBuffer.charAt(collectBuffer.length() - 1) == '\"') ) { // DECSCA decsca(); @@ -5188,8 +5401,9 @@ public class ECMA48 implements Runnable { collect(ch); } if (ch == 0x5C) { - if ((collectBuffer.size() > 0) - && (collectBuffer.get(collectBuffer.size() - 1) == 0x1B)) { + if ((collectBuffer.length() > 0) + && (collectBuffer.charAt(collectBuffer.length() - 1) == 0x1B) + ) { toGround(); } } @@ -5241,8 +5455,9 @@ public class ECMA48 implements Runnable { collect(ch); } if (ch == 0x5C) { - if ((collectBuffer.size() > 0) && - (collectBuffer.get(collectBuffer.size() - 1) == 0x1B)) { + if ((collectBuffer.length() > 0) && + (collectBuffer.charAt(collectBuffer.length() - 1) == 0x1B) + ) { toGround(); } } @@ -5272,8 +5487,9 @@ public class ECMA48 implements Runnable { collect(ch); } if (ch == 0x5C) { - if ((collectBuffer.size() > 0) && - (collectBuffer.get(collectBuffer.size() - 1) == 0x1B)) { + if ((collectBuffer.length() > 0) && + (collectBuffer.charAt(collectBuffer.length() - 1) == 0x1B) + ) { toGround(); } } @@ -5319,8 +5535,8 @@ public class ECMA48 implements Runnable { collect(ch); } if (ch == 0x5C) { - if ((collectBuffer.size() > 0) - && (collectBuffer.get(collectBuffer.size() - 1) == 0x1B) + if ((collectBuffer.length() > 0) + && (collectBuffer.charAt(collectBuffer.length() - 1) == 0x1B) ) { toGround(); } @@ -5387,12 +5603,12 @@ public class ECMA48 implements Runnable { case VT52_DIRECT_CURSOR_ADDRESS: // This is a special case for the VT52 sequence "ESC Y l c" - if (collectBuffer.size() == 0) { + if (collectBuffer.length() == 0) { collect(ch); - } else if (collectBuffer.size() == 1) { + } else if (collectBuffer.length() == 1) { // We've got the two characters, one in the buffer and the // other in ch. - cursorPosition(collectBuffer.get(0) - '\040', ch - '\040'); + cursorPosition(collectBuffer.charAt(0) - '\040', ch - '\040'); toGround(); } return; @@ -5406,6 +5622,9 @@ public class ECMA48 implements Runnable { * @return current cursor X */ public final int getCursorX() { + if (display.get(currentState.cursorY).isDoubleWidth()) { + return currentState.cursorX * 2; + } return currentState.cursorX; } @@ -5441,77 +5660,56 @@ public class ECMA48 implements Runnable { while (!done && !stopReaderThread) { try { - // We assume that if inputStream has bytes available, then - // input won't block on read(). int n = inputStream.available(); - if (n > 0) { - // 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 newSize = Math.max(readBufferUTF8.length * 2, n); - - readBufferUTF8 = new char[newSize]; - } - } else { - if (readBuffer.length < n) { - // The buffer wasn't big enough, make it huger - int newSize = Math.max(readBuffer.length * 2, n); - readBuffer = new byte[newSize]; - } - } + // 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 rc = -1; - if (utf8) { - rc = input.read(readBufferUTF8, 0, n); - } else { - rc = inputStream.read(readBuffer, 0, n); + readBufferUTF8 = new char[newSizeHalf * 2]; } - // System.err.printf("read() %d\n", rc); System.err.flush(); - if (rc == -1) { - // This is EOF - done = true; - } else { - for (int i = 0; i < rc; i++) { - int ch = 0; - if (utf8) { - ch = readBufferUTF8[i]; - } else { - ch = readBuffer[i]; - } - // Don't step on UI events - synchronized (this) { - consume((char)ch); - } - } + } else { + if (readBuffer.length < n) { + // The buffer wasn't big enough, make it huger + int newSizeHalf = Math.max(readBuffer.length, n); + readBuffer = new byte[newSizeHalf * 2]; } + } + + int rc = -1; + if (utf8) { + rc = input.read(readBufferUTF8, 0, + readBufferUTF8.length); } else { - // Wait 10 millis for more data - Thread.sleep(10); + rc = inputStream.read(readBuffer, 0, + readBuffer.length); + } + // System.err.printf("read() %d\n", rc); System.err.flush(); + if (rc == -1) { + // This is EOF + done = true; + } else { + for (int i = 0; i < rc; i++) { + int ch = 0; + if (utf8) { + ch = readBufferUTF8[i]; + } else { + ch = readBuffer[i]; + } + // Don't step on UI events + synchronized (this) { + consume((char)ch); + } + } } // System.err.println("end while loop"); System.err.flush(); - } catch (InterruptedException e) { - // SQUASH } catch (IOException e) { e.printStackTrace(); done = true; } } // while ((done == false) && (stopReaderThread == false)) - // Close the input stream - try { - if (utf8) { - input.close(); - input = null; - inputStream = null; - } else { - inputStream.close(); - inputStream = null; - } - } catch (IOException e) { - e.printStackTrace(); - } - // Let the rest of the world know that I am done. stopReaderThread = true;