55
66#define MAX_COMDLINE_SIZE 80
77#define MAX_WORDS 6
8+ #define BACKSPACE_CHAR 0x08
9+ #define ESCAPE_CHAR ' \x1b '
10+ #define CSI_CHAR ' ['
11+ #define LEFT_ARROW_CHAR ' D'
12+ #define RIGHT_ARROW_CHAR ' C'
13+ #define DELETE_KEY_1_CHAR ' 3'
14+ #define DELETE_KEY_2_CHAR ' ~'
15+ #define PRINT_CHAR_START 32
16+ #define PRINT_CHAR_END 126
817
918namespace serial_console
1019{
1120 bool global_disable_serial_console = false ;
1221
22+ /* *
23+ * @brief Redraws the characters from the current cursor position to the end of the buffer on the serial console.
24+ *
25+ * This function is used to update the terminal display when characters are inserted or deleted
26+ * in the middle of the input buffer. It:
27+ * - Saves the current cursor position
28+ * - Clears the line from the cursor to the end
29+ * - Prints characters from 'cur' to 'len'
30+ * - Restores the original cursor position
31+ *
32+ * @param cur Current cursor position within the buffer
33+ * @param len Current length of the buffer (number of characters entered)
34+ * @param buf Character buffer containing the input string
35+ */
36+ static inline void redraw (const int cur, const int len, char *buf) {
37+ if (!temporary_config.remote_echo )
38+ return ;
39+
40+ Serial.print (" \x1b [s" );
41+ Serial.print (" \x1b [K" );
42+
43+ // Reprint characters from cur to end
44+ for (int i = cur; i < len; i++) {
45+ Serial.print ((char )buf[i]);
46+ }
47+
48+ Serial.print (" \x1b [u" );
49+ }
50+
1351 /*
1452 * read_string_until: Non-blocking replacement for Serial.readStringUntil()..
1553 * With delimeter '\n' acts as 'read line'.
@@ -20,6 +58,7 @@ namespace serial_console
2058 bool read_string_until (char delimiter, char *result, int max_len)
2159 {
2260 static int index = 0 ;
61+ static int cur = 0 ;
2362 int c; // read character, -1 if none
2463 int cnt = 100 ; // limit on amount of iterations in one go; we're supposed to be non-blocking!
2564
@@ -28,43 +67,75 @@ namespace serial_console
2867 --cnt;
2968
3069 // backspaceF
31- if (c == 8 )
32- {
33- if (index > 0 )
34- {
35- if (temporary_config.remote_echo ) Serial.print (" \x08 \x08 " ); // overwrite last character with space and move cursor 1 back.
70+ if (c == BACKSPACE_CHAR && cur > 0 ) {
71+ // shift characters left from cursor position
72+ memmove (&result[cur - 1 ], &result[cur], index - cur);
3673 index--;
37- }
38- continue ;
39- }
74+ cur--;
75+ // move cursor left on terminal and redraw updated string
76+ if (temporary_config.remote_echo ) Serial.print (" \x1b [D" );
77+ redraw (cur, index, result);
78+ // handle ANSI escape sequences (arrow keys, delete key)
79+ } else if (c == ESCAPE_CHAR) {
80+
81+ if ((c = Serial.read ()) == -1 )
82+ break ;
4083
41- if (temporary_config.remote_echo ) Serial.print ((char )c); // echo
84+ // Expect '[' character
85+ if (c != CSI_CHAR)
86+ continue ;
4287
43- // Buffer overflow handling:
44- // start treating current buffer as invalid:
45- // - stop collecting more data
46- // - return false on delimeter, flushing everything collected,
47- // - restart collection from scratch after delimeter,
48- // - return control as normal.
88+ if ((c = Serial.read ()) == -1 )
89+ break ;
4990
50- if (index >= max_len - 1 )
51- {
52- if (c == delimiter) // got delimeter: flush buffer quietly, restart collection.
53- {
91+ // Left arrow key
92+ if (c == LEFT_ARROW_CHAR && cur > 0 ) {
93+ // move cursor left on terminal
94+ if (temporary_config.remote_echo ) Serial.print (" \x1b [D" );
95+ cur--;
96+ // Right arrow key
97+ } else if (c == RIGHT_ARROW_CHAR && cur < index) {
98+ // move cursor right on terminal
99+ if (temporary_config.remote_echo ) Serial.print (" \x1b [C" );
100+ cur++;
101+ // Delete key
102+ } else if (c == DELETE_KEY_1_CHAR) {
103+ if ((c = Serial.read ()) == -1 )
104+ break ;
105+ if (c == DELETE_KEY_2_CHAR && cur < index) {
106+ memmove (&result[cur], &result[cur + 1 ], index - cur - 1 );
107+ index--;
108+ redraw (cur, index, result);
109+ }
110+ }
111+
112+ // Handle printable characters
113+ } else if (c >= PRINT_CHAR_START && c <= PRINT_CHAR_END) {
114+ // Append character at the end
115+ if (index < max_len - 1 && cur == index) {
116+ if (temporary_config.remote_echo ) Serial.print ((char )c);
117+ result[index++] = c;
118+ cur++;
119+ // Insert character in the middl
120+ } else if (index < max_len - 1 ) {
121+ memmove (&result[cur + 1 ], &result[cur], index - cur);
122+ result[cur] = c;
123+ index++;
124+ if (temporary_config.remote_echo ) Serial.print ((char )c);
125+ cur++;
126+ redraw (cur, index, result);
127+ } else if (c == delimiter) { // got delimeter: flush buffer quietly, restart collection.
54128 index = 0 ;
129+ cur = 0 ;
55130 return false ;
56131 }
57- else
58- continue ; // discard any data past the end of the buffer, keep reading
59- }
60-
61- result[index++] = c;
62-
63132 // delimiter was found
64- if (c == delimiter)
65- {
133+ } else if (c == delimiter) {
134+
135+ if (temporary_config.remote_echo ) Serial.println ();
66136 result[index] = ' \0 ' ; // Null-terminate the string
67137 index = 0 ;
138+ cur = 0 ;
68139 return true ; // Success: Delimiter found
69140 }
70141 }
0 commit comments