X-Git-Url: http://git.nikiroo.be/?p=jvcard.git;a=blobdiff_plain;f=src%2Fcom%2Fgooglecode%2Flanterna%2Fterminal%2Fansi%2FStreamBasedTerminal.java;fp=src%2Fcom%2Fgooglecode%2Flanterna%2Fterminal%2Fansi%2FStreamBasedTerminal.java;h=0000000000000000000000000000000000000000;hp=a9bbe965237b89692f75a76de7ce2ca6dbc4bcd7;hb=f06c81000632cfb5f525ca458f719338f55f9f66;hpb=a73a906356c971b080c36368e71a15d87e8b8d31 diff --git a/src/com/googlecode/lanterna/terminal/ansi/StreamBasedTerminal.java b/src/com/googlecode/lanterna/terminal/ansi/StreamBasedTerminal.java deleted file mode 100644 index a9bbe96..0000000 --- a/src/com/googlecode/lanterna/terminal/ansi/StreamBasedTerminal.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * This file is part of lanterna (http://code.google.com/p/lanterna/). - * - * lanterna 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 Lesser 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 . - * - * Copyright (C) 2010-2015 Martin - */ -package com.googlecode.lanterna.terminal.ansi; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.nio.CharBuffer; -import java.nio.charset.Charset; - -import com.googlecode.lanterna.Symbols; -import com.googlecode.lanterna.input.InputDecoder; -import com.googlecode.lanterna.input.KeyDecodingProfile; -import com.googlecode.lanterna.input.KeyStroke; -import com.googlecode.lanterna.input.ScreenInfoAction; -import com.googlecode.lanterna.input.ScreenInfoCharacterPattern; -import com.googlecode.lanterna.terminal.AbstractTerminal; -import com.googlecode.lanterna.TerminalPosition; -import com.googlecode.lanterna.TerminalSize; -import java.io.ByteArrayOutputStream; -import java.util.LinkedList; -import java.util.Queue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/** - * An abstract terminal implementing functionality for terminals using OutputStream/InputStream. You can extend from - * this class if your terminal implementation is using standard input and standard output but not ANSI escape codes (in - * which case you should extend ANSITerminal). This class also contains some automatic UTF-8 to VT100 character - * conversion when the terminal is not set to read UTF-8. - * - * @author Martin - */ -public abstract class StreamBasedTerminal extends AbstractTerminal { - - private static final Charset UTF8_REFERENCE = Charset.forName("UTF-8"); - - private final InputStream terminalInput; - private final OutputStream terminalOutput; - private final Charset terminalCharset; - - private final InputDecoder inputDecoder; - private final Queue keyQueue; - private final Lock readLock; - - @SuppressWarnings("WeakerAccess") - public StreamBasedTerminal(InputStream terminalInput, OutputStream terminalOutput, Charset terminalCharset) { - this.terminalInput = terminalInput; - this.terminalOutput = terminalOutput; - if(terminalCharset == null) { - this.terminalCharset = Charset.defaultCharset(); - } - else { - this.terminalCharset = terminalCharset; - } - this.inputDecoder = new InputDecoder(new InputStreamReader(this.terminalInput, this.terminalCharset)); - this.keyQueue = new LinkedList(); - this.readLock = new ReentrantLock(); - //noinspection ConstantConditions - } - - /** - * {@inheritDoc} - * - * The {@code StreamBasedTerminal} class will attempt to translate some unicode characters to VT100 if the encoding - * attached to this {@code Terminal} isn't UTF-8. - */ - @Override - public void putCharacter(char c) throws IOException { - writeToTerminal(translateCharacter(c)); - } - - /** - * This method will write a list of bytes directly to the output stream of the terminal. - * @param bytes Bytes to write to the terminal (synchronized) - * @throws java.io.IOException If there was an underlying I/O error - */ - @SuppressWarnings("WeakerAccess") - protected void writeToTerminal(byte... bytes) throws IOException { - synchronized(terminalOutput) { - terminalOutput.write(bytes); - } - } - - @Override - public byte[] enquireTerminal(int timeout, TimeUnit timeoutTimeUnit) throws IOException { - synchronized(terminalOutput) { - terminalOutput.write(5); //ENQ - flush(); - } - - //Wait for input - long startTime = System.currentTimeMillis(); - while(terminalInput.available() == 0) { - if(System.currentTimeMillis() - startTime > timeoutTimeUnit.toMillis(timeout)) { - return new byte[0]; - } - try { - Thread.sleep(1); - } - catch(InterruptedException e) { - return new byte[0]; - } - } - - //We have at least one character, read as far as we can and return - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - while(terminalInput.available() > 0) { - buffer.write(terminalInput.read()); - } - return buffer.toByteArray(); - } - - /** - * Adds a KeyDecodingProfile to be used when converting raw user input characters to {@code Key} objects. - * - * @see KeyDecodingProfile - * @param profile Decoding profile to add - * @deprecated Use {@code getInputDecoder().addProfile(profile)} instead - */ - @Deprecated - @SuppressWarnings("WeakerAccess") - public void addKeyDecodingProfile(KeyDecodingProfile profile) { - inputDecoder.addProfile(profile); - } - - /** - * Returns the {@code InputDecoder} attached to this {@code StreamBasedTerminal}. Can be used to add additional - * character patterns to recognize and tune the way input is turned in {@code KeyStroke}:s. - * @return {@code InputDecoder} attached to this {@code StreamBasedTerminal} - */ - public InputDecoder getInputDecoder() { - return inputDecoder; - } - - @SuppressWarnings("ConstantConditions") - TerminalSize waitForTerminalSizeReport() throws IOException { - long startTime = System.currentTimeMillis(); - readLock.lock(); - try { - while(true) { - KeyStroke key = inputDecoder.getNextCharacter(false); - if(key == null) { - if(System.currentTimeMillis() - startTime > 1000) { //Wait 1 second for the terminal size report to come, is this reasonable? - throw new IOException( - "Timeout while waiting for terminal size report! Your terminal may have refused to go into cbreak mode."); - } - try { - Thread.sleep(1); - } - catch(InterruptedException ignored) {} - continue; - } - - // check both: real ScreenInfoActions and F3 keystrokes with modifiers: - ScreenInfoAction report = ScreenInfoCharacterPattern.tryToAdopt(key); - if (report == null) { - keyQueue.add(key); - } - else { - TerminalPosition reportedTerminalPosition = report.getPosition(); - onResized(reportedTerminalPosition.getColumn(), reportedTerminalPosition.getRow()); - return new TerminalSize(reportedTerminalPosition.getColumn(), reportedTerminalPosition.getRow()); - } - } - } - finally { - readLock.unlock(); - } - } - - @Override - public KeyStroke pollInput() throws IOException { - return readInput(false); - } - - @Override - public KeyStroke readInput() throws IOException { - return readInput(true); - } - - private KeyStroke readInput(boolean blocking) throws IOException { - readLock.lock(); - try { - if(!keyQueue.isEmpty()) { - return keyQueue.poll(); - } - KeyStroke key = inputDecoder.getNextCharacter(blocking); - if (key instanceof ScreenInfoAction) { - TerminalPosition reportedTerminalPosition = ((ScreenInfoAction)key).getPosition(); - onResized(reportedTerminalPosition.getColumn(), reportedTerminalPosition.getRow()); - return pollInput(); - } else { - return key; - } - } - finally { - readLock.unlock(); - } - } - - @Override - public void flush() throws IOException { - synchronized(terminalOutput) { - terminalOutput.flush(); - } - } - - protected Charset getCharset() { - return terminalCharset; - } - - @SuppressWarnings("WeakerAccess") - protected byte[] translateCharacter(char input) { - if(UTF8_REFERENCE != null && UTF8_REFERENCE == terminalCharset) { - return convertToCharset(input); - } - //Convert ACS to ordinary terminal codes - switch(input) { - case Symbols.ARROW_DOWN: - return convertToVT100('v'); - case Symbols.ARROW_LEFT: - return convertToVT100('<'); - case Symbols.ARROW_RIGHT: - return convertToVT100('>'); - case Symbols.ARROW_UP: - return convertToVT100('^'); - case Symbols.BLOCK_DENSE: - case Symbols.BLOCK_MIDDLE: - case Symbols.BLOCK_SOLID: - case Symbols.BLOCK_SPARSE: - return convertToVT100((char) 97); - case Symbols.HEART: - case Symbols.CLUB: - case Symbols.SPADES: - return convertToVT100('?'); - case Symbols.FACE_BLACK: - case Symbols.FACE_WHITE: - case Symbols.DIAMOND: - return convertToVT100((char) 96); - case Symbols.BULLET: - return convertToVT100((char) 102); - case Symbols.DOUBLE_LINE_CROSS: - case Symbols.SINGLE_LINE_CROSS: - return convertToVT100((char) 110); - case Symbols.DOUBLE_LINE_HORIZONTAL: - case Symbols.SINGLE_LINE_HORIZONTAL: - return convertToVT100((char) 113); - case Symbols.DOUBLE_LINE_BOTTOM_LEFT_CORNER: - case Symbols.SINGLE_LINE_BOTTOM_LEFT_CORNER: - return convertToVT100((char) 109); - case Symbols.DOUBLE_LINE_BOTTOM_RIGHT_CORNER: - case Symbols.SINGLE_LINE_BOTTOM_RIGHT_CORNER: - return convertToVT100((char) 106); - case Symbols.DOUBLE_LINE_T_DOWN: - case Symbols.SINGLE_LINE_T_DOWN: - case Symbols.DOUBLE_LINE_T_SINGLE_DOWN: - case Symbols.SINGLE_LINE_T_DOUBLE_DOWN: - return convertToVT100((char) 119); - case Symbols.DOUBLE_LINE_T_LEFT: - case Symbols.SINGLE_LINE_T_LEFT: - case Symbols.DOUBLE_LINE_T_SINGLE_LEFT: - case Symbols.SINGLE_LINE_T_DOUBLE_LEFT: - return convertToVT100((char) 117); - case Symbols.DOUBLE_LINE_T_RIGHT: - case Symbols.SINGLE_LINE_T_RIGHT: - case Symbols.DOUBLE_LINE_T_SINGLE_RIGHT: - case Symbols.SINGLE_LINE_T_DOUBLE_RIGHT: - return convertToVT100((char) 116); - case Symbols.DOUBLE_LINE_T_UP: - case Symbols.SINGLE_LINE_T_UP: - case Symbols.DOUBLE_LINE_T_SINGLE_UP: - case Symbols.SINGLE_LINE_T_DOUBLE_UP: - return convertToVT100((char) 118); - case Symbols.DOUBLE_LINE_TOP_LEFT_CORNER: - case Symbols.SINGLE_LINE_TOP_LEFT_CORNER: - return convertToVT100((char) 108); - case Symbols.DOUBLE_LINE_TOP_RIGHT_CORNER: - case Symbols.SINGLE_LINE_TOP_RIGHT_CORNER: - return convertToVT100((char) 107); - case Symbols.DOUBLE_LINE_VERTICAL: - case Symbols.SINGLE_LINE_VERTICAL: - return convertToVT100((char) 120); - default: - return convertToCharset(input); - } - } - - private byte[] convertToVT100(char code) { - //Warning! This might be terminal type specific!!!! - //So far it's worked everywhere I've tried it (xterm, gnome-terminal, putty) - return new byte[]{27, 40, 48, (byte) code, 27, 40, 66}; - } - - private byte[] convertToCharset(char input) { - return terminalCharset.encode(Character.toString(input)).array(); - } -}