diff --git a/NEWS.md b/NEWS.md index b9496b340..c6b878857 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ This document attempts to list user-visible changes and any major internal rearrangements of Notcurses. +* 2.1.2 (not yet released) + * Add `notcurses_linesigs_enable()` and `notcurses_linesigs_disable()`. + * 2.1.1 (2020-12-16) * Progress bars via `ncprogbar`, using the standard widget API. diff --git a/USAGE.md b/USAGE.md index 16dced778..2a83730b4 100644 --- a/USAGE.md +++ b/USAGE.md @@ -554,12 +554,6 @@ nckey_supppuab_p(char32_t w){ return w >= 0x100000 && w <= 0x10fffd; } -// Is the event a synthesized mouse event? -static inline bool -nckey_mouse_p(char32_t r){ - return r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE; -} - // An input event. Cell coordinates are currently defined only for mouse events. typedef struct ncinput { char32_t id; // identifier. Unicode codepoint or synthesized NCKEY event @@ -601,6 +595,20 @@ notcurses_getc_blocking(struct notcurses* n, ncinput* ni){ } ``` +By default, certain keys are mapped to signals by the terminal's line +discipline. This can be disabled with `notcurses_linesigs_disable()`, and +reenabled with `notcurses_linesigs_enable()`. + +``` +// Disable signals originating from the terminal's line discipline, i.e. +// SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z). They are enabled by default. +int notcurses_linesigs_disable(struct notcurses* n); + +// Restore signals originating from the terminal's line discipline, i.e. +// SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z), if disabled. +int notcurses_linesigs_enable(struct notcurses* n); +``` + ## Mice notcurses supports mice, though only through brokers such as X or @@ -616,6 +624,12 @@ int notcurses_mouse_enable(struct notcurses* n); // Disable mouse events. Any events in the input queue can still be delivered. int notcurses_mouse_disable(struct notcurses* n); + +// Is the event a synthesized mouse event? +static inline bool +nckey_mouse_p(char32_t r){ + return r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE; +} ``` "Button-event tracking mode" implies the ability to detect mouse button diff --git a/doc/man/man3/notcurses_input.3.md b/doc/man/man3/notcurses_input.3.md index c4e56dee4..edbc481d5 100644 --- a/doc/man/man3/notcurses_input.3.md +++ b/doc/man/man3/notcurses_input.3.md @@ -41,6 +41,10 @@ typedef struct ncinput { **static inline bool ncinput_equal_p(const struct ncinput* ***n1***, const struct ncinput* ***n2***);** +**int notcurses_linesigs_disable(struct notcurses* ***n***);** + +**int notcurses_linesigs_enable(struct notcurses* ***n***);** + # DESCRIPTION notcurses supports input from keyboards and mice, and any device that looks @@ -73,6 +77,13 @@ be called without the possibility of blocking. not considering padding or the **seqnum** field), returning **true** if they represent the same input (though not necessarily the same input event). +**notcurses_linesigs_disable** disables conversion of inputs **INTR**, **QUIT**, +**SUSP**, and **DSUSP** into **SIGINT**, **SIGQUIT**, and **SIGTSTP**. These +conversions are enabled by default. **notcurses_linesigs_enable** undoes this +action, but signals in the interim are permanently lost. + +**int notcurses_linesigs_enable(struct notcurses* ***n***);** + ## Mice For mouse events, the additional fields **y** and **x** are set. These fields diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 953b3087a..38b46b9b7 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1012,6 +1012,14 @@ API int notcurses_mouse_enable(struct notcurses* n); // Disable mouse events. Any events in the input queue can still be delivered. API int notcurses_mouse_disable(struct notcurses* n); +// Disable signals originating from the terminal's line discipline, i.e. +// SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z). They are enabled by default. +API int notcurses_linesigs_disable(struct notcurses* n); + +// Restore signals originating from the terminal's line discipline, i.e. +// SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z), if disabled. +API int notcurses_linesigs_enable(struct notcurses* n); + // Refresh the physical screen to match what was last rendered (i.e., without // reflecting any changes since the last call to notcurses_render()). This is // primarily useful if the screen is externally corrupted, or if an diff --git a/src/lib/input.c b/src/lib/input.c index 04cd8b556..84cae7fec 100644 --- a/src/lib/input.c +++ b/src/lib/input.c @@ -28,7 +28,7 @@ int cbreak_mode(int ttyfd, const struct termios* tpreserved){ // etc. still have their typical effects. ICRNL maps return to 13 (Ctrl+M) // instead of 10 (Ctrl+J). modtermios.c_lflag &= (~ECHO & ~ICANON); - modtermios.c_iflag &= (~ICRNL); + modtermios.c_iflag &= ~ICRNL; if(tcsetattr(ttyfd, TCSANOW, &modtermios)){ fprintf(stderr, "Error disabling echo / canonical on %d (%s)\n", ttyfd, strerror(errno)); return -1; @@ -36,6 +36,44 @@ int cbreak_mode(int ttyfd, const struct termios* tpreserved){ return 0; } +// Disable signals originating from the terminal's line discipline, i.e. +// SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z). They are enabled by default. +int notcurses_linesigs_disable(notcurses* n){ + if(n->ttyfd < 0){ + return 0; + } + struct termios tios; + if(tcgetattr(n->ttyfd, &tios)){ + logerror(n, "Couldn't preserve terminal state for %d (%s)\n", n->ttyfd, strerror(errno)); + return -1; + } + tios.c_lflag &= ~ISIG; + if(tcsetattr(n->ttyfd, TCSANOW, &tios)){ + logerror(n, "Error disabling signals on %d (%s)\n", n->ttyfd, strerror(errno)); + return -1; + } + return 0; +} + +// Restore signals originating from the terminal's line discipline, i.e. +// SIGINT (^C), SIGQUIT (^\), and SIGTSTP (^Z), if disabled. +int notcurses_linesigs_enable(notcurses* n){ + if(n->ttyfd < 0){ + return 0; + } + struct termios tios; + if(tcgetattr(n->ttyfd, &tios)){ + logerror(n, "Couldn't preserve terminal state for %d (%s)\n", n->ttyfd, strerror(errno)); + return -1; + } + tios.c_lflag |= ~ISIG; + if(tcsetattr(n->ttyfd, TCSANOW, &tios)){ + logerror(n, "Error disabling signals on %d (%s)\n", n->ttyfd, strerror(errno)); + return -1; + } + return 0; +} + static inline int pop_input_keypress(ncinputlayer* nc){ int candidate = nc->inputbuf[nc->inputbuf_valid_starts];