Skip to content

Commit 36d811e

Browse files
committed
Fixed: Parse (but ignore for now) terminal APC sequences
1 parent c2d57f2 commit 36d811e

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

terminal-emulator/src/main/java/com/termux/terminal/TerminalEmulator.java

+40
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public final class TerminalEmulator {
7979
private static final int ESC_CSI_SINGLE_QUOTE = 18;
8080
/** Escape processing: CSI ! */
8181
private static final int ESC_CSI_EXCLAMATION = 19;
82+
/** Escape processing: "ESC _" or Application Program Command (APC). */
83+
private static final int ESC_APC = 20;
84+
/** Escape processing: "ESC _" or Application Program Command (APC), followed by Escape. */
85+
private static final int ESC_APC_ESCAPE = 21;
8286

8387
/** The number of parameter arguments. This name comes from the ANSI standard for terminal escape codes. */
8488
private static final int MAX_ESCAPE_PARAMETERS = 16;
@@ -548,6 +552,15 @@ private void processByte(byte byteToProcess) {
548552
}
549553

550554
public void processCodePoint(int b) {
555+
// The Application Program-Control (APC) string might be arbitrary non-printable characters, so handle that early.
556+
if (mEscapeState == ESC_APC) {
557+
doApc(b);
558+
return;
559+
} else if (mEscapeState == ESC_APC_ESCAPE) {
560+
doApcEscape(b);
561+
return;
562+
}
563+
551564
switch (b) {
552565
case 0: // Null character (NUL, ^@). Do nothing.
553566
break;
@@ -1004,6 +1017,30 @@ private void doDeviceControl(int b) {
10041017
}
10051018
}
10061019

1020+
/**
1021+
* When in {@link #ESC_APC} (APC, Application Program Command) sequence.
1022+
*/
1023+
private void doApc(int b) {
1024+
if (b == 27) {
1025+
continueSequence(ESC_APC_ESCAPE);
1026+
}
1027+
// Eat APC sequences silently for now.
1028+
}
1029+
1030+
/**
1031+
* When in {@link #ESC_APC} (APC, Application Program Command) sequence.
1032+
*/
1033+
private void doApcEscape(int b) {
1034+
if (b == '\\') {
1035+
// A String Terminator (ST), ending the APC escape sequence.
1036+
finishSequence();
1037+
} else {
1038+
// The Escape character was not the start of a String Terminator (ST),
1039+
// but instead just data inside of the APC escape sequence.
1040+
continueSequence(ESC_APC);
1041+
}
1042+
}
1043+
10071044
private int nextTabStop(int numTabs) {
10081045
for (int i = mCursorCol + 1; i < mColumns; i++)
10091046
if (mTabStop[i] && --numTabs == 0) return Math.min(i, mRightMargin);
@@ -1399,6 +1436,9 @@ private void doEsc(int b) {
13991436
case '>': // DECKPNM
14001437
setDecsetinternalBit(DECSET_BIT_APPLICATION_KEYPAD, false);
14011438
break;
1439+
case '_': // APC - Application Program Command.
1440+
continueSequence(ESC_APC);
1441+
break;
14021442
default:
14031443
unknownSequence(b);
14041444
break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.termux.terminal;
2+
3+
public class ApcTest extends TerminalTestCase {
4+
5+
public void testApcConsumed() {
6+
// At time of writing this is part of what yazi sends for probing for kitty graphics protocol support:
7+
// https://github.com/sxyazi/yazi/blob/0cdaff98d0b3723caff63eebf1974e7907a43a2c/yazi-adapter/src/emulator.rs#L129
8+
// This should not result in anything being written to the screen: If kitty graphics protocol support
9+
// is implemented it should instead result in an error code on stdin, and if not it should be consumed
10+
// silently just as xterm does. See https://sw.kovidgoyal.net/kitty/graphics-protocol/.
11+
withTerminalSized(2, 2)
12+
.enterString("\033_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\033\\")
13+
.assertLinesAre(" ", " ");
14+
15+
// It is ok for the APC content to be non printable characters:
16+
withTerminalSized(12, 2)
17+
.enterString("hello \033_some\023\033_\\apc#end\033\\ world")
18+
.assertLinesAre("hello world", " ");
19+
}
20+
21+
}

0 commit comments

Comments
 (0)