diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java index 3ef6a558..706f3458 100644 --- a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java @@ -7,6 +7,14 @@ public DSR(final Terminal terminal) { super(terminal); } + @Override + public int[] defaultParameters(CSIState state) { + // Ps omitted (or 0) defaults to 5 — device status report. CSIManager substitutes + // this before execute, so a bare CSI n replies \033[0n instead of hanging the guest + // waiting for a status response that never comes (§36 m4). + return new int[] {5}; + } + @Override public void execute(int[] args, int argCount, CSIState state) { if (args[0] == 5) { diff --git a/src/test/java/li/cil/oc2/common/vm/terminal/TerminalBufferTest.java b/src/test/java/li/cil/oc2/common/vm/terminal/TerminalBufferTest.java index 4bd87707..6e392814 100644 --- a/src/test/java/li/cil/oc2/common/vm/terminal/TerminalBufferTest.java +++ b/src/test/java/li/cil/oc2/common/vm/terminal/TerminalBufferTest.java @@ -130,6 +130,32 @@ void vpaMovesRowOnly() { assertEquals(6, terminal.y); } + @Test + void dsrBareCsiNRepliesStatus() { + // §36 m4: DSR (CSI Ps n) with no Ps defaults to Ps=5 (device status). CSIManager + // substitutes the handler's defaultParameters before execute, so a bare CSI n + // replies \033[0n instead of hanging a guest waiting for a status response. + write(terminal, CSI + "n"); + final ByteBuffer reply = terminal.io.getInput(); + assertNotNull(reply, "bare CSI n must produce a status-report reply"); + final byte[] bytes = new byte[reply.remaining()]; + reply.get(bytes); + assertEquals("\033[0n", new String(bytes, StandardCharsets.US_ASCII), + "bare CSI n replies operating-status (\\033[0n)"); + } + + @Test + void dsrExplicitFiveStillRepliesStatus() { + // Explicit Ps=5 is unchanged by the defaultParameters fix — still a status report. + write(terminal, CSI + "5n"); + final ByteBuffer reply = terminal.io.getInput(); + assertNotNull(reply, "CSI 5n must produce a status-report reply"); + final byte[] bytes = new byte[reply.remaining()]; + reply.get(bytes); + assertEquals("\033[0n", new String(bytes, StandardCharsets.US_ASCII), + "CSI 5n replies operating-status (\\033[0n)"); + } + @Test void cudMovesCursorDownAndClampsSaturatedCount() { // parseArgument saturates at Integer.MAX_VALUE; terminal.y + args[0] must not overflow to a