/* * 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 <http://www.gnu.org/licenses/>. * * Copyright (C) 2010-2017 Martin Berglund */ package com.googlecode.lanterna.terminal; import com.googlecode.lanterna.TestTerminalFactory; import com.googlecode.lanterna.input.KeyStroke; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * * @author martin */ public class PseudoTerminal { public static void main(String[] args) throws InterruptedException, IOException { final Terminal rawTerminal = new TestTerminalFactory(args).createTerminal(); //assume bash is available Process bashProcess = Runtime.getRuntime().exec("bash", makeEnvironmentVariables()); ProcessOutputReader stdout = new ProcessOutputReader(bashProcess.getInputStream(), rawTerminal); ProcessOutputReader stderr = new ProcessOutputReader(bashProcess.getErrorStream(), rawTerminal); ProcessInputWriter stdin = new ProcessInputWriter(bashProcess.getOutputStream(), rawTerminal); stdout.start(); stderr.start(); stdin.start(); int returnCode = bashProcess.waitFor(); stdout.stop(); stderr.stop(); stdin.stop(); System.exit(returnCode); } private static String[] makeEnvironmentVariables() { List<String> environment = new ArrayList<String>(); Map<String, String> env = new TreeMap<String, String>(System.getenv()); env.put("TERM", "xterm"); //Will this make bash detect us as a proper terminal?? for(String key : env.keySet()) { environment.add(key + "=" + env.get(key)); } return environment.toArray(new String[environment.size()]); } private static class ProcessOutputReader { private final InputStreamReader inputStreamReader; private final Terminal terminalEmulator; private boolean stop; public ProcessOutputReader(InputStream inputStream, Terminal terminalEmulator) { this.inputStreamReader = new InputStreamReader(inputStream, Charset.defaultCharset()); this.terminalEmulator = terminalEmulator; this.stop = false; } private void start() { new Thread("OutputReader") { @Override public void run() { try { char[] buffer = new char[1024]; int readCharacters = inputStreamReader.read(buffer); while(readCharacters != -1 && !stop) { if(readCharacters > 0) { for(int i = 0; i < readCharacters; i++) { terminalEmulator.putCharacter(buffer[i]); } terminalEmulator.flush(); } else { try { Thread.sleep(1); } catch(InterruptedException e) { } } readCharacters = inputStreamReader.read(buffer); } } catch(IOException e) { e.printStackTrace(); } finally { try { inputStreamReader.close(); } catch(IOException e) { } } } }.start(); } private void stop() { stop = true; } } private static class ProcessInputWriter { private final OutputStream outputStream; private final Terminal terminalEmulator; private boolean stop; public ProcessInputWriter(OutputStream outputStream, Terminal terminalEmulator) { this.outputStream = outputStream; this.terminalEmulator = terminalEmulator; this.stop = false; } private void start() { new Thread("InputWriter") { @Override public void run() { try { while(!stop) { KeyStroke keyStroke = terminalEmulator.pollInput(); if(keyStroke == null) { Thread.sleep(1); } else { switch(keyStroke.getKeyType()) { case Character: writeCharacter(keyStroke.getCharacter()); break; case Enter: writeCharacter('\n'); break; case Backspace: writeCharacter('\b'); break; case Tab: writeCharacter('\t'); break; default: } flush(); } } } catch(IOException e) { } catch(InterruptedException e) { } finally { try { outputStream.close(); } catch(IOException e) { } } } }.start(); } private void writeCharacter(char character) throws IOException { outputStream.write(character); terminalEmulator.putCharacter(character); } private void flush() throws IOException { outputStream.flush(); terminalEmulator.flush(); } private void stop() { stop = true; } } }