| 1 | /* |
| 2 | * This file is part of lanterna (http://code.google.com/p/lanterna/). |
| 3 | * |
| 4 | * lanterna is free software: you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU Lesser General Public License as published by |
| 6 | * the Free Software Foundation, either version 3 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU Lesser General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU Lesser General Public License |
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | * |
| 17 | * Copyright (C) 2010-2015 Martin |
| 18 | */ |
| 19 | package com.googlecode.lanterna.terminal; |
| 20 | |
| 21 | import com.googlecode.lanterna.SGR; |
| 22 | import com.googlecode.lanterna.TerminalSize; |
| 23 | import com.googlecode.lanterna.TextColor; |
| 24 | import com.googlecode.lanterna.graphics.TextGraphics; |
| 25 | import com.googlecode.lanterna.input.InputProvider; |
| 26 | import java.io.IOException; |
| 27 | import java.util.concurrent.TimeUnit; |
| 28 | |
| 29 | /** |
| 30 | * This is the main terminal interface, at the lowest level supported by Lanterna. You can write your own |
| 31 | * implementation of this if you want to target an exotic text terminal specification or another graphical environment |
| 32 | * (like SWT), but you should probably extend {@code AbstractTerminal} instead of implementing this interface directly. |
| 33 | * <p> |
| 34 | * The normal way you interact in Java with a terminal is through the standard output (System.out) and standard error |
| 35 | * (System.err) and it's usually through printing text only. This interface abstracts a terminal at a more fundamental |
| 36 | * level, expressing methods for not only printing text but also changing colors, moving the cursor new positions, |
| 37 | * enable special modifiers and get notified when the terminal's size has changed. |
| 38 | * <p> |
| 39 | * If you want to write an application that has a very precise control of the terminal, this is the |
| 40 | * interface you should be programming against. |
| 41 | * |
| 42 | * @author Martin |
| 43 | */ |
| 44 | public interface Terminal extends InputProvider { |
| 45 | |
| 46 | /** |
| 47 | * Calling this method will, where supported, give your terminal a private area to use, separate from what was there |
| 48 | * before. Some terminal emulators will preserve the terminal history and restore it when you exit private mode. |
| 49 | * Some terminals will just clear the screen and put the cursor in the top-left corner. Typically, if you terminal |
| 50 | * supports scrolling, going into private mode will disable the scrolling and leave you with a fixed screen, which |
| 51 | * can be useful if you don't want to deal with what the terminal buffer will look like if the user scrolls up. |
| 52 | * |
| 53 | * @throws java.io.IOException If there was an underlying I/O error |
| 54 | * @throws IllegalStateException If you are already in private mode |
| 55 | */ |
| 56 | void enterPrivateMode() throws IOException; |
| 57 | |
| 58 | /** |
| 59 | * If you have previously entered private mode, this method will exit this and, depending on implementation, maybe |
| 60 | * restore what the terminal looked like before private mode was entered. If the terminal doesn't support a |
| 61 | * secondary buffer for private mode, it will probably make a new line below the private mode and place the cursor |
| 62 | * there. |
| 63 | * |
| 64 | * @throws java.io.IOException If there was an underlying I/O error |
| 65 | * @throws IllegalStateException If you are not in private mode |
| 66 | */ |
| 67 | void exitPrivateMode() throws IOException; |
| 68 | |
| 69 | /** |
| 70 | * Removes all the characters, colors and graphics from the screen and leaves you with a big empty space. Text |
| 71 | * cursor position is undefined after this call (depends on platform and terminal) so you should always call |
| 72 | * {@code moveCursor} next. Some terminal implementations doesn't reset color and modifier state so it's also good |
| 73 | * practise to call {@code resetColorAndSGR()} after this. |
| 74 | * @throws java.io.IOException If there was an underlying I/O error |
| 75 | */ |
| 76 | void clearScreen() throws IOException; |
| 77 | |
| 78 | /** |
| 79 | * Moves the text cursor to a new location on the terminal. The top-left corner has coordinates 0 x 0 and the bottom- |
| 80 | * right corner has coordinates terminal_width-1 x terminal_height-1. You can retrieve the size of the terminal by |
| 81 | * calling getTerminalSize(). |
| 82 | * |
| 83 | * @param x The 0-indexed column to place the cursor at |
| 84 | * @param y The 0-indexed row to place the cursor at |
| 85 | * @throws java.io.IOException If there was an underlying I/O error |
| 86 | */ |
| 87 | void setCursorPosition(int x, int y) throws IOException; |
| 88 | |
| 89 | /** |
| 90 | * Hides or shows the text cursor, but not all terminal (-emulators) supports this. The text cursor is normally a |
| 91 | * text block or an underscore, sometimes blinking, which shows the user where keyboard-entered text is supposed to |
| 92 | * show up. |
| 93 | * |
| 94 | * @param visible Hides the text cursor if {@code false} and shows it if {@code true} |
| 95 | * @throws java.io.IOException If there was an underlying I/O error |
| 96 | */ |
| 97 | void setCursorVisible(boolean visible) throws IOException; |
| 98 | |
| 99 | /** |
| 100 | * Prints one character to the terminal at the current cursor location. Please note that the cursor will then move |
| 101 | * one column to the right, so multiple calls to {@code putCharacter} will print out a text string without the need |
| 102 | * to reposition the text cursor. If you reach the end of the line while putting characters using this method, you |
| 103 | * can expect the text cursor to move to the beginning of the next line. |
| 104 | * <p> |
| 105 | * You can output CJK (Chinese, Japanese, Korean) characters (as well as other regional scripts) but remember that |
| 106 | * the terminal that the user is using might not have the required font to render it. Also worth noticing is that |
| 107 | * CJK (and some others) characters tend to take up 2 columns per character, simply because they are a square in |
| 108 | * their construction as opposed to the somewhat rectangular shape we fit latin characters in. As it's very |
| 109 | * difficult to create a monospace font for CJK with a 2:1 height-width proportion, it seems like the implementers |
| 110 | * back in the days simply gave up and made each character take 2 column. It causes issues for the random terminal |
| 111 | * programmer because you can't really trust 1 character = 1 column, but I suppose it's "しょうがない". |
| 112 | * |
| 113 | * @param c Character to place on the terminal |
| 114 | * @throws java.io.IOException If there was an underlying I/O error |
| 115 | */ |
| 116 | void putCharacter(char c) throws IOException; |
| 117 | |
| 118 | /** |
| 119 | * Creates a new TextGraphics object that uses this Terminal directly when outputting. Keep in mind that you are |
| 120 | * probably better off to switch to a Screen to make advanced text graphics more efficient. Also, this TextGraphics |
| 121 | * implementation will not call {@code .flush()} after any operation, so you'll need to do that on your own. |
| 122 | * @return TextGraphics implementation that draws directly using this Terminal interface |
| 123 | */ |
| 124 | TextGraphics newTextGraphics() throws IOException; |
| 125 | |
| 126 | /** |
| 127 | * Activates an {@code SGR} (Selected Graphic Rendition) code. This code modifies a state inside the terminal |
| 128 | * that will apply to all characters written afterwards, such as bold, italic, blinking code and so on. |
| 129 | * |
| 130 | * @param sgr SGR code to apply |
| 131 | * @throws java.io.IOException If there was an underlying I/O error |
| 132 | * @see SGR |
| 133 | * @see <a href="http://www.vt100.net/docs/vt510-rm/SGR">http://www.vt100.net/docs/vt510-rm/SGR</a> |
| 134 | */ |
| 135 | void enableSGR(SGR sgr) throws IOException; |
| 136 | |
| 137 | /** |
| 138 | * Deactivates an {@code SGR} (Selected Graphic Rendition) code which has previously been activated through {@code |
| 139 | * enableSGR(..)}. |
| 140 | * |
| 141 | * @param sgr SGR code to apply |
| 142 | * @throws java.io.IOException If there was an underlying I/O error |
| 143 | * @see SGR |
| 144 | * @see <a href="http://www.vt100.net/docs/vt510-rm/SGR">http://www.vt100.net/docs/vt510-rm/SGR</a> |
| 145 | */ |
| 146 | void disableSGR(SGR sgr) throws IOException; |
| 147 | |
| 148 | /** |
| 149 | * Removes all currently active SGR codes and sets foreground and background colors back to default. |
| 150 | * |
| 151 | * @throws java.io.IOException If there was an underlying I/O error |
| 152 | * @see SGR |
| 153 | * @see <a href="http://www.vt100.net/docs/vt510-rm/SGR">http://www.vt100.net/docs/vt510-rm/SGR</a> |
| 154 | */ |
| 155 | void resetColorAndSGR() throws IOException; |
| 156 | |
| 157 | /** |
| 158 | * Changes the foreground color for all the following characters put to the terminal. The foreground color is what |
| 159 | * color to draw the text in, as opposed to the background color which is the color surrounding the characters. |
| 160 | * <p> |
| 161 | * This overload is using the TextColor class to define a color, which is a layer of abstraction above the three |
| 162 | * different color formats supported (ANSI, indexed and RGB). The other setForegroundColor(..) overloads gives |
| 163 | * you direct access to set one of those three. |
| 164 | * <p> |
| 165 | * Note to implementers of this interface, just make this method call <b>color.applyAsForeground(this);</b> |
| 166 | * |
| 167 | * @param color Color to use for foreground |
| 168 | * @throws java.io.IOException If there was an underlying I/O error |
| 169 | */ |
| 170 | void setForegroundColor(TextColor color) throws IOException; |
| 171 | |
| 172 | /** |
| 173 | * Changes the background color for all the following characters put to the terminal. The background color is the |
| 174 | * color surrounding the text being printed. |
| 175 | * <p> |
| 176 | * This overload is using the TextColor class to define a color, which is a layer of abstraction above the three |
| 177 | * different color formats supported (ANSI, indexed and RGB). The other setBackgroundColor(..) overloads gives |
| 178 | * you direct access to set one of those three. |
| 179 | * <p> |
| 180 | * Note to implementers of this interface, just make this method call <b>color.applyAsBackground(this);</b> |
| 181 | * |
| 182 | * @param color Color to use for the background |
| 183 | * @throws java.io.IOException If there was an underlying I/O error |
| 184 | */ |
| 185 | void setBackgroundColor(TextColor color) throws IOException; |
| 186 | |
| 187 | /** |
| 188 | * Adds a {@code ResizeListener} to be called when the terminal has changed size. There is no guarantee that this |
| 189 | * listener will really be invoked when the terminal has changed size, at all depends on the terminal emulator |
| 190 | * implementation. Normally on Unix systems the WINCH signal will be sent to the process and lanterna can intercept |
| 191 | * this. |
| 192 | * <p> |
| 193 | * There are no guarantees on what thread the call will be made on, so please be careful with what kind of operation |
| 194 | * you perform in this callback. You should probably not take too long to return. |
| 195 | * |
| 196 | * @see ResizeListener |
| 197 | * @param listener Listener object to be called when the terminal has been changed |
| 198 | */ |
| 199 | void addResizeListener(ResizeListener listener); |
| 200 | |
| 201 | /** |
| 202 | * Removes a {@code ResizeListener} from the list of listeners to be notified when the terminal has changed size |
| 203 | * |
| 204 | * @see ResizeListener |
| 205 | * @param listener Listener object to remove |
| 206 | */ |
| 207 | void removeResizeListener(ResizeListener listener); |
| 208 | |
| 209 | /** |
| 210 | * Returns the size of the terminal, expressed as a {@code TerminalSize} object. Please bear in mind that depending |
| 211 | * on the {@code Terminal} implementation, this may or may not be accurate. See the implementing classes for more |
| 212 | * information. Most commonly, calling getTerminalSize() will involve some kind of hack to retrieve the size of the |
| 213 | * terminal, like moving the cursor to position 5000x5000 and then read back the location, unless the terminal |
| 214 | * implementation has a more smooth way of getting this data. Keep this in mind and see if you can avoid calling |
| 215 | * this method too often. There is a helper class, SimpleTerminalResizeListener, that you can use to cache the size |
| 216 | * and update it only when resize events are received (which depends on if a resize is detectable, which they are not |
| 217 | * on all platforms). |
| 218 | * |
| 219 | * @return Size of the terminal |
| 220 | * @throws java.io.IOException if there was an I/O error trying to retrieve the size of the terminal |
| 221 | */ |
| 222 | TerminalSize getTerminalSize() throws IOException; |
| 223 | |
| 224 | /** |
| 225 | * Retrieves optional information from the terminal by printing the ENQ ({@literal \}u005) character. Terminals and terminal |
| 226 | * emulators may or may not respond to this command, sometimes it's configurable. |
| 227 | * |
| 228 | * @param timeout How long to wait for the talk-back message, if there's nothing immediately available on the input |
| 229 | * stream, you should probably set this to a somewhat small value to prevent unnecessary blockage on the input stream |
| 230 | * but large enough to accommodate a round-trip to the user's terminal (~300 ms if you are connection across the globe). |
| 231 | * @param timeoutUnit What unit to use when interpreting the {@code timeout} parameter |
| 232 | * @return Answer-back message from the terminal or empty if there was nothing |
| 233 | * @throws java.io.IOException If there was an I/O error while trying to read the enquiry reply |
| 234 | */ |
| 235 | byte[] enquireTerminal(int timeout, TimeUnit timeoutUnit) throws IOException; |
| 236 | |
| 237 | /** |
| 238 | * Calls {@code flush()} on the underlying {@code OutputStream} object, or whatever other implementation this |
| 239 | * terminal is built around. Some implementing classes of this interface (like SwingTerminal) doesn't do anything |
| 240 | * as it doesn't really apply to them. |
| 241 | * @throws java.io.IOException If there was an underlying I/O error |
| 242 | */ |
| 243 | void flush() throws IOException; |
| 244 | } |