--- /dev/null
+/*
+ * Copyright (c) 2023, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ *
+ * Test using curses(3)'s own cooked input mode that interprets some special
+ * characters similarly to native tty(4) cooked modes. This can be different
+ * because curses simulates it, providing its own, when echo is enabled and
+ * multiple-character input happens.
+ *
+ * $ cc -Wall -O0 -g -o cooked cooked.c -lcurses
+ */
+
+#include <curses.h>
+#include <err.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+
+int main(void);
+static void cleanup(void);
+
+
+/* To explicitly save/restore tty(4) state despite curses(3) */
+static struct termios old_tios;
+
+/* Curses window */
+static WINDOW *w = NULL;
+
+
+int
+main(void)
+{
+
+ /* Setup curses */
+ (void)tcgetattr(STDIN_FILENO, &old_tios);
+ if ((w = initscr()) == NULL)
+ err(EXIT_FAILURE, "initscr()");
+
+ /* Exit cleanup hook to restore normal terminal */
+ (void)atexit(cleanup);
+
+ /* Typical mode */
+ (void)cbreak();
+ (void)nonl();
+ (void)keypad(w, TRUE);
+ (void)intrflush(stdscr, FALSE);
+ (void)timeout(-1);
+
+ /* Curses "ICANON" mode */
+ (void)curs_set(1);
+ (void)intrflush(stdscr, FALSE);
+ (void)nl();
+ (void)echo();
+ (void)scrollok(stdscr, TRUE);
+ (void)leaveok(w, FALSE);
+ (void)intrflush(w, TRUE);
+ (void)move(10, 10);
+ (void)refresh(); /* doupdate() does not update cursor pos */
+
+ for (;;) {
+ char str[1024];
+
+ if (getnstr(str, 1023) != OK)
+ err(EXIT_FAILURE, "getnstr()");
+ (void)printw("%s\n", str);
+ (void)refresh();
+ if (strcasecmp(str, "quit") == 0) {
+ (void)printw("Bye!\n");
+ (void)refresh();
+ break;
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+}
+
+static void
+cleanup(void)
+{
+
+ (void)curs_set(1);
+ (void)endwin();
+ (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_tios);
+}