@@ -26,10 +26,69 @@ private void readStream(InputStream inputStream, final ShellHandlerBase shellHan
2626 InputStreamReader isr = new InputStreamReader (inputStream , StandardCharsets .UTF_8 );
2727 StringBuilder buffer = new StringBuilder ();
2828 int ch ;
29+ // Trạng thái nhận diện escape sequence đang đọc dở, để có thể flush ngay khi 1 escape
30+ // sequence (vd ESC[2J của lệnh `clear`) vừa đọc xong, thay vì phải đợi tới '\n'/'\r'
31+ // tiếp theo mới gửi đi. Rất nhiều escape sequence (clear màn hình, di chuyển con trỏ...)
32+ // KHÔNG kèm theo newline, nên nếu chỉ flush theo '\n'/'\r' như trước đây, dữ liệu clear
33+ // sẽ bị kẹt lại trong buffer của thread đọc này và không bao giờ tới được UI cho tới khi
34+ // có dòng output tiếp theo (hoặc tiến trình kết thúc) -> lệnh `clear` trông như "không xoá"
35+ // hoặc xoá bị trễ/xoá nhầm nội dung không liên quan.
36+ // 0 = bình thường, 1 = vừa gặp ESC (chờ ký tự kế tiếp để biết loại), 2 = trong chuỗi CSI
37+ // (ESC[...), chờ finalByte, 3 = trong chuỗi OSC (ESC]...), chờ BEL hoặc ESC\, 4 = trong
38+ // OSC vừa gặp ESC, chờ '\' để xác nhận kết thúc (ST).
39+ int escState = 0 ;
2940 while ((ch = isr .read ()) != -1 ) {
3041 char c = (char ) ch ;
3142 buffer .append (c );
32- if (c == '\n' || c == '\r' ) {
43+ boolean flush = false ;
44+
45+ switch (escState ) {
46+ case 0 :
47+ if (c == '\u001B' ) {
48+ escState = 1 ;
49+ } else if (c == '\n' || c == '\r' ) {
50+ flush = true ;
51+ }
52+ break ;
53+ case 1 :
54+ if (c == '[' ) {
55+ escState = 2 ; // CSI
56+ } else if (c == ']' ) {
57+ escState = 3 ; // OSC
58+ } else {
59+ // Escape đơn (vd ESC( ESC) ESC= ESC>...) coi như đã hoàn chỉnh ngay sau
60+ // ký tự này -> flush luôn để không bị kẹt buffer.
61+ escState = 0 ;
62+ flush = true ;
63+ }
64+ break ;
65+ case 2 :
66+ // CSI kết thúc bằng 1 finalByte trong khoảng '@'..'~' (ECMA-48), vd 'J' (xoá
67+ // màn hình), 'm' (màu SGR), 'H' (di chuyển con trỏ)...
68+ if (c >= '@' && c <= '~' ) {
69+ escState = 0 ;
70+ flush = true ;
71+ }
72+ break ;
73+ case 3 :
74+ if (c == '\u0007' ) {
75+ escState = 0 ;
76+ flush = true ;
77+ } else if (c == '\u001B' ) {
78+ escState = 4 ;
79+ }
80+ break ;
81+ case 4 :
82+ if (c == '\\' ) {
83+ escState = 0 ;
84+ flush = true ;
85+ } else {
86+ escState = 3 ;
87+ }
88+ break ;
89+ }
90+
91+ if (flush ) {
3392 String segment = buffer .toString ();
3493 shellHandlerBase .sendMessage (
3594 shellHandlerBase .obtainMessage (what , shellTranslation .resolveRow (segment ))
@@ -90,4 +149,4 @@ public void setHandler(Context context, Process process, final ShellHandlerBase
90149 readerError .start ();
91150 waitExit .start ();
92151 }
93- }
152+ }
0 commit comments