From: Ahmad Fatoum <a.fatoum@barebox.org>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@barebox.org>
Subject: [PATCH v2 2/2] readkey: handle standalone ESC keypress with timeout
Date: Sun, 3 May 2026 10:23:20 +0200 [thread overview]
Message-ID: <20260503082348.2755843-2-a.fatoum@barebox.org> (raw)
In-Reply-To: <20260503082348.2755843-1-a.fatoum@barebox.org>
read_key() unconditionally called getchar() twice after receiving an
ESC byte (0x1B), assuming it was the start of a multi-byte escape
sequence. A standalone ESC keypress sends only the single 0x1B byte,
so the second getchar() would block indefinitely, making it impossible
to use ESC on its own to cancel operations.
Poll with tstc() and a 50ms timeout after the initial ESC byte. If no
follow-up character arrives, return the bare ESC. This matches the
standard terminal approach for distinguishing ESC keypresses from
escape sequences, which arrive as a rapid burst.
Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
v1 -> v2:
- implement pollchar() for CONSOLE_SIMPLE as well
---
common/console.c | 13 +++++++++++++
common/console_simple.c | 14 ++++++++++++++
include/stdio.h | 2 ++
lib/readkey.c | 31 +++++++++++++++++++++++++++++--
4 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/common/console.c b/common/console.c
index 0ce89390864b..162579b8c5cf 100644
--- a/common/console.c
+++ b/common/console.c
@@ -571,6 +571,19 @@ int tstc(void)
}
EXPORT_SYMBOL(tstc);
+int pollchar(ktime_t duration)
+{
+ ktime_t start = get_time_ns();
+
+ while (!tstc()) {
+ if (is_timeout(start, duration))
+ return -ETIMEDOUT;
+ }
+
+ return getchar();
+}
+EXPORT_SYMBOL(pollchar);
+
int console_putc(struct console_device *con, char c)
{
bool crlf = c == '\n';
diff --git a/common/console_simple.c b/common/console_simple.c
index b4d0e19015d8..6771d457455e 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -5,6 +5,7 @@
#include <errno.h>
#include <debug_ll.h>
#include <console.h>
+#include <clock.h>
#include <security/config.h>
LIST_HEAD(console_list);
@@ -66,6 +67,19 @@ int getchar(void)
}
EXPORT_SYMBOL(getchar);
+int pollchar(ktime_t duration)
+{
+ ktime_t start = get_time_ns();
+
+ while (!tstc()) {
+ if (is_timeout(start, duration))
+ return -ETIMEDOUT;
+ }
+
+ return getchar();
+}
+EXPORT_SYMBOL(pollchar);
+
void console_flush(void)
{
if (console && console->flush)
diff --git a/include/stdio.h b/include/stdio.h
index f5b23140adde..c8225430ad29 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -12,9 +12,11 @@
/* stdin */
int tstc(void);
int getchar(void);
+int pollchar(ktime_t duration);
#else
static inline int tstc(void) { return 0; }
static inline int getchar(void) { return -EINVAL; }
+static inline int pollchar(ktime_t duration) { return -ENOSYS; }
#endif
int readline(const char *prompt, char *buf, int len);
diff --git a/lib/readkey.c b/lib/readkey.c
index c26e9d51aba9..71f9b41c5055 100644
--- a/lib/readkey.c
+++ b/lib/readkey.c
@@ -17,6 +17,8 @@
*/
#include <common.h>
+#include <clock.h>
+#include <linux/ktime.h>
#include <linux/ctype.h>
#include <readkey.h>
@@ -46,6 +48,18 @@ static const struct esc_cmds esccmds[] = {
{"[6~", BB_KEY_PAGEDOWN},// Cursor Key Page Down
};
+static int poll_key_into_buf(unsigned char *key)
+{
+ int ret;
+
+ ret = pollchar(50 * MSECOND);
+ if (ret < 0)
+ return ret;
+
+ *key = ret;
+ return 0;
+}
+
int read_key(void)
{
unsigned char c;
@@ -54,8 +68,21 @@ int read_key(void)
if (c == 27) {
int i = 0;
- esc[i++] = getchar();
- esc[i++] = getchar();
+
+ /*
+ * Escape sequences (arrow keys, etc.) arrive as a burst
+ * of characters: ESC [ A, ESC [ 1 ~ etc. A standalone
+ * ESC keypress sends just the single 0x1b byte.
+ *
+ * Wait briefly for a follow-up character; if nothing
+ * arrives it was a bare ESC.
+ */
+ if (poll_key_into_buf(&esc[i++]))
+ return '\e';
+
+ if (poll_key_into_buf(&esc[i++]))
+ return -1;
+
if (isdigit(esc[1])) {
while(1) {
esc[i] = getchar();
--
2.47.3
next prev parent reply other threads:[~2026-05-03 8:24 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-03 8:23 [PATCH v2 1/2] include: ktime: move ktime_t definition globally Ahmad Fatoum
2026-05-03 8:23 ` Ahmad Fatoum [this message]
2026-05-07 11:19 ` Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260503082348.2755843-2-a.fatoum@barebox.org \
--to=a.fatoum@barebox.org \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox