hv: shell: improve console to modify input easier

1. make memcpy_erms as a public API; add a new one
  memcpy_erms_backwards, which supports to copy data from tail to head.

  2. improve to use right/left/home/end key to move cursor, and support
delete/backspace key to modify current input command.

Tracked-On: #7931
Signed-off-by: Minggui Cao <minggui.cao@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Minggui Cao 2022-07-20 13:15:32 +08:00 committed by acrnsi-robot
parent d5b2c82156
commit 83164d6030
4 changed files with 145 additions and 28 deletions

View File

@ -24,7 +24,7 @@ void *memset(void *base, uint8_t v, size_t n)
return base; return base;
} }
static inline void memcpy_erms(void *d, const void *s, size_t slen) void memcpy_erms(void *d, const void *s, size_t slen)
{ {
asm volatile ("rep; movsb" asm volatile ("rep; movsb"
: "=&D"(d), "=&S"(s) : "=&D"(d), "=&S"(s)
@ -32,6 +32,15 @@ static inline void memcpy_erms(void *d, const void *s, size_t slen)
: "memory"); : "memory");
} }
/* copy data from tail to head (backwards) with ERMS (Enhanced REP MOVSB/STOSB) */
void memcpy_erms_backwards(void *d, const void *s, size_t slen)
{
asm volatile ("std; rep; movsb; cld"
: "=&D"(d), "=&S"(s)
: "c"(slen), "0" (d), "1" (s)
: "memory");
}
/* /*
* @brief Copies at most slen bytes from src address to dest address, up to dmax. * @brief Copies at most slen bytes from src address to dest address, up to dmax.
* *

View File

@ -157,12 +157,17 @@ static struct shell_cmd shell_cmds[] = {
}, },
}; };
/* for function key: up/down key */ /* for function key: up/down/right/left/home/end and delete key */
enum function_key { enum function_key {
KEY_NONE, KEY_NONE,
KEY_DELETE = 0x5B33,
KEY_UP = 0x5B41, KEY_UP = 0x5B41,
KEY_DOWN = 0x5B42, KEY_DOWN = 0x5B42,
KEY_RIGHT = 0x5B43,
KEY_LEFT = 0x5B44,
KEY_END = 0x5B46,
KEY_HOME = 0x5B48,
}; };
/* The initial log level*/ /* The initial log level*/
@ -287,6 +292,40 @@ static void clear_input_line(uint32_t len)
} }
} }
static void set_cursor_pos(uint32_t left_offset)
{
while (left_offset > 0) {
left_offset--;
shell_puts("\b");
}
}
static void handle_delete_key(void)
{
if (p_shell->cursor_offset < p_shell->input_line_len) {
uint32_t delta = p_shell->input_line_len - p_shell->cursor_offset - 1;
/* Send a space + backspace sequence to delete character */
shell_puts(" \b");
/* display the left input chars and remove former last one */
shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset + 1);
shell_puts(" \b");
set_cursor_pos(delta);
memcpy_erms(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset,
p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset + 1, delta);
/* Null terminate the last character to erase it */
p_shell->buffered_line[p_shell->input_line_active][p_shell->input_line_len - 1] = 0;
/* Reduce the length of the string by one */
p_shell->input_line_len--;
}
}
static void handle_updown_key(enum function_key key_value) static void handle_updown_key(enum function_key key_value)
{ {
int32_t to_select, current_select = p_shell->to_select_index; int32_t to_select, current_select = p_shell->to_select_index;
@ -316,6 +355,10 @@ static void handle_updown_key(enum function_key key_value)
} }
if (strcmp(p_shell->buffered_line[current_select], p_shell->buffered_line[p_shell->input_line_active]) != 0) { if (strcmp(p_shell->buffered_line[current_select], p_shell->buffered_line[p_shell->input_line_active]) != 0) {
/* reset cursor pos and clear current input line first, then output selected cmd */
if (p_shell->cursor_offset < p_shell->input_line_len) {
shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset);
}
clear_input_line(p_shell->input_line_len); clear_input_line(p_shell->input_line_len);
shell_puts(p_shell->buffered_line[current_select]); shell_puts(p_shell->buffered_line[current_select]);
@ -325,6 +368,7 @@ static void handle_updown_key(enum function_key key_value)
memcpy_s(p_shell->buffered_line[p_shell->input_line_active], SHELL_CMD_MAX_LEN, memcpy_s(p_shell->buffered_line[p_shell->input_line_active], SHELL_CMD_MAX_LEN,
p_shell->buffered_line[current_select], len + 1); p_shell->buffered_line[current_select], len + 1);
p_shell->input_line_len = len; p_shell->input_line_len = len;
p_shell->cursor_offset = len;
} }
} }
@ -333,15 +377,46 @@ static void shell_handle_special_char(char ch)
enum function_key key_value = KEY_NONE; enum function_key key_value = KEY_NONE;
switch (ch) { switch (ch) {
/* original function key value: ESC + key, so consume the next 2 characters */ /* original function key value: ESC + key (2/3 bytes), so consume the next 2/3 characters */
case 0x1b: case 0x1b:
key_value = (shell_getc() << 8) | shell_getc(); key_value = (shell_getc() << 8) | shell_getc();
if (key_value == KEY_DELETE) {
(void)shell_getc(); /* delete key has one more byte */
}
switch (key_value) { switch (key_value) {
case KEY_DELETE:
handle_delete_key();
break;
case KEY_UP: case KEY_UP:
case KEY_DOWN: case KEY_DOWN:
handle_updown_key(key_value); handle_updown_key(key_value);
break; break;
case KEY_RIGHT:
if (p_shell->cursor_offset < p_shell->input_line_len) {
shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset);
p_shell->cursor_offset++;
set_cursor_pos(p_shell->input_line_len - p_shell->cursor_offset);
}
break;
case KEY_LEFT:
if (p_shell->cursor_offset > 0) {
p_shell->cursor_offset--;
shell_puts("\b");
}
break;
case KEY_END:
if (p_shell->cursor_offset < p_shell->input_line_len) {
shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset);
p_shell->cursor_offset = p_shell->input_line_len;
}
break;
case KEY_HOME:
if (p_shell->cursor_offset > 0) {
set_cursor_pos(p_shell->cursor_offset);
p_shell->cursor_offset = 0;
}
break;
default: default:
break; break;
} }
@ -358,6 +433,57 @@ static void shell_handle_special_char(char ch)
} }
} }
static void handle_backspace_key(void)
{
/* Ensure length is not 0 */
if (p_shell->cursor_offset > 0U) {
/* Echo backspace */
shell_puts("\b");
/* Send a space + backspace sequence to delete character */
shell_puts(" \b");
if (p_shell->cursor_offset < p_shell->input_line_len) {
uint32_t delta = p_shell->input_line_len - p_shell->cursor_offset;
/* display the left input-chars and remove the former last one */
shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset);
shell_puts(" \b");
set_cursor_pos(delta);
memcpy_erms(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset - 1,
p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset, delta);
}
/* Null terminate the last character to erase it */
p_shell->buffered_line[p_shell->input_line_active][p_shell->input_line_len - 1] = 0;
/* Reduce the length of the string by one */
p_shell->input_line_len--;
p_shell->cursor_offset--;
}
}
static void handle_input_char(char ch)
{
uint32_t delta = p_shell->input_line_len - p_shell->cursor_offset;
/* move the input from cursor offset back first */
if (delta > 0) {
memcpy_erms_backwards(p_shell->buffered_line[p_shell->input_line_active] + p_shell->input_line_len,
p_shell->buffered_line[p_shell->input_line_active] + p_shell->input_line_len - 1, delta);
}
p_shell->buffered_line[p_shell->input_line_active][p_shell->cursor_offset] = ch;
/* Echo back the input */
shell_puts(p_shell->buffered_line[p_shell->input_line_active] + p_shell->cursor_offset);
set_cursor_pos(delta);
/* Move to next character in string */
p_shell->input_line_len++;
p_shell->cursor_offset++;
}
static bool shell_input_line(void) static bool shell_input_line(void)
{ {
bool done = false; bool done = false;
@ -369,22 +495,7 @@ static bool shell_input_line(void)
switch (ch) { switch (ch) {
/* Backspace */ /* Backspace */
case '\b': case '\b':
/* Ensure length is not 0 */ handle_backspace_key();
if (p_shell->input_line_len > 0U) {
/* Reduce the length of the string by one */
p_shell->input_line_len--;
/* Null terminate the last character to erase it */
p_shell->buffered_line[p_shell->input_line_active][p_shell->input_line_len] = 0;
/* Echo backspace */
shell_puts("\b");
/* Send a space + backspace sequence to delete
* character
*/
shell_puts(" \b");
}
break; break;
/* Carriage-return */ /* Carriage-return */
@ -397,6 +508,7 @@ static bool shell_input_line(void)
/* Reset command length for next command processing */ /* Reset command length for next command processing */
p_shell->input_line_len = 0U; p_shell->input_line_len = 0U;
p_shell->cursor_offset = 0U;
break; break;
/* Line feed */ /* Line feed */
@ -410,14 +522,7 @@ static bool shell_input_line(void)
if (p_shell->input_line_len < SHELL_CMD_MAX_LEN) { if (p_shell->input_line_len < SHELL_CMD_MAX_LEN) {
/* See if a "standard" prINTable ASCII character received */ /* See if a "standard" prINTable ASCII character received */
if ((ch >= 32) && (ch <= 126)) { if ((ch >= 32) && (ch <= 126)) {
/* Add character to string */ handle_input_char(ch);
p_shell->buffered_line[p_shell->input_line_active][p_shell->input_line_len] = ch;
/* Echo back the input */
shell_puts(&p_shell->buffered_line[p_shell->input_line_active]
[p_shell->input_line_len]);
/* Move to next character in string */
p_shell->input_line_len++;
} else { } else {
/* call special character handler */ /* call special character handler */
shell_handle_special_char(ch); shell_handle_special_char(ch);
@ -431,7 +536,7 @@ static bool shell_input_line(void)
/* Reset command length for next command processing */ /* Reset command length for next command processing */
p_shell->input_line_len = 0U; p_shell->input_line_len = 0U;
p_shell->cursor_offset = 0U;
} }
break; break;
} }

View File

@ -36,6 +36,7 @@ struct shell {
int32_t input_line_active; /* Active input line index */ int32_t input_line_active; /* Active input line index */
int32_t to_select_index; /* used for up/down key to select former cmds */ int32_t to_select_index; /* used for up/down key to select former cmds */
uint32_t cursor_offset; /* cursor offset position from left input line */
struct shell_cmd *cmds; /* cmds supported */ struct shell_cmd *cmds; /* cmds supported */
uint32_t cmd_count; /* Count of cmds supported */ uint32_t cmd_count; /* Count of cmds supported */

View File

@ -42,6 +42,8 @@ char *strchr(char *s_arg, char ch);
size_t strnlen_s(const char *str_arg, size_t maxlen_arg); size_t strnlen_s(const char *str_arg, size_t maxlen_arg);
void *memset(void *base, uint8_t v, size_t n); void *memset(void *base, uint8_t v, size_t n);
int32_t memcpy_s(void *d, size_t dmax, const void *s, size_t slen); int32_t memcpy_s(void *d, size_t dmax, const void *s, size_t slen);
void memcpy_erms(void *d, const void *s, size_t slen);
void memcpy_erms_backwards(void *d, const void *s, size_t slen);
int64_t strtol_deci(const char *nptr); int64_t strtol_deci(const char *nptr);
uint64_t strtoul_hex(const char *nptr); uint64_t strtoul_hex(const char *nptr);
char *strstr_s(const char *str1, size_t maxlen1, const char *str2, size_t maxlen2); char *strstr_s(const char *str1, size_t maxlen1, const char *str2, size_t maxlen2);