好吧,这就是我的想法……
基本思想是我们要跟踪“用户”输入和“进程”输出。
基本上我所做的是设置它,以便当进程终止时,我们计算文档中插入符号的当前位置并将其标记为用户输入的开始位置。
此示例不包括将输出写入进程,您可以将其滑入;)
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-我在我的 Mac 上运行它,所以你可能需要为 Windows 调用“cmd”...;)
PPS- 这是一个不完整的示例,如果不是凌晨 1 点,我可能会填写它,但是,这不会阻止用户按下最后一个已知用户输入位置之外的空格。如果我要解决这个问题,我会使用 aDocumentFilter
并简单地“保护”用户位置之前的所有文本,不允许用户删除它
更新了“受保护的 DocumentFilter”示例
向不应再允许用户编辑的DocumentFilter
受保护区域添加了“受保护” 。Document
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.
}
}
}
}