How do I send the input of the user, user input only, to the outputstream?
I\'m currently using a keylistner,
jTextArea console = new jTextArea;
con
Okay, so this is my idea...
The basic idea is we want to keep track of "user" input and "process" output.
Basically what I've done is set it up so that when the process terminates, we calculate the current position of the caret in the document and mark that as the start position of the user input.
This example doesn't include writing output to the process, you can slide that in ;)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.BadLocationException;
import org.w3c.dom.ls.LSException;
public class QuickTerminal {
public static void main(String[] args) {
new QuickTerminal();
}
public QuickTerminal() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ConsolePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface CommandListener {
public void commandOutput(String text);
public void commandCompleted(String cmd, int result);
public void commandFailed(Exception exp);
}
public class ConsolePane extends JPanel implements CommandListener {
private JTextArea textArea;
private int userInputStart = 0;
private Command cmd;
public ConsolePane() {
cmd = new Command(this);
setLayout(new BorderLayout());
textArea = new JTextArea(20, 30);
add(new JScrollPane(textArea));
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
int range = textArea.getCaretPosition() - userInputStart;
try {
String text = textArea.getText(userInputStart, range).trim();
System.out.println("[" + text + "]");
userInputStart += range;
if (!cmd.isRunning()) {
cmd.execute(text);
} else {
}
} catch (BadLocationException ex) {
Logger.getLogger(QuickTerminal.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
// if (!cmd.isRunning()) {
// cmd.send(...);
// }
}
}
});
}
@Override
public void commandOutput(String text) {
SwingUtilities.invokeLater(new AppendTask(textArea, text));
}
@Override
public void commandFailed(Exception exp) {
SwingUtilities.invokeLater(new AppendTask(textArea, "Command failed - " + exp.getMessage()));
}
@Override
public void commandCompleted(String cmd, int result) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int pos = textArea.getCaretPosition();
System.out.println("pos = " + pos + "; length = " + textArea.getText().length());
textArea.setCaretPosition(textArea.getText().length());
userInputStart = pos;
}
});
}
}
public class AppendTask implements Runnable {
private JTextArea textArea;
private String text;
public AppendTask(JTextArea textArea, String text) {
this.textArea = textArea;
this.text = text;
}
@Override
public void run() {
textArea.append(text);
}
}
public class Command {
private CommandListener listener;
private ProcessRunner runner;
public Command(CommandListener listener) {
this.listener = listener;
}
public boolean isRunning() {
return runner != null && runner.isAlive();
}
public void execute(String cmd) {
if (!cmd.trim().isEmpty()) {
List<String> values = new ArrayList<>(25);
if (cmd.contains("\"")) {
while (cmd.contains("\"")) {
String start = cmd.substring(0, cmd.indexOf("\""));
cmd = cmd.substring(start.length());
String quote = cmd.substring(cmd.indexOf("\"") + 1);
cmd = cmd.substring(cmd.indexOf("\"") + 1);
quote = quote.substring(0, cmd.indexOf("\""));
cmd = cmd.substring(cmd.indexOf("\"") + 1);
if (!start.trim().isEmpty()) {
String parts[] = start.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
values.add(quote.trim());
}
if (!cmd.trim().isEmpty()) {
String parts[] = cmd.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
for (String value : values) {
System.out.println("[" + value + "]");
}
} else {
if (!cmd.trim().isEmpty()) {
String parts[] = cmd.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
}
runner = new ProcessRunner(listener, values);
}
}
public void send(String cmd) {
// Send user input to the running process...
}
}
public class ProcessRunner extends Thread {
private List<String> cmds;
private CommandListener listener;
public ProcessRunner(CommandListener listener, List<String> cmds) {
this.cmds = cmds;
this.listener = listener;
start();
}
@Override
public void run() {
try {
System.out.println("cmds = " + cmds);
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.redirectErrorStream();
Process p = pb.start();
StreamReader reader = new StreamReader(listener, p.getInputStream());
// Need a stream writer...
int result = p.waitFor();
// Terminate the stream writer
reader.join();
listener.commandCompleted(null, result);
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
public class StreamReader extends Thread {
private InputStream is;
private CommandListener listener;
public StreamReader(CommandListener listener, InputStream is) {
this.is = is;
this.listener = listener;
start();
}
@Override
public void run() {
try {
int value = -1;
while ((value = is.read()) != -1) {
listener.commandOutput(Character.toString((char) value));
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
PS- I was running this on my Mac, so you might need to put in a call to "cmd" for Windows... ;)
PPS- This is an incomplete example, if it wasn't 1am I might fill it in, but, this doesn't stop the user from pressing back space beyond the last known user input position. If I was going to fix this, I would use a DocumentFilter
and simply "protect" all the text before the user position, disallowing the user from removing it
Updated with "Protected DocumentFilter" example
Added a "protected" DocumentFilter
to protected areas of the Document
that the user should no longer be allowed to edit.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class QuickTerminal {
public static void main(String[] args) {
new QuickTerminal();
}
public QuickTerminal() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ConsolePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface CommandListener {
public void commandOutput(String text);
public void commandCompleted(String cmd, int result);
public void commandFailed(Exception exp);
}
public class ConsolePane extends JPanel implements CommandListener, UserInput {
private JTextArea textArea;
private int userInputStart = 0;
private Command cmd;
public ConsolePane() {
cmd = new Command(this);
setLayout(new BorderLayout());
textArea = new JTextArea(20, 30);
((AbstractDocument)textArea.getDocument()).setDocumentFilter(new ProtectedDocumentFilter(this));
add(new JScrollPane(textArea));
textArea.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
int range = textArea.getCaretPosition() - userInputStart;
try {
String text = textArea.getText(userInputStart, range).trim();
System.out.println("[" + text + "]");
userInputStart += range;
if (!cmd.isRunning()) {
cmd.execute(text);
} else {
}
} catch (BadLocationException ex) {
Logger.getLogger(QuickTerminal.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
// if (!cmd.isRunning()) {
// cmd.send(...);
// }
}
}
});
}
@Override
public void commandOutput(String text) {
SwingUtilities.invokeLater(new AppendTask(textArea, text));
}
@Override
public void commandFailed(Exception exp) {
SwingUtilities.invokeLater(new AppendTask(textArea, "Command failed - " + exp.getMessage()));
}
@Override
public void commandCompleted(String cmd, int result) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int pos = textArea.getCaretPosition();
System.out.println("pos = " + pos + "; length = " + textArea.getText().length());
textArea.setCaretPosition(textArea.getText().length());
userInputStart = pos;
}
});
}
@Override
public int getUserInputStart() {
return userInputStart;
}
}
public interface UserInput {
public int getUserInputStart();
}
public class AppendTask implements Runnable {
private JTextArea textArea;
private String text;
public AppendTask(JTextArea textArea, String text) {
this.textArea = textArea;
this.text = text;
}
@Override
public void run() {
textArea.append(text);
}
}
public class Command {
private CommandListener listener;
private ProcessRunner runner;
public Command(CommandListener listener) {
this.listener = listener;
}
public boolean isRunning() {
return runner != null && runner.isAlive();
}
public void execute(String cmd) {
if (!cmd.trim().isEmpty()) {
List<String> values = new ArrayList<>(25);
if (cmd.contains("\"")) {
while (cmd.contains("\"")) {
String start = cmd.substring(0, cmd.indexOf("\""));
cmd = cmd.substring(start.length());
String quote = cmd.substring(cmd.indexOf("\"") + 1);
cmd = cmd.substring(cmd.indexOf("\"") + 1);
quote = quote.substring(0, cmd.indexOf("\""));
cmd = cmd.substring(cmd.indexOf("\"") + 1);
if (!start.trim().isEmpty()) {
String parts[] = start.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
values.add(quote.trim());
}
if (!cmd.trim().isEmpty()) {
String parts[] = cmd.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
for (String value : values) {
System.out.println("[" + value + "]");
}
} else {
if (!cmd.trim().isEmpty()) {
String parts[] = cmd.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
}
runner = new ProcessRunner(listener, values);
}
}
public void send(String cmd) {
// Send user input to the running process...
}
}
public class ProcessRunner extends Thread {
private List<String> cmds;
private CommandListener listener;
public ProcessRunner(CommandListener listener, List<String> cmds) {
this.cmds = cmds;
this.listener = listener;
start();
}
@Override
public void run() {
try {
System.out.println("cmds = " + cmds);
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.redirectErrorStream();
Process p = pb.start();
StreamReader reader = new StreamReader(listener, p.getInputStream());
// Need a stream writer...
int result = p.waitFor();
// Terminate the stream writer
reader.join();
listener.commandCompleted(null, result);
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
public class StreamReader extends Thread {
private InputStream is;
private CommandListener listener;
public StreamReader(CommandListener listener, InputStream is) {
this.is = is;
this.listener = listener;
start();
}
@Override
public void run() {
try {
int value = -1;
while ((value = is.read()) != -1) {
listener.commandOutput(Character.toString((char) value));
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
public class ProtectedDocumentFilter extends DocumentFilter {
private UserInput userInput;
public ProtectedDocumentFilter(UserInput userInput) {
this.userInput = userInput;
}
public UserInput getUserInput() {
return userInput;
}
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.remove(fb, offset, length); //To change body of generated methods, choose Tools | Templates.
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.replace(fb, offset, length, text, attrs); //To change body of generated methods, choose Tools | Templates.
}
}
}
}
I would suggest that when any other key is released, if starflag = true you store the start, and set startflag to false as you said, and when "enter" is actually pressed, you can do startflag = true; and store the end as the getCaretPosition().
My understanding of your intentions beyond that is slightly vague, but here are my ideas: If you have an entire "conversation" of sorts going on in your console, and you want ALL of the user entries, then you could simply use an ArrayList userinputs, and instead of start = console.getCaretPosition(), you could do userinputs.add(new Point(console.getCaretPosition(),-1)); and then when the user ends his input(or before STDOUT sends input), do userinputs.get(userinputs.size()-1).y = console.getCaretPosition()(Or you could store a temporary point, and only add the point upon it's completion - when it get an end as well.)
If you are sending the user input to the output whenever the enter key is pressed, then I don't see what more is needed than the simple code above, that essentially works like this:
public void keyReleased(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_ENTER){
startflag = true;
//Just get the text from the start(stored below), and up until where the caret is now, as the users output.
}else{
if(startflag){
start = console.getCaretPosition()
startflag = false;
}
}
}