aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgbc dev <gbc@localhost>2026-07-16 11:25:43 +0200
committergbc dev <gbc@localhost>2026-07-16 11:25:43 +0200
commit283040a1a5356e774276ba8f6c7404483b81bc11 (patch)
tree846c6c51fde7b96bbbce13e268fa660062f75bdd
parentserial: deliver EOF (0x04) on stdin end for headless console (diff)
downloadsl0pboy-283040a1a5356e774276ba8f6c7404483b81bc11.tar.gz
sl0pboy-283040a1a5356e774276ba8f6c7404483b81bc11.tar.xz
sl0pboy-283040a1a5356e774276ba8f6c7404483b81bc11.zip
headless: interactive TTY mode (raw stdin) for driving a guest OS live
When stdin is a terminal, --headless now disables canonical mode + local echo so keystrokes reach the guest immediately and only the guest echoes (no doubled chars). Piped/redirected stdin is untouched (scripted input still works). Keep ISIG so Ctrl-C quits; restore termios on exit. VMIN=1 so a no-data non-blocking read is EAGAIN, not a 0-byte read the serial layer would misread as EOF.
-rw-r--r--src/main.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
index f0709c2..648ded2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -9,6 +9,7 @@
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
+#include <termios.h>
static volatile sig_atomic_t running = 1;
static void on_sig(int s) { (void)s; running = 0; }
@@ -100,6 +101,21 @@ int main(int argc, char **argv) {
if (fl != -1) fcntl(STDIN_FILENO, F_SETFL, fl | O_NONBLOCK);
signal(SIGINT, on_sig);
signal(SIGTERM, on_sig);
+ // Interactive: if stdin is a terminal, drop line-buffering + local echo
+ // so keystrokes reach the guest immediately and only the guest echoes.
+ // (Piped/redirected stdin is left alone, for scripted input.)
+ struct termios saved_tio;
+ bool raw_tty = isatty(STDIN_FILENO) && tcgetattr(STDIN_FILENO, &saved_tio) == 0;
+ if (raw_tty) {
+ struct termios t = saved_tio;
+ t.c_lflag &= ~(ICANON | ECHO); // char-at-a-time, no echo (keep ISIG)
+ // VMIN=1 (not 0): with O_NONBLOCK, "no data" is EAGAIN, not a 0-byte
+ // read that we'd otherwise misread as EOF.
+ t.c_cc[VMIN] = 1;
+ t.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSANOW, &t);
+ fprintf(stderr, "[gbc: interactive serial console - Ctrl-C to quit]\n");
+ }
bool uncapped = (target_fps <= 0);
double start_t = now_sec();
u64 start_cyc = gb->cycles;
@@ -118,6 +134,7 @@ int main(int argc, char **argv) {
}
}
}
+ if (raw_tty) tcsetattr(STDIN_FILENO, TCSANOW, &saved_tio);
cart_free(&gb->cart); free(gb); return 0;
}