A new oracle, TerminalWindowRun, types into Java's own command line window: the window writes each line after its prompt, takes a blank line, cls, reset and exit itself, keeps the lines for the arrow keys, and keeps its text, history and working directory over a stop and a start. The room now holds a command line window per computer for everyone (TerminalWindow), kept over stops; the protocol carries its lines and the one way to read them (terminalScreen); the core goes on in the working directory of the run before (continueIn). The desktop opens programs in Java's frame, and the command line works with keyboard and finger: grey on black, the prompt hidden while a command runs, history, chips for the commands, Ctrl+C. The room's failure is now tested in the browser. Fixed: the room handed the engine the wall clock with fractions of a millisecond, and a ping hung after its first timeout. The engine and the room count whole milliseconds, as Java's clock does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
109 lines
4.8 KiB
Java
109 lines
4.8 KiB
Java
// Types into FILIUS' own command line window (GUIApplicationTerminalWindow on
|
|
// a GUIDesktopPanel) of a computer without a network, key by key as its key
|
|
// listener hears them, and writes after each key what the window shows: its
|
|
// text, its prompt and whether the prompt is shown, the input line. Then the
|
|
// simulation is stopped and started again (beenden, starten), as a change of
|
|
// mode does, and the window and the working directory are read again: the
|
|
// reference for the editor's command line window (packages/sim/test/
|
|
// terminalWindow.test.ts).
|
|
//
|
|
// Usage: java -cp filius.jar:lib/*:classes TerminalWindowRun <output json>
|
|
|
|
import filius.gui.anwendungssicht.GUIApplicationTerminalWindow;
|
|
import filius.gui.anwendungssicht.GUIDesktopPanel;
|
|
import filius.hardware.knoten.Rechner;
|
|
import filius.software.system.Betriebssystem;
|
|
|
|
import java.awt.event.KeyEvent;
|
|
import java.awt.event.KeyListener;
|
|
import java.io.FileOutputStream;
|
|
import java.lang.reflect.Field;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JTextArea;
|
|
import javax.swing.JTextField;
|
|
|
|
public class TerminalWindowRun {
|
|
static final String TERMINAL = "filius.software.lokal.Terminal";
|
|
|
|
static Object field(Object owner, String name) throws Exception {
|
|
Field field = GUIApplicationTerminalWindow.class.getDeclaredField(name);
|
|
field.setAccessible(true);
|
|
return field.get(owner);
|
|
}
|
|
|
|
static Map<String, Object> shown(GUIApplicationTerminalWindow window, String step) throws Exception {
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
|
result.put("step", step);
|
|
result.put("text", ((JTextArea) field(window, "terminalField")).getText());
|
|
JLabel label = (JLabel) field(window, "inputLabel");
|
|
result.put("prompt", label.getText());
|
|
result.put("promptShown", label.isVisible());
|
|
result.put("input", ((JTextField) field(window, "inputField")).getText());
|
|
return result;
|
|
}
|
|
|
|
static void press(JTextField input, int key, int modifiers) {
|
|
KeyEvent event = new KeyEvent(input, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), modifiers, key, KeyEvent.CHAR_UNDEFINED);
|
|
for (KeyListener listener : input.getKeyListeners()) listener.keyPressed(event);
|
|
}
|
|
|
|
/** Waits until the program has answered: the prompt is shown again (or a second passed). */
|
|
static void settle(GUIApplicationTerminalWindow window) throws Exception {
|
|
JLabel label = (JLabel) field(window, "inputLabel");
|
|
for (int waited = 0; waited < 2000 && !label.isVisible(); waited += 20) Thread.sleep(20);
|
|
Thread.sleep(200);
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
try {
|
|
run(args);
|
|
} catch (Throwable error) {
|
|
error.printStackTrace();
|
|
System.exit(1);
|
|
}
|
|
System.exit(0);
|
|
}
|
|
|
|
static void run(String[] args) throws Exception {
|
|
Rechner host = new Rechner();
|
|
Betriebssystem system = (Betriebssystem) host.getSystemSoftware();
|
|
system.installApp(TERMINAL, true);
|
|
system.starten();
|
|
GUIDesktopPanel desktop = new GUIDesktopPanel(system);
|
|
GUIApplicationTerminalWindow window = (GUIApplicationTerminalWindow) desktop.starteAnwendung(TERMINAL);
|
|
JTextField input = (JTextField) field(window, "inputField");
|
|
List<Object> steps = new ArrayList<>();
|
|
steps.add(shown(window, "open"));
|
|
// A line typed and entered ("type:<line>"), a key ("up", "down", "ctrl+c"), a stop and start ("restart").
|
|
String[] keys = { "enter:", "enter: ", "enter:pwd", "enter:mkdir dir", "enter:cd dir", "enter:pwd", "enter:nosuchcommand", "up", "up", "up", "down", "down", "down",
|
|
"enter:cls", "enter:ls", "restart", "enter:pwd", "up", "enter:exit" };
|
|
for (String key : keys) {
|
|
if (key.startsWith("enter:")) {
|
|
input.setText(key.substring("enter:".length()));
|
|
press(input, KeyEvent.VK_ENTER, 0);
|
|
settle(window);
|
|
} else if (key.equals("up")) {
|
|
press(input, KeyEvent.VK_UP, 0);
|
|
} else if (key.equals("down")) {
|
|
press(input, KeyEvent.VK_DOWN, 0);
|
|
} else if (key.equals("restart")) {
|
|
system.beenden();
|
|
system.starten();
|
|
Thread.sleep(300);
|
|
}
|
|
steps.add(shown(window, key));
|
|
}
|
|
Map<String, Object> output = new LinkedHashMap<>();
|
|
output.put("steps", steps);
|
|
try (FileOutputStream out = new FileOutputStream(args[0])) {
|
|
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
System.out.println("terminal window steps: " + steps.size());
|
|
}
|
|
}
|