curs_inopts(3X)

πŸ“¦ version 15.1, in freebsd 14.5, freebsd 15.1

πŸ’– curs_inopts(3X) β€” Library calls πŸ’–

okay bestie, gather round, because this is the page about how curses handles input from your terminal. yes, it's long. yes, it's worth it. let's go 🫢


✨ NAME ✨

cbreak, echo, halfdelay, intrflush, is_cbreak, is_echo, is_nl, is_raw, keypad, meta, nl, nocbreak, nodelay, noecho, nonl, noqiflush, noraw, notimeout, qiflush, raw, timeout, wtimeout, typeahead β€” get and set curses terminal input options. periodt. πŸ’…


🌸 SYNOPSIS 🌸

#include <curses.h>

int cbreak(void);
int nocbreak(void);

int echo(void);
int noecho(void);

int intrflush(WINDOW * win /* ignored */, bool bf);
int keypad(WINDOW * win, bool bf);
int meta(WINDOW * win /* ignored */, bool bf);
int nodelay(WINDOW * win, bool bf);
int notimeout(WINDOW * win, bool bf);

int nl(void);
int nonl(void);

void qiflush(void);
void noqiflush(void);

int raw(void);
int noraw(void);

int halfdelay(int tenths);
void timeout(int delay);
void wtimeout(WINDOW * win, int delay);

int typeahead(int fd);

/* extensions */
int is_cbreak(void);
int is_echo(void);
int is_nl(void);
int is_raw(void);

πŸ¦‹ DESCRIPTION πŸ¦‹

so basically, curses is out here handing you a whole lil control panel for how your app deals with terminal input. some of these knobs are global β€” they mess with the terminal's mode or its line discipline, so they affect every window. others are per-window, just vibing on one window only. and here's the thing: the library does not auto-apply any of this to new windows or derived windows. nope. you gotta configure each window yourself if you want that behavior. main character energy means doing your own setup, bestie. ✨

also, heads up: some of the descriptions below talk about an "input character reading function". that's wgetch(3X) in the non-wide character curses API, and wget_wch(3X) in the wide character API. and it's not just those two β€” on top of the variant forms described in ncurses(3X), the curses functions wgetstr(3X) and wget_wstr(3X) plus their own variants all call the appropriate input character reading function. so yeah, the whole squad is involved. πŸŽ€


πŸ“ cbreak, nocbreak

so normally the terminal driver is out here buffering your typed characters β€” it won't hand them to the app until you hit a line feed or carriage return. that canonical ("cooked") line discipline also gives you software flow control, simple line editing (character erase, word erase, and whole-line erasure aka "kill"), and job control. all very cute, all very delayed.

cbreak flips the terminal into cbreak mode, which:

  • disables line buffering, and
  • disables erase and kill character processing.

the interrupt, quit, suspend, and flow control characters are unaffected β€” those keep doing their thing. and now characters the user types become immediately available to the program. slay. πŸŽ‰

nocbreak puts you back in canonical ("cooked") mode. 🍳

real talk: when a curses app starts, the terminal's state is a mystery. unknown. so a program should call cbreak or nocbreak explicitly β€” don't assume. most interactive programs using curses go with cbreak mode. and note that calling cbreak overrides raw.

the man page for the input character reading function gets into how cbreak and nocbreak interact with echo and noecho. iykyk. πŸ’œ


🌈 echo, noecho

echo and noecho decide whether characters the user types get written to the curses window by the input character reading function, as they're typed. important: curses always disables the terminal driver's own echoing β€” that's not up for debate. by default, a curses screen's echo option is set.

but most interactive program authors want to do their own echoing in some controlled area of the screen, or just not echo at all β€” so they call noecho. iconic behavior, honestly. ✨

the man page for the input character reading function discusses how echo and noecho interact with cbreak and nocbreak. 🫢


🧚 halfdelay

halfdelay sets up half-delay mode. it's like cbreak mode's cousin β€” characters typed by the user are immediately available to the program. but there's a twist: after blocking for tenths tenth-seconds, an input character reading function returns ERR if no input is pending. not me waiting around, bestie. 😭

the value of tenths must be between 1 and 255. use nocbreak to leave half-delay mode. πŸ’…


πŸ’€ intrflush

intrflush calls qiflush (see below) if bf is TRUE, and noqiflush if bf is FALSE. also it completely ignores its win argument. like, doesn't even look at it. πŸ™ˆ


πŸ‘‘ keypad

