[PATCH 1/2] efi_loader: efi_console: support editable input fields
    Casey Connolly 
    casey.connolly at linaro.org
       
    Thu Oct 23 16:26:46 CEST 2025
    
    
  
When editing eficonfig "optional data" (typically cmdline arguments)
it's useful to be able to edit the string rather than having to re-type
the entire thing. Implement support for editing buffers to make this a
whole lot nicer. Specifically, add support for moving the cursor with
the arrow keys and End key as well as deleting backwards with the delete
key.
Signed-off-by: Casey Connolly <casey.connolly at linaro.org>
---
 cmd/eficonfig.c              |  2 ++
 lib/efi_loader/efi_console.c | 52 ++++++++++++++++++++++++++++++++++++--------
 2 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index 8ac0fb98e02e..d8d946c87ac8 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -973,8 +973,10 @@ static efi_status_t handle_user_input(u16 *buf, int buf_size,
 	tmp = calloc(1, buf_size * sizeof(u16));
 	if (!tmp)
 		return EFI_OUT_OF_RESOURCES;
 
+	/* Populate tmp so user can edit existing string */
+	u16_strcpy(tmp, buf);
 	ret = efi_console_get_u16_string(cin, tmp, buf_size, NULL, 4, cursor_col);
 	if (ret == EFI_SUCCESS)
 		u16_strcpy(buf, tmp);
 
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 953f6831466e..7bfd18233feb 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -1383,36 +1383,61 @@ efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *c
 					efi_console_filter_func filter_func,
 					int row, int col)
 {
 	efi_status_t ret;
-	efi_uintn_t len = 0;
+	efi_uintn_t len;
+	efi_uintn_t cursor;
+	efi_uintn_t i;
 	struct efi_input_key key;
 
 	printf(ANSI_CURSOR_POSITION
 	       ANSI_CLEAR_LINE_TO_END
 	       ANSI_CURSOR_SHOW, row, col);
 
 	efi_cin_empty_buffer();
 
+	len = u16_strlen(buf);
+	cursor = len;
 	for (;;) {
+		printf(ANSI_CURSOR_POSITION "%ls"
+		       ANSI_CLEAR_LINE_TO_END ANSI_CURSOR_POSITION,
+		       row, col, buf, row, col + (int)cursor);
 		do {
 			ret = EFI_CALL(cin->read_key_stroke(cin, &key));
 			mdelay(10);
 		} while (ret == EFI_NOT_READY);
 
 		if (key.unicode_char == u'\b') {
-			if (len > 0)
-				buf[--len] = u'\0';
-
-			printf(ANSI_CURSOR_POSITION
-			       "%ls"
-			       ANSI_CLEAR_LINE_TO_END, row, col, buf);
+			if (cursor > 0) {
+				if (cursor == len) {
+					buf[--cursor] = u'\0';
+				} else {
+					for (i = cursor - 1; i < len; i++)
+						buf[i] = buf[i + 1];
+					cursor--;
+				}
+				len--;
+			}
+			continue;
+		} else if (key.scan_code == 8) { /* delete */
+			for (i = cursor; i <= len; i++)
+				buf[i] = buf[i + 1];
+			len--;
 			continue;
 		} else if (key.unicode_char == u'\r') {
 			buf[len] = u'\0';
 			return EFI_SUCCESS;
 		} else if (key.unicode_char == 0x3 || key.scan_code == 23) {
 			return EFI_ABORTED;
+		} else if (key.scan_code == 3) { /* Right arrow */
+			cursor += (cursor < len) ? 1 : 0;
+			continue;
+		} else if (key.scan_code == 4) { /* Left arrow */
+			cursor -= (cursor > 0) ? 1 : 0;
+			continue;
+		} else if (key.scan_code == 6) { /* End */
+			cursor = len;
+			continue;
 		} else if (key.unicode_char < 0x20) {
 			/* ignore control codes other than Ctrl+C, '\r' and '\b' */
 			continue;
 		} else if (key.scan_code != 0) {
@@ -1427,9 +1452,18 @@ efi_status_t efi_console_get_u16_string(struct efi_simple_text_input_protocol *c
 
 		if (len >= (count - 1))
 			continue;
 
-		buf[len] = key.unicode_char;
+		/*
+		 * Insert the character into the middle of the buffer, shift the
+		 * characters after the cursor along. The check above ensures we
+		 * will never overflow the buffer.
+		 * If the cursor is at the end of the string then this will
+		 * do nothing.
+		 */
+		for (i = len + 1; i > cursor; i--)
+			buf[i] = buf[i - 1];
+		buf[cursor] = key.unicode_char;
+		cursor++;
 		len++;
-		printf(ANSI_CURSOR_POSITION "%ls", row, col, buf);
 	}
 }
-- 
2.51.0
    
    
More information about the U-Boot
mailing list