X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjexer%2Fio%2FECMA48Terminal.java;h=0cf0452a52f438ecc9865e66c672660cc6534c4c;hb=15ea4d7374314d856f72e83f3bc07fe9ec059741;hp=069c143f2d32e9a8c6f86dc474ac2149df6f2244;hpb=32437017f5e13c3668fe12328364ed3cd8eac8eb;p=fanfix.git diff --git a/src/jexer/io/ECMA48Terminal.java b/src/jexer/io/ECMA48Terminal.java index 069c143..0cf0452 100644 --- a/src/jexer/io/ECMA48Terminal.java +++ b/src/jexer/io/ECMA48Terminal.java @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (C) 2016 Kevin Lamonte + * Copyright (C) 2017 Kevin Lamonte * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -60,6 +60,12 @@ import static jexer.TKeypress.*; */ public final class ECMA48Terminal implements Runnable { + /** + * If true, emit T.416-style RGB colors. This is a) expensive in + * bandwidth, and b) potentially terrible looking for non-xterms. + */ + private static boolean doRgbColor = false; + /** * The session information. */ @@ -335,12 +341,115 @@ public final class ECMA48Terminal implements Runnable { windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN, sessionInfo.getWindowWidth(), sessionInfo.getWindowHeight()); + // Permit RGB colors only if externally requested + if (System.getProperty("jexer.ECMA48.rgbColor") != null) { + if (System.getProperty("jexer.ECMA48.rgbColor").equals("true")) { + doRgbColor = true; + } + } + // Spin up the input reader eventQueue = new LinkedList(); readerThread = new Thread(this); readerThread.start(); } + /** + * Constructor sets up state for getEvent(). + * + * @param listener the object this backend needs to wake up when new + * input comes in + * @param input the InputStream underlying 'reader'. Its available() + * method is used to determine if reader.read() will block or not. + * @param reader a Reader connected to the remote user. + * @param writer a PrintWriter connected to the remote user. + * @param setRawMode if true, set System.in into raw mode with stty. + * This should in general not be used. It is here solely for Demo3, + * which uses System.in. + * @throws IllegalArgumentException if input, reader, or writer are null. + */ + public ECMA48Terminal(final Object listener, final InputStream input, + final Reader reader, final PrintWriter writer, + final boolean setRawMode) { + + if (input == null) { + throw new IllegalArgumentException("InputStream must be specified"); + } + if (reader == null) { + throw new IllegalArgumentException("Reader must be specified"); + } + if (writer == null) { + throw new IllegalArgumentException("Writer must be specified"); + } + reset(); + mouse1 = false; + mouse2 = false; + mouse3 = false; + stopReaderThread = false; + this.listener = listener; + + inputStream = input; + this.input = reader; + + if (setRawMode == true) { + sttyRaw(); + } + this.setRawMode = setRawMode; + + if (input instanceof SessionInfo) { + // This is a TelnetInputStream that exposes window size and + // environment variables from the telnet layer. + sessionInfo = (SessionInfo) input; + } + if (sessionInfo == null) { + if (setRawMode == true) { + // Reading right off the tty + sessionInfo = new TTYSessionInfo(); + } else { + sessionInfo = new TSessionInfo(); + } + } + + this.output = writer; + + // Enable mouse reporting and metaSendsEscape + this.output.printf("%s%s", mouse(true), xtermMetaSendsEscape(true)); + this.output.flush(); + + // Hang onto the window size + windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN, + sessionInfo.getWindowWidth(), sessionInfo.getWindowHeight()); + + // Permit RGB colors only if externally requested + if (System.getProperty("jexer.ECMA48.rgbColor") != null) { + if (System.getProperty("jexer.ECMA48.rgbColor").equals("true")) { + doRgbColor = true; + } + } + + // Spin up the input reader + eventQueue = new LinkedList(); + readerThread = new Thread(this); + readerThread.start(); + } + + /** + * Constructor sets up state for getEvent(). + * + * @param listener the object this backend needs to wake up when new + * input comes in + * @param input the InputStream underlying 'reader'. Its available() + * method is used to determine if reader.read() will block or not. + * @param reader a Reader connected to the remote user. + * @param writer a PrintWriter connected to the remote user. + * @throws IllegalArgumentException if input, reader, or writer are null. + */ + public ECMA48Terminal(final Object listener, final InputStream input, + final Reader reader, final PrintWriter writer) { + + this(listener, input, reader, writer, false); + } + /** * Restore terminal to normal state. */ @@ -1139,17 +1248,114 @@ public final class ECMA48Terminal implements Runnable { return "\033[?1036l"; } + /** + * Create an xterm OSC sequence to change the window title. Note package + * private access. + * + * @param title the new title + * @return the string to emit to xterm + */ + String setTitle(final String title) { + return "\033]2;" + title + "\007"; + } + /** * Create a SGR parameter sequence for a single color change. Note * package private access. * + * @param bold if true, set bold * @param color one of the Color.WHITE, Color.BLUE, etc. constants * @param foreground if true, this is a foreground color * @return the string to emit to an ANSI / ECMA-style terminal, * e.g. "\033[42m" */ - String color(final Color color, final boolean foreground) { - return color(color, foreground, true); + String color(final boolean bold, final Color color, + final boolean foreground) { + return color(color, foreground, true) + + rgbColor(bold, color, foreground); + } + + /** + * Create a T.416 RGB parameter sequence for a single color change. + * + * @param bold if true, set bold + * @param color one of the Color.WHITE, Color.BLUE, etc. constants + * @param foreground if true, this is a foreground color + * @return the string to emit to an xterm terminal with RGB support, + * e.g. "\033[38;2;RR;GG;BBm" + */ + private String rgbColor(final boolean bold, final Color color, + final boolean foreground) { + if (doRgbColor == false) { + return ""; + } + StringBuilder sb = new StringBuilder("\033["); + if (bold) { + // Bold implies foreground only + sb.append("38;2;"); + if (color.equals(Color.BLACK)) { + sb.append("116;116;116"); + } else if (color.equals(Color.RED)) { + sb.append("252;116;116"); + } else if (color.equals(Color.GREEN)) { + sb.append("116;252;116"); + } else if (color.equals(Color.YELLOW)) { + sb.append("252;252;116"); + } else if (color.equals(Color.BLUE)) { + sb.append("116;116;252"); + } else if (color.equals(Color.MAGENTA)) { + sb.append("252;116;252"); + } else if (color.equals(Color.CYAN)) { + sb.append("116;252;252"); + } else if (color.equals(Color.WHITE)) { + sb.append("252;252;252"); + } + } else { + if (foreground) { + sb.append("38;2;"); + } else { + sb.append("48;2;"); + } + if (color.equals(Color.BLACK)) { + sb.append("0;0;0"); + } else if (color.equals(Color.RED)) { + sb.append("168;0;0"); + } else if (color.equals(Color.GREEN)) { + sb.append("0;168;0"); + } else if (color.equals(Color.YELLOW)) { + sb.append("168;116;0"); + } else if (color.equals(Color.BLUE)) { + sb.append("0;0;168"); + } else if (color.equals(Color.MAGENTA)) { + sb.append("168;0;168"); + } else if (color.equals(Color.CYAN)) { + sb.append("0;168;168"); + } else if (color.equals(Color.WHITE)) { + sb.append("168;168;168"); + } + } + sb.append("m"); + return sb.toString(); + } + + /** + * Create a T.416 RGB parameter sequence for both foreground and + * background color change. + * + * @param bold if true, set bold + * @param foreColor one of the Color.WHITE, Color.BLUE, etc. constants + * @param backColor one of the Color.WHITE, Color.BLUE, etc. constants + * @return the string to emit to an xterm terminal with RGB support, + * e.g. "\033[38;2;RR;GG;BB;48;2;RR;GG;BBm" + */ + private String rgbColor(final boolean bold, final Color foreColor, + final Color backColor) { + if (doRgbColor == false) { + return ""; + } + + return rgbColor(bold, foreColor, true) + + rgbColor(false, backColor, false); } /** @@ -1185,13 +1391,16 @@ public final class ECMA48Terminal implements Runnable { * Create a SGR parameter sequence for both foreground and background * color change. Note package private access. * + * @param bold if true, set bold * @param foreColor one of the Color.WHITE, Color.BLUE, etc. constants * @param backColor one of the Color.WHITE, Color.BLUE, etc. constants * @return the string to emit to an ANSI / ECMA-style terminal, * e.g. "\033[31;42m" */ - String color(final Color foreColor, final Color backColor) { - return color(foreColor, backColor, true); + String color(final boolean bold, final Color foreColor, + final Color backColor) { + return color(foreColor, backColor, true) + + rgbColor(bold, foreColor, backColor); } /** @@ -1284,7 +1493,7 @@ public final class ECMA48Terminal implements Runnable { sb.append("\033[0;"); } sb.append(String.format("%d;%dm", ecmaForeColor, ecmaBackColor)); - return sb.toString(); + return sb.toString() + rgbColor(bold, foreColor, backColor); } /**