keypad enables recognition of a terminal's function keys. here's the deal:

  • if enabled (bf is TRUE), then when an input character reading function reads ESC, it waits for further input corresponding to an escape sequence defined by the terminal type description. if a valid sequence populates the input stream, the input character reading function returns a value representing the function key β€” like KEY_LEFT. πŸŽ‰ (wide-character API users: wget_wch(3X) returns KEY_CODE_YES to indicate the availability of a function key code in its wch parameter.) if the sequence is invalid, the input character reading function returns only its last character. πŸ’€
  • if disabled (bf is FALSE), curses does not treat function keys specially, and the program has to interpret escape sequences itself. you're on your own, bestie. 🫑

and if the terminal type description defines the keypad_local (rmkx) and keypad_xmit (smkx) capabilities:

  • enabling a window's keypad mode sets the terminal's keypad to transmit
  • disabling keypad mode sets the terminal's keypad to work locally

by default, a window's keypad mode is off. πŸŒ™


πŸ’œ meta

initially, whether the terminal returns 7- or 8-bit character codes on input depends on how the terminal driver is configured; on POSIX systems, see termios(3). here's how to take control:

  • to force 8 bits to be returned, call meta(..., TRUE) β€” this is equivalent, on POSIX systems, to setting the CS8 flag on the terminal.
  • to force 7 bits to be returned, call meta(..., FALSE) β€” equivalent, on POSIX systems, to setting the CS7 flag on the terminal.

