From 05dbb28d6e8613216f43e8d0fae487c1d9c2fcd3 Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Tue, 10 Mar 2015 13:47:37 -0400 Subject: [PATCH] ECMA48Backend compiles --- .gitignore | 3 + Makefile | 6 +- README.md | 28 ++- build.xml | 37 +++- src/jexer/backend/Backend.java | 4 +- src/jexer/backend/ECMA48Backend.java | 109 ++++++++++++ src/jexer/event/TResizeEvent.java | 2 +- src/jexer/io/ECMA48Terminal.java | 249 +++++++++++---------------- src/jexer/io/Screen.java | 1 - 9 files changed, 272 insertions(+), 167 deletions(-) create mode 100644 src/jexer/backend/ECMA48Backend.java diff --git a/.gitignore b/.gitignore index 8184903..1b71ff2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ *.war *.ear +# Generated docs +docs/** + # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/Makefile b/Makefile index ddfabb5..1dd5790 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,8 @@ JEXER_SRC = $(SRC_DIR)/jexer/TApplication.java \ $(SRC_DIR)/jexer/io/Screen.java \ $(SRC_DIR)/jexer/io/ECMA48Screen.java \ $(SRC_DIR)/jexer/io/ECMA48Terminal.java \ - $(SRC_DIR)/jexer/backend/Backend.java + $(SRC_DIR)/jexer/backend/Backend.java \ + $(SRC_DIR)/jexer/backend/ECMA48Backend.java JEXER_BIN = $(TARGET_DIR)/jexer/TApplication.class \ $(TARGET_DIR)/jexer/TCommand.class \ @@ -82,7 +83,8 @@ JEXER_BIN = $(TARGET_DIR)/jexer/TApplication.class \ $(TARGET_DIR)/jexer/io/Screen.class \ $(TARGET_DIR)/jexer/io/ECMA48Screen.class \ $(TARGET_DIR)/jexer/io/ECMA48Terminal.class \ - $(TARGET_DIR)/jexer/backend/Backend.class + $(TARGET_DIR)/jexer/backend/Backend.class \ + $(TARGET_DIR)/jexer/backend/ECMA48Backend.class JAVAC = javac JAVAFLAGS = -g -deprecation diff --git a/README.md b/README.md index e9cd463..3392cd8 100644 --- a/README.md +++ b/README.md @@ -31,21 +31,21 @@ import jexer.*; public class MyApplication extends TApplication { public MyApplication() { - super(); + super(); - // Create an editor window that has support for - // copy/paste, search text, arrow keys, horizontal - // and vertical scrollbar, etc. - addEditor(); + // Create an editor window that has support for + // copy/paste, search text, arrow keys, horizontal + // and vertical scrollbar, etc. + addEditor(); - // Create standard menus for File and Window - addFileMenu(); - addWindowMenu(); + // Create standard menus for File and Window + addFileMenu(); + addWindowMenu(); } public static void main(String [] args) { - MyApplication app = new MyApplication(); - app.run(); + MyApplication app = new MyApplication(); + app.run(); } } ``` @@ -60,10 +60,9 @@ version 1.0: 0.0.1: - Base classes: - - Events - - Backend - - ECMABackend + - EMCA48Terminal read thread - TApplication loop +- Incorporate checkstyle ant task 0.0.2: @@ -75,7 +74,6 @@ version 1.0: - ECMATerminal - Mouse 1006 mode parsing - - Win32 support (used for reading/writing sockets) - Bugs - TDirectoryList cannot be navigated only with keyboard - TTreeView cannot be navigated only with keyboard @@ -102,5 +100,3 @@ Wishlist features (2.0): - TTerminal - TComboBox - AWTBackend -- ECMABackend - - libgpm support diff --git a/build.xml b/build.xml index fd9b882..da82c0f 100644 --- a/build.xml +++ b/build.xml @@ -61,7 +61,7 @@ includeantruntime="false"/> - + @@ -73,5 +73,38 @@ - + + + + + + + + + + + Test]]> + + + Copyright © 2015 Kevin Lamonte. Licensed LGPLv3+]]> + + + + + diff --git a/src/jexer/backend/Backend.java b/src/jexer/backend/Backend.java index d7ef911..66c7cf3 100644 --- a/src/jexer/backend/Backend.java +++ b/src/jexer/backend/Backend.java @@ -33,6 +33,7 @@ package jexer.backend; import java.util.List; + import jexer.event.TInputEvent; import jexer.io.Screen; import jexer.session.SessionInfo; @@ -64,7 +65,8 @@ public abstract class Backend { * Subclasses must provide an implementation to get keyboard, mouse, and * screen resize events. * - * @param timeout maximum amount of time to wait for an event + * @param timeout maximum amount of time (in millis) to wait for an + * event. 0 means to return immediately, i.e. perform a poll. * @return events received, or an empty list if the timeout was reached */ abstract public List getEvents(int timeout); diff --git a/src/jexer/backend/ECMA48Backend.java b/src/jexer/backend/ECMA48Backend.java new file mode 100644 index 0000000..835dfaa --- /dev/null +++ b/src/jexer/backend/ECMA48Backend.java @@ -0,0 +1,109 @@ +/** + * Jexer - Java Text User Interface + * + * Version: $Id$ + * + * Author: Kevin Lamonte, kevin.lamonte@gmail.com + * + * License: LGPLv3 or later + * + * Copyright: This module is licensed under the GNU Lesser General + * Public License Version 3. Please see the file "COPYING" in this + * directory for more information about the GNU Lesser General Public + * License Version 3. + * + * Copyright (C) 2015 Kevin Lamonte + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see + * http://www.gnu.org/licenses/, or write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +package jexer.backend; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import jexer.event.TInputEvent; +import jexer.io.ECMA48Screen; +import jexer.io.ECMA48Terminal; + +/** + * This class uses an xterm/ANSI X3.64/ECMA-48 type terminal to provide a + * screen, keyboard, and mouse to TApplication. + */ +public class ECMA48Backend extends Backend { + + /** + * Input events are processed by this Terminal. + */ + private ECMA48Terminal terminal; + + /** + * Public constructor. + * + * @param input an InputStream connected to the remote user, or null for + * System.in. If System.in is used, then on non-Windows systems it will + * be put in raw mode; shutdown() will (blindly!) put System.in in cooked + * mode. input is always converted to a Reader with UTF-8 encoding. + * @param output an OutputStream connected to the remote user, or null + * for System.out. output is always converted to a Writer with UTF-8 + * encoding. + */ + public ECMA48Backend(InputStream input, OutputStream output) throws UnsupportedEncodingException { + + // Create a terminal and explicitly set stdin into raw mode + terminal = new ECMA48Terminal(input, output); + + // Create a screen + screen = new ECMA48Screen(terminal); + + // Clear the screen + terminal.getOutput().write(terminal.clearAll()); + terminal.flush(); + } + + /** + * Sync the logical screen to the physical device. + */ + @Override + public void flushScreen() { + screen.flushPhysical(); + } + + /** + * Get keyboard, mouse, and screen resize events. + * + * @param timeout maximum amount of time (in millis) to wait for an + * event. 0 means to return immediately, i.e. perform a poll. + * @return events received, or an empty list if the timeout was reached + * first + */ + @Override + public List getEvents(int timeout) { + return terminal.getEvents(); + } + + /** + * Subclasses must provide an implementation that closes sockets, + * restores console, etc. + */ + @Override + public void shutdown() { + terminal.shutdown(); + } + +} diff --git a/src/jexer/event/TResizeEvent.java b/src/jexer/event/TResizeEvent.java index aabf051..101b8f3 100644 --- a/src/jexer/event/TResizeEvent.java +++ b/src/jexer/event/TResizeEvent.java @@ -66,7 +66,7 @@ public class TResizeEvent extends TInputEvent { * * @param type the Type of resize, Screen or Widget * @param width the new width - * @param width the new height + * @param height the new height */ public TResizeEvent(Type type, int width, int height) { this.type = type; diff --git a/src/jexer/io/ECMA48Terminal.java b/src/jexer/io/ECMA48Terminal.java index 8d3c0fe..7542f8a 100644 --- a/src/jexer/io/ECMA48Terminal.java +++ b/src/jexer/io/ECMA48Terminal.java @@ -696,16 +696,21 @@ public class ECMA48Terminal { } /** - * Parses the next character of input to see if an InputEvent is - * fully here. + * Return any events in the IO queue. * - * Params: - * ch = Unicode code point - * noChar = if true, ignore ch. This is currently used to - * return a bare ESC and RESIZE events. + * @return list of new events (which may be empty) + */ + public List getEvents() { + List events = new LinkedList(); + return events; + } + + /** + * Parses the next character of input to see if an InputEvent is fully + * here. * - * Returns: - * list of new events (which may be empty) + * @param ch Unicode code point + * @return list of new events (which may be empty) */ public List getEvents(char ch) { return getEvents(ch, false); @@ -715,13 +720,10 @@ public class ECMA48Terminal { * Parses the next character of input to see if an InputEvent is * fully here. * - * Params: - * ch = Unicode code point - * noChar = if true, ignore ch. This is currently used to - * return a bare ESC and RESIZE events. - * - * Returns: - * list of new events (which may be empty) + * @param ch Unicode code point + * @param noChar if true, ignore ch. This is currently used to return a + * bare ESC and RESIZE events. + * @return list of new events (which may be empty) */ public List getEvents(char ch, boolean noChar) { List events = new LinkedList(); @@ -1103,15 +1105,12 @@ public class ECMA48Terminal { } /** - * Tell (u)xterm that we want alt- keystrokes to send escape + - * character rather than set the 8th bit. Anyone who wants UTF8 - * should want this enabled. + * Tell (u)xterm that we want alt- keystrokes to send escape + character + * rather than set the 8th bit. Anyone who wants UTF8 should want this + * enabled. * - * Params: - * on = if true, enable metaSendsEscape - * - * Returns: - * the string to emit to xterm + * @param on if true, enable metaSendsEscape + * @return the string to emit to xterm */ static public String xtermMetaSendsEscape(boolean on) { if (on) { @@ -1121,15 +1120,13 @@ public class ECMA48Terminal { } /** - * Convert a list of SGR parameters into a full escape sequence. - * This also eliminates a trailing ';' which would otherwise reset - * everything to white-on-black not-bold. - * - * Params: - * str = string of parameters, e.g. "31;1;" + * Convert a list of SGR parameters into a full escape sequence. This + * also eliminates a trailing ';' which would otherwise reset everything + * to white-on-black not-bold. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[31;1m" + * @param str string of parameters, e.g. "31;1;" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[31;1m" */ static public String addHeaderSGR(String str) { if (str.length() > 0) { @@ -1144,12 +1141,10 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for a single color change. * - * Params: - * color = one of the Color.WHITE, Color.BLUE, etc. constants - * foreground = if true, this is a foreground color - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[42m" + * @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" */ static public String color(Color color, boolean foreground) { return color(color, foreground, true); @@ -1158,14 +1153,12 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for a single color change. * - * Params: - * color = one of the Color.WHITE, Color.BLUE, etc. constants - * foreground = if true, this is a foreground color - * header = if true, make the full header, otherwise just emit - * the color parameter e.g. "42;" - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[42m" + * @param color one of the Color.WHITE, Color.BLUE, etc. constants + * @param foreground if true, this is a foreground color + * @param header if true, make the full header, otherwise just emit the + * color parameter e.g. "42;" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[42m" */ static public String color(Color color, boolean foreground, boolean header) { @@ -1190,12 +1183,10 @@ public class ECMA48Terminal { * Create a SGR parameter sequence for both foreground and * background color change. * - * Params: - * foreColor = one of the Color.WHITE, Color.BLUE, etc. constants - * backColor = one of the Color.WHITE, Color.BLUE, etc. constants - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[31;42m" + * @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" */ static public String color(Color foreColor, Color backColor) { return color(foreColor, backColor, true); @@ -1205,14 +1196,12 @@ public class ECMA48Terminal { * Create a SGR parameter sequence for both foreground and * background color change. * - * Params: - * foreColor = one of the Color.WHITE, Color.BLUE, etc. constants - * backColor = one of the Color.WHITE, Color.BLUE, etc. constants - * header = if true, make the full header, otherwise just emit - * the color parameter e.g. "31;42;" - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[31;42m" + * @param foreColor one of the Color.WHITE, Color.BLUE, etc. constants + * @param backColor one of the Color.WHITE, Color.BLUE, etc. constants + * @param header if true, make the full header, otherwise just emit the + * color parameter e.g. "31;42;" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[31;42m" */ static public String color(Color foreColor, Color backColor, boolean header) { @@ -1233,19 +1222,17 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for foreground, background, and - * several attributes. This sequence first resets all attributes - * to default, then sets attributes as per the parameters. - * - * Params: - * foreColor = one of the Color.WHITE, Color.BLUE, etc. constants - * backColor = one of the Color.WHITE, Color.BLUE, etc. constants - * bold = if true, set bold - * reverse = if true, set reverse - * blink = if true, set blink - * underline = if true, set underline + * several attributes. This sequence first resets all attributes to + * default, then sets attributes as per the parameters. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[0;1;31;42m" + * @param foreColor one of the Color.WHITE, Color.BLUE, etc. constants + * @param backColor one of the Color.WHITE, Color.BLUE, etc. constants + * @param bold if true, set bold + * @param reverse if true, set reverse + * @param blink if true, set blink + * @param underline if true, set underline + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[0;1;31;42m" */ static public String color(Color foreColor, Color backColor, boolean bold, boolean reverse, boolean blink, boolean underline) { @@ -1299,11 +1286,9 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for enabling reverse color. * - * Params: - * on = if true, turn on reverse - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[7m" + * @param on if true, turn on reverse + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[7m" */ static public String reverse(boolean on) { if (on) { @@ -1315,8 +1300,8 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence to reset to defaults. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[0m" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[0m" */ static public String normal() { return normal(true); @@ -1325,12 +1310,10 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence to reset to defaults. * - * Params: - * header = if true, make the full header, otherwise just emit - * the bare parameter e.g. "0;" - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[0m" + * @param header if true, make the full header, otherwise just emit the + * bare parameter e.g. "0;" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[0m" */ static public String normal(boolean header) { if (header) { @@ -1342,11 +1325,9 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for enabling boldface. * - * Params: - * on = if true, turn on bold - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[1m" + * @param on if true, turn on bold + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[1m" */ static public String bold(boolean on) { return bold(on, true); @@ -1355,13 +1336,11 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for enabling boldface. * - * Params: - * on = if true, turn on bold - * header = if true, make the full header, otherwise just emit - * the bare parameter e.g. "1;" - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[1m" + * @param on if true, turn on bold + * @param header if true, make the full header, otherwise just emit the + * bare parameter e.g. "1;" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[1m" */ static public String bold(boolean on, boolean header) { if (header) { @@ -1379,11 +1358,9 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for enabling blinking text. * - * Params: - * on = if true, turn on blink - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[5m" + * @param on if true, turn on blink + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[5m" */ static public String blink(boolean on) { return blink(on, true); @@ -1392,13 +1369,11 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for enabling blinking text. * - * Params: - * on = if true, turn on blink - * header = if true, make the full header, otherwise just emit - * the bare parameter e.g. "5;" - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[5m" + * @param on if true, turn on blink + * @param header if true, make the full header, otherwise just emit the + * bare parameter e.g. "5;" + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[5m" */ static public String blink(boolean on, boolean header) { if (header) { @@ -1414,14 +1389,12 @@ public class ECMA48Terminal { } /** - * Create a SGR parameter sequence for enabling underline / - * underscored text. - * - * Params: - * on = if true, turn on underline + * Create a SGR parameter sequence for enabling underline / underscored + * text. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal, e.g. "\033[4m" + * @param on if true, turn on underline + * @return the string to emit to an ANSI / ECMA-style terminal, + * e.g. "\033[4m" */ static public String underline(boolean on) { if (on) { @@ -1433,11 +1406,8 @@ public class ECMA48Terminal { /** * Create a SGR parameter sequence for enabling the visible cursor. * - * Params: - * on = if true, turn on cursor - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @param on if true, turn on cursor + * @return the string to emit to an ANSI / ECMA-style terminal */ public String cursor(boolean on) { if (on && (cursorOn == false)) { @@ -1455,8 +1425,7 @@ public class ECMA48Terminal { * Clear the entire screen. Because some terminals use back-color-erase, * set the color to white-on-black beforehand. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @return the string to emit to an ANSI / ECMA-style terminal */ static public String clearAll() { return "\033[0;37;40m\033[2J"; @@ -1467,8 +1436,7 @@ public class ECMA48Terminal { * Because some terminals use back-color-erase, set the color to * white-on-black beforehand. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @return the string to emit to an ANSI / ECMA-style terminal */ static public String clearRemainingLine() { return "\033[0;37;40m\033[K"; @@ -1478,8 +1446,7 @@ public class ECMA48Terminal { * Clear the line up the cursor (inclusive). Because some terminals use * back-color-erase, set the color to white-on-black beforehand. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @return the string to emit to an ANSI / ECMA-style terminal */ static public String clearPreceedingLine() { return "\033[0;37;40m\033[1K"; @@ -1489,8 +1456,7 @@ public class ECMA48Terminal { * Clear the line. Because some terminals use back-color-erase, set the * color to white-on-black beforehand. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @return the string to emit to an ANSI / ECMA-style terminal */ static public String clearLine() { return "\033[0;37;40m\033[2K"; @@ -1499,8 +1465,7 @@ public class ECMA48Terminal { /** * Move the cursor to the top-left corner. * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @return the string to emit to an ANSI / ECMA-style terminal */ static public String home() { return "\033[H"; @@ -1509,29 +1474,25 @@ public class ECMA48Terminal { /** * Move the cursor to (x, y). * - * Params: - * x = column coordinate. 0 is the left-most column. - * y = row coordinate. 0 is the top-most row. - * - * Returns: - * the string to emit to an ANSI / ECMA-style terminal + * @param x column coordinate. 0 is the left-most column. + * @param y row coordinate. 0 is the top-most row. + * @return the string to emit to an ANSI / ECMA-style terminal */ static public String gotoXY(int x, int y) { return String.format("\033[%d;%dH", y + 1, x + 1); } /** - * Tell (u)xterm that we want to receive mouse events based on - * "Any event tracking" and UTF-8 coordinates. See + * Tell (u)xterm that we want to receive mouse events based on "Any event + * tracking" and UTF-8 coordinates. See * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking * - * Finally, this sets the alternate screen buffer. - * - * Params: - * on = if true, enable mouse report + * Note that this also sets the alternate/primary screen buffer. * - * Returns: - * the string to emit to xterm + * @param on If true, enable mouse report and use the alternate screen + * buffer. If false disable mouse reporting and use the primary screen + * buffer. + * @return the string to emit to xterm */ static public String mouse(boolean on) { if (on) { diff --git a/src/jexer/io/Screen.java b/src/jexer/io/Screen.java index 6910a66..1ecc304 100644 --- a/src/jexer/io/Screen.java +++ b/src/jexer/io/Screen.java @@ -143,7 +143,6 @@ public abstract class Screen { * @param x column coordinate. 0 is the left-most column. * @param y row coordinate. 0 is the top-most row. * @param attr attributes to use (bold, foreColor, backColor) - * @param clip if true, honor clipping/offset */ public void putAttrXY(int x, int y, CellAttributes attr) { putAttrXY(x, y, attr, true); -- 2.27.0