X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2Ftterminal%2FECMA48.java;h=c6aa0b21e7f981ac5a66d7f65fa49ac7aec2e9f8;hb=5ca5f8e5310b189232ed337643f3b7b2ce6cd3b1;hp=5ff3518f3e3fb29785d55580e9377ba2855bb1fe;hpb=34bb6e525628111b87a36556bbdd2719c6d7925f;p=fanfix.git diff --git a/src/jexer/tterminal/ECMA48.java b/src/jexer/tterminal/ECMA48.java index 5ff3518..c6aa0b2 100644 --- a/src/jexer/tterminal/ECMA48.java +++ b/src/jexer/tterminal/ECMA48.java @@ -506,6 +506,11 @@ public class ECMA48 implements Runnable { */ private ArrayList userQueue = new ArrayList(); + /** + * Number of bytes/characters passed to consume(). + */ + private long readCount = 0; + /** * DECSC/DECRC save/restore a subset of the total state. This class * encapsulates those specific flags/modes. @@ -854,6 +859,34 @@ public class ECMA48 implements Runnable { // ECMA48 ----------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Wait for a period of time to get output from the launched process. + * + * @param millis millis to wait for, or 0 to wait forever + * @return true if the launched process has emitted something + */ + public boolean waitForOutput(final int millis) { + if (millis < 0) { + throw new IllegalArgumentException("timeout must be >= 0"); + } + int waitedMillis = millis; + final int pollTimeout = 5; + while (true) { + if (readCount != 0) { + return true; + } + if ((millis > 0) && (waitedMillis < 0)){ + return false; + } + try { + Thread.sleep(pollTimeout); + } catch (InterruptedException e) { + // SQUASH + } + waitedMillis -= pollTimeout; + } + } + /** * Process keyboard and mouse events from the user. * @@ -1025,11 +1058,6 @@ public class ECMA48 implements Runnable { // the input streams. if (stopReaderThread == false) { stopReaderThread = true; - try { - readerThread.join(1000); - } catch (InterruptedException e) { - // SQUASH - } } // Now close the output stream. @@ -1686,35 +1714,45 @@ public class ECMA48 implements Runnable { if (mouseEncoding == MouseEncoding.SGR) { sb.append((char) 0x1B); sb.append("[<"); + int buttons = 0; if (mouse.isMouse1()) { if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { - sb.append("32;"); + buttons = 32; } else { - sb.append("0;"); + buttons = 0; } } else if (mouse.isMouse2()) { if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { - sb.append("33;"); + buttons = 33; } else { - sb.append("1;"); + buttons = 1; } } else if (mouse.isMouse3()) { if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { - sb.append("34;"); + buttons = 34; } else { - sb.append("2;"); + buttons = 2; } } else if (mouse.isMouseWheelUp()) { - sb.append("64;"); + buttons = 64; } else if (mouse.isMouseWheelDown()) { - sb.append("65;"); + buttons = 65; } else { // This is motion with no buttons down. - sb.append("35;"); + buttons = 35; + } + if (mouse.isAlt()) { + buttons |= 0x08; + } + if (mouse.isCtrl()) { + buttons |= 0x10; + } + if (mouse.isShift()) { + buttons |= 0x04; } - sb.append(String.format("%d;%d", mouse.getX() + 1, + sb.append(String.format("%d;%d;%d", buttons, mouse.getX() + 1, mouse.getY() + 1)); if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { @@ -1728,35 +1766,46 @@ public class ECMA48 implements Runnable { sb.append((char) 0x1B); sb.append('['); sb.append('M'); + int buttons = 0; if (mouse.getType() == TMouseEvent.Type.MOUSE_UP) { - sb.append((char) (0x03 + 32)); + buttons = 0x03 + 32; } else if (mouse.isMouse1()) { if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { - sb.append((char) (0x00 + 32 + 32)); + buttons = 0x00 + 32 + 32; } else { - sb.append((char) (0x00 + 32)); + buttons = 0x00 + 32; } } else if (mouse.isMouse2()) { if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { - sb.append((char) (0x01 + 32 + 32)); + buttons = 0x01 + 32 + 32; } else { - sb.append((char) (0x01 + 32)); + buttons = 0x01 + 32; } } else if (mouse.isMouse3()) { if (mouse.getType() == TMouseEvent.Type.MOUSE_MOTION) { - sb.append((char) (0x02 + 32 + 32)); + buttons = 0x02 + 32 + 32; } else { - sb.append((char) (0x02 + 32)); + buttons = 0x02 + 32; } } else if (mouse.isMouseWheelUp()) { - sb.append((char) (0x04 + 64)); + buttons = 0x04 + 64; } else if (mouse.isMouseWheelDown()) { - sb.append((char) (0x05 + 64)); + buttons = 0x05 + 64; } else { // This is motion with no buttons down. - sb.append((char) (0x03 + 32)); + buttons = 0x03 + 32; + } + if (mouse.isAlt()) { + buttons |= 0x08; + } + if (mouse.isCtrl()) { + buttons |= 0x10; + } + if (mouse.isShift()) { + buttons |= 0x04; } + sb.append((char) (buttons & 0xFF)); sb.append((char) (mouse.getX() + 33)); sb.append((char) (mouse.getY() + 33)); } @@ -3178,10 +3227,10 @@ public class ECMA48 implements Runnable { if (decPrivateModeFlag == true) { if (value == true) { // Enable sixel scrolling (default). - // TODO + // Not supported } else { // Disable sixel scrolling. - // TODO + // Not supported } } } @@ -4016,7 +4065,7 @@ public class ECMA48 implements Runnable { case 8: // Invisible - // TODO + // Not supported break; case 90: @@ -4757,13 +4806,22 @@ public class ECMA48 implements Runnable { private void oscPut(final char xtermChar) { // System.err.println("oscPut: " + xtermChar); + boolean oscEnd = false; + + if (xtermChar == 0x07) { + oscEnd = true; + } + if ((xtermChar == '\\') + && (collectBuffer.charAt(collectBuffer.length() - 1) == '\033') + ) { + oscEnd = true; + } + // Collect first collectBuffer.append(xtermChar); // Xterm cases... - if ((xtermChar == 0x07) - || (collectBuffer.toString().endsWith("\033\\")) - ) { + if (oscEnd) { String args = null; if (xtermChar == 0x07) { args = collectBuffer.substring(0, collectBuffer.length() - 1); @@ -4846,11 +4904,19 @@ public class ECMA48 implements Runnable { private void pmPut(final char pmChar) { // System.err.println("pmPut: " + pmChar); + boolean pmEnd = false; + + if ((pmChar == '\\') + && (collectBuffer.charAt(collectBuffer.length() - 1) == '\033') + ) { + pmEnd = true; + } + // Collect first collectBuffer.append(pmChar); // Xterm cases... - if (collectBuffer.toString().endsWith("\033\\")) { + if (pmEnd) { String arg = null; arg = collectBuffer.substring(0, collectBuffer.length() - 2); @@ -4938,6 +5004,7 @@ public class ECMA48 implements Runnable { * @param ch character from the remote side */ private void consume(final int ch) { + readCount++; // DEBUG // System.err.printf("%c STATE = %s\n", ch, scanState); @@ -7272,8 +7339,21 @@ public class ECMA48 implements Runnable { } Cell cell = new Cell(); - cell.setImage(image.getSubimage(x * textWidth, - y * textHeight, width, height)); + if ((width != textWidth) || (height != textHeight)) { + BufferedImage newImage; + newImage = new BufferedImage(textWidth, textHeight, + BufferedImage.TYPE_INT_ARGB); + + java.awt.Graphics gr = newImage.getGraphics(); + gr.drawImage(image.getSubimage(x * textWidth, + y * textHeight, width, height), + 0, 0, null, null); + gr.dispose(); + cell.setImage(newImage); + } else { + cell.setImage(image.getSubimage(x * textWidth, + y * textHeight, width, height)); + } cells[x][y] = cell; } @@ -7285,9 +7365,10 @@ public class ECMA48 implements Runnable { for (int x = 0; x < cellColumns; x++) { assert (currentState.cursorX <= rightMargin); - // TODO: Render text of current cell first, then image over - // it (accounting for blank pixels). For now, just copy the - // cell. + // A real sixel terminal would render the text of the current + // cell first, then image over it (accounting for blank + // pixels). We do not support that. A cell is either text, + // or image, but not a mix of image-over-text. DisplayLine line = display.get(currentState.cursorY); line.replace(currentState.cursorX, cells[x][y]);