mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-08-29 02:38:19 +00:00
Fix USB terminal backspace handling
This commit is contained in:
@@ -139,6 +139,35 @@ static void clearUsbTerminalLine() {
|
||||
usb_terminal_line_len = 0;
|
||||
}
|
||||
|
||||
static void printUsbTerminalInputEcho() {
|
||||
const char* password = nullptr;
|
||||
size_t visible_len = usb_terminal_line_len;
|
||||
if (mesh::cli::parseTerminalArgumentCommand(
|
||||
usb_terminal_line, "login", password)
|
||||
== mesh::cli::TerminalArgumentCommandMatch::Valid) {
|
||||
visible_len = static_cast<size_t>(password - usb_terminal_line);
|
||||
}
|
||||
|
||||
if (visible_len > 0) {
|
||||
Serial.write(reinterpret_cast<const uint8_t*>(usb_terminal_line),
|
||||
visible_len);
|
||||
}
|
||||
for (size_t i = visible_len; i < usb_terminal_line_len; i++) {
|
||||
Serial.print('*');
|
||||
}
|
||||
}
|
||||
|
||||
static void redrawUsbTerminalInput() {
|
||||
// The documented picocom `--imap spchex` converts an echoed BS to "[08]".
|
||||
// It deliberately leaves CR untouched, so redraw the edited line with CR
|
||||
// and printable bytes only. Padding clears a removed tab or wide glyph.
|
||||
Serial.print("\r> ");
|
||||
printUsbTerminalInputEcho();
|
||||
Serial.print(" ");
|
||||
Serial.print("\r> ");
|
||||
printUsbTerminalInputEcho();
|
||||
}
|
||||
|
||||
static bool isUsbTerminalDataConnected() {
|
||||
#if defined(RP2040_PLATFORM)
|
||||
return (bool)Serial;
|
||||
@@ -285,8 +314,9 @@ static void serviceUsbTerminal() {
|
||||
|
||||
if (c == '\b' || c == 0x7F) {
|
||||
if (usb_terminal_line_len > 0) {
|
||||
usb_terminal_line[--usb_terminal_line_len] = 0;
|
||||
Serial.print("\b \b");
|
||||
usb_terminal_line_len = mesh::cli::eraseLastTerminalInput(
|
||||
usb_terminal_line, usb_terminal_line_len);
|
||||
redrawUsbTerminalInput();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,20 @@ inline bool shouldMaskTerminalInput(const char* line) {
|
||||
== TerminalArgumentCommandMatch::Valid;
|
||||
}
|
||||
|
||||
// Remove one complete UTF-8 code point from a terminal input buffer. Invalid
|
||||
// trailing bytes are still removed safely, and the result remains terminated.
|
||||
inline size_t eraseLastTerminalInput(char* line, size_t line_length) {
|
||||
if (line == nullptr || line_length == 0) return 0;
|
||||
|
||||
size_t new_length = line_length - 1;
|
||||
while (new_length > 0
|
||||
&& (static_cast<uint8_t>(line[new_length]) & 0xC0) == 0x80) {
|
||||
new_length--;
|
||||
}
|
||||
line[new_length] = 0;
|
||||
return new_length;
|
||||
}
|
||||
|
||||
inline TerminalChannelCommandMatch parseTerminalChannelMessage(
|
||||
const char* command, TerminalChannelMessage& message) {
|
||||
message.selector = nullptr;
|
||||
|
||||
@@ -198,6 +198,24 @@ TEST(CLICommandUtils, MasksOnlyTerminalLoginPasswordInput) {
|
||||
EXPECT_FALSE(mesh::cli::shouldMaskTerminalInput("login-status"));
|
||||
}
|
||||
|
||||
TEST(CLICommandUtils, BackspaceErasesAsciiAndUtf8Characters) {
|
||||
char ascii[] = "trace path 2 7773";
|
||||
size_t length = strlen(ascii);
|
||||
|
||||
length = mesh::cli::eraseLastTerminalInput(ascii, length);
|
||||
EXPECT_STREQ("trace path 2 777", ascii);
|
||||
EXPECT_EQ(strlen(ascii), length);
|
||||
|
||||
char utf8[] = "channel Public hi 👋";
|
||||
length = strlen(utf8);
|
||||
length = mesh::cli::eraseLastTerminalInput(utf8, length);
|
||||
EXPECT_STREQ("channel Public hi ", utf8);
|
||||
EXPECT_EQ(strlen(utf8), length);
|
||||
|
||||
EXPECT_EQ(0u, mesh::cli::eraseLastTerminalInput(nullptr, 0));
|
||||
EXPECT_EQ(0u, mesh::cli::eraseLastTerminalInput(utf8, 0));
|
||||
}
|
||||
|
||||
TEST(CLICommandUtils, ParsesStrictDecimalValues) {
|
||||
float value = 0.0f;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user