curses ignores the window argument win. (it's just there for the vibes, apparently. πŸ™ˆ)

and if the terminfo string capabilities meta_on (smm) and meta_off (rmm) are defined for the terminal type, then enabling meta mode sends smm's value to the terminal and disabling it sends that of rmm to the terminal. ✨


🌸 nl, nonl

initially, whether the terminal reports a carriage return using the character code for a line feed in cbreak or raw modes depends on the configuration of the terminal driver; see termios(3). so:

  • nl configures the terminal to perform this translation.
  • nonl disables it.

and under its canonical ("cooked") line discipline, the terminal driver always translates carriage returns to line feeds. no debate, no exceptions. πŸ’…


⭐ nodelay

nodelay configures the input character reading function to be non-blocking for window win. if no input is ready, the reading function returns ERR. if disabled (bf is FALSE), the reading function does not return until it has input. so like β€” one mode is "i'm busy, don't wait up", the other is "i will literally stand here until you speak." 😭


πŸ¦‹ notimeout

when keypad has been called on a window and the input character reading function reads an ESC character from it, curses sets a timer while waiting for the next character. if the timer elapses, curses interprets the ESC as an explicit press of the terminal's Escape key (or equivalent).

notimeout(win, TRUE) disables this timer. ⏰

the whole point of the timeout is to tell apart sequences produced by a function key from ones typed by a user. but if this timer is disabled, curses waits forever for subsequent keystrokes until it determines the escape sequence to be valid or invalid. forever. fr fr. πŸ’€


πŸŽ€ qiflush, noqiflush

qiflush and noqiflush configure the terminal driver's treatment of its input and output queues when it handles the interrupt, suspend, or quit characters under the canonical ("cooked") or cbreak line disciplines on POSIX systems; see termios(3). the default behavior is inherited from the terminal driver settings. okay so:

  • calling qiflush configures the terminal to flush the queues (discarding their contents) when any of these events occurs. it gives the impression of faster response to user input, but it makes the library's model of the screen contents incorrect. 🚨
  • calling noqiflush prevents such flushing, but might frustrate impatient users on slow connections if a curses update of the screen is in progress when the event occurs; see typeahead below for a mitigation of this problem. 🐌
pro tip (straight from the page, bestie): you may want to call noqiflush in a signal handler if, after the handler exits, you want output to continue as though the signal had not occurred. ✨

πŸ”₯ raw, noraw

raw configures the terminal to read input in raw mode. it's similar to cbreak mode (see cbreak above) except that it furthermore passes through the terminal's configured interrupt, quit, suspend, and flow control characters uninterpreted to the application β€” instead of generating a signal or acting on I/O flow. so no signals, no flow control, just raw characters hitting your app. wild. πŸ’…

the behavior of the terminal's "Break" key (if any) depends on terminal driver configuration parameters that curses does not handle. not our problem, not our department. πŸ™ˆ

noraw restores the terminal's canonical ("cooked") line discipline. 🍳


πŸ’– timeout, wtimeout

wtimeout configures whether a curses input character reading function called on window win uses blocking or non-blocking reads. here's the whole mood ring:

  • if delay is negative, curses uses a blocking read, waiting indefinitely for input.
  • if delay is zero, the read is non-blocking; an input character reading function returns ERR if no input is pending.
  • if delay is positive, an input character reading function blocks for delay milliseconds, and returns ERR if the delay elapses and there is still no input pending. ⏱️

timeout calls wtimeout on stdscr. that's it, that's the shortcut. ✨


🧚 typeahead

normally, a curses library checks the terminal's input file descriptor for activity with poll(2) or select(2) while updating the screen. if it finds any, it postpones output until the next wrefresh(3X) or doupdate(3X) call β€” allowing faster response to user key strokes. so considerate. πŸ₯°

the library tests the file descriptor corresponding to the FILE stream pointer passed to newterm(3X) (or stdin if initscr(3X) was called), for pending input.

typeahead instructs curses to test file descriptor fd instead. and an fd of -1 disables the check entirely. πŸ‘‘


🌈 RETURN VALUE 🌈

timeout and wtimeout return no value. they just do the thing and leave. πŸ’…

cbreak, nocbreak, echo, noecho, halfdelay, intrflush, keypad, meta, nodelay, notimeout, nl, nonl, raw, noraw, and typeahead return OK on success and ERR on failure. classic.

in ncurses, the functions in the previous paragraph return ERR if:

  • the library's TERMINAL structure for the device has not been initialized with initscr(3X), newterm(3X), or setupterm(3X), or
  • win is a null pointer (except with intrflush and meta, which ignore its value). πŸ™ˆ

further, halfdelay returns ERR if delay is outside the range 1..255. 🚨

see section "EXTENSIONS" below for the return values of is_cbreak, is_echo, is_nl, and is_raw. ✨

πŸ“ NOTES

Okay bestie, real talk β€” a bunch of these functions might not even be functions. echo, noecho, halfdelay, intrflush, meta, nl, nonl, nodelay, notimeout, noqiflush, qiflush, timeout, and wtimeout may be implemented as macros. So like, don't try anything cute with function pointers, mwah πŸ’…


So noraw and nocbreak are doing historical-practice-core, and what that means is: they each try to restore the terminal's canonical (β€œcooked”) line discipline β€” noraw from raw, and nocbreak from cbreak. ✨

⚠️ And here's the tea: mixing raw/noraw calls with cbreak/nocbreak calls leaves you with terminal driver control states that are hard to predict or understand. Like genuinely, nobody can read those vibes. Doing it is not recommended, fr fr.

The way that curses documentation throws the words β€œdelay” and β€œtimeout” around all willy-nilly to describe two related but distinct aspects of input handling is honestly giving chaos 😭 β€” at the risk of confusing you, the user.

So let's break it down, no cap:

  • halfdelay, nodelay, timeout, and wtimeout decide whether the input character reading function (wgetch(3X) or wget_wch(3X)) waits for keyboard input to begin, and for how long.
  • keypad decides whether that same function waits for further input if the first character it reads is ESC.
  • Calling notimeout β€” which, bestie, has absolutely nothing to do with timeout or wtimeout πŸ™ˆ β€” makes that second delay in expectation of further characters effectively infinite.

X/Open Curses offers no means of otherwise configuring the length of this second delay. But! An AIX and ncurses extension, ESCDELAY, exists and is available both as an environment variable (for the user) and as a global symbol (for the application) to do exactly that. See ncurses(3X) and curs_variables(3X) for the deets 🫢


✨ EXTENSIONS ✨

ncurses serves up four is_ functions, one for each of cbreak, echo, nl, and raw, so your application can actually query their states instead of just guessing. Iconic behaviour, honestly πŸ‘‘

Here's the mapping, bestie:

  • is_cbreak β€” queries the state that cbreak sets and nocbreak resets
  • is_echo β€” queries the state that echo sets and noecho resets
  • is_nl β€” queries the state that nl sets and nonl resets
  • is_raw β€” queries the state that raw sets and noraw resets

And in every single case, the function returns:

  • 1 β€” if the option is set,
  • 0 β€” if the option is unset, or
  • -1 β€” if the library's TERMINAL structure for the device has not been initialized πŸ’€

🌍 PORTABILITY 🌍

If your app is using ncurses extensions, you should gate that usage on whether the NCURSES_VERSION preprocessor macro is visible. That's the vibe check, periodt.

Except as noted in the section β€œEXTENSIONS” above, X/Open Curses Issue 4 describes these functions. It specifies no error conditions for them β€” so don't go looking for error codes that aren't there, bestie πŸŽ€

SVr4 describes a successful return value only as β€œan integer value other than ERR”. That's it. That's the whole description. So helpful of it πŸ’€


Here's where it gets juicy. ncurses follows X/Open Curses and the historical practice of System V curses, which means it clears the terminal driver's β€œecho” flag when initializing the screen. BSD curses did not do this β€” but its raw function turned it off as a side effect, sneaky little thing.

πŸ’– For best portability, call echo or noecho explicitly right after initialization, even if your program retains the terminal's canonical (β€œcooked”) line discipline. Do it. Future you says thank you.

X/Open Curses is being ambiguous and mysterious about whether raw should disable the carriage return and line feed translation feature controlled by nl and nonl πŸ™ˆ

  • BSD curses turned off these translations.
  • System V curses did not.
  • ncurses does, on the assumption that a programmer requesting raw input wants a clean (ideally, 8-bit clean) connection that the operating system will not alter.

Okay so when keypad is first enabled for a window, ncurses loads the standard function key string capabilities for the terminal type description of its screen β€” check the entries beginning with β€œkey_” in terminfo(5), iykyk. πŸ”‘

If that description includes extended string capabilities β€” produced by the -x option of tic(1), for example β€” then ncurses also defines keys for the capabilities whose codes begin with β€œk”.

And listen: ncurses generates a numeric key code for each such extended capability. Depending on previous loads of terminal type descriptions, these may differ from one execution of a program to the next 😳 so don't hardcode them, bestie.

  • keyname(3X) recognizes the generated key codes and returns a name beginning with β€œk”, denoting the terminfo capability name rather than KEY_, which is used for curses key names.
  • On the other hand, an application can use define_key(3X) to bind a selected key to a string of the programmer's choice. πŸ’… This feature lets an application check for its presence with tigetstr(3X), and reassign the numeric key code to match its own needs.

Low-level applications can use tigetstr(3X) to obtain the definition of any string capability. Meanwhile, curses applications use the input character reading function to obtain key codes from input, and they rely upon the order in which the string capabilities are loaded.

Multiple key capability strings can have the same value, but the input character reading function can report only one key code. Rude, but true 😭

Most curses implementations (ncurses included) load key definitions in the order they appear in the strfnames array of string capability names β€” see term_variables(3X). The last capability read using a particular definition determines the key code to be reported. ✨

In ncurses, extended capabilities can be interpreted as key definitions. The library loads these after its built-in definitions, and if an extended capability's value is the same as one previously loaded, the library uses the later definition. Last one in wins, periodt.


πŸ“œ HISTORY πŸ“œ

  • 4BSD (1980) introduced echo, noecho, nl, nonl, raw, and noraw. The originals, the icons πŸ‘‘
  • SVr2 (1984) featured a new terminal driver, extending the curses API to support it with cbreak, nocbreak, intrflush, keypad, meta, nodelay, and typeahead.
  • SVr3 (1987) added halfdelay, notimeout, and wtimeout. Then qiflush and noqiflush appeared in SVr3.1 (1987), at which point intrflush became a wrapper for either of these functions, depending on the value of its Boolean argument. SVr3.1 also added timeout.
  • ncurses 6.5 (2024) introduced is_cbreak, is_echo, is_nl, and is_raw. Fresh out the oven πŸ“

Okay this next bit is a genuine glow-up story. ✨

Formerly, ncurses used nl and nonl to control the conversion of newlines to carriage return/line feed on output as well as input. But X/Open Curses documents the use of these functions only for input.

Where did this difference come from, you ask? It arose from converting the pcurses source (1986) β€” which used ioctl(2) calls and the sgttyb structure β€” to termios (the POSIX terminal API).

  • In the former, both input and output conversions were controlled via a single option, β€œCRMOD”.
  • The latter separates these features.

And because that conversion interferes with output optimization, ncurses 6.2 (2020) amended nl and nonl to eliminate their effect on output. Character development, honestly πŸ¦‹


πŸ‘€ SEE ALSO πŸ‘€

  • curses(3X)
  • curs_getch(3X)
  • curs_initscr(3X)
  • curs_util(3X)
  • define_key(3X)
  • termios(3)
  • term_variables(3X)

And that's the whole page, bestie!! πŸŽ€ This one's from ncurses 6.6, dated 2025-10-04, and you just finished reading curs_inopts(3X) in all its glory. Go forth and configure those input options responsibly, mwah πŸ’–βœ¨

πŸ“¦ where this page comes from