input: move to inputlayer abstraction

pull/966/head
nick black 4 years ago committed by Nick Black
parent 602607d737
commit 2ef2435953

@ -20,7 +20,7 @@ void sigwinch_handler(int signo){
}
static inline int
pop_input_keypress(notcurses* nc){
pop_input_keypress(ncinputlayer* nc){
int candidate = nc->inputbuf[nc->inputbuf_valid_starts];
// fprintf(stderr, "DEOCCUPY: %u@%u read: %d\n", nc->inputbuf_occupied, nc->inputbuf_valid_starts, nc->inputbuf[nc->inputbuf_valid_starts]);
if(++nc->inputbuf_valid_starts == sizeof(nc->inputbuf) / sizeof(*nc->inputbuf)){
@ -32,7 +32,7 @@ pop_input_keypress(notcurses* nc){
// assumes there is space, as you presumably just popped it
static inline void
unpop_keypress(notcurses* nc, int kpress){
unpop_keypress(ncinputlayer* nc, int kpress){
++nc->inputbuf_occupied;
if(nc->inputbuf_valid_starts-- == 0){
nc->inputbuf_valid_starts = sizeof(nc->inputbuf) / sizeof(*nc->inputbuf) - 1;
@ -73,7 +73,7 @@ void input_free_esctrie(esctrie** eptr){
}
static int
notcurses_add_input_escape(notcurses* nc, const char* esc, char32_t special){
ncinputlayer_add_input_escape(ncinputlayer* nc, const char* esc, char32_t special){
if(esc[0] != ESC || strlen(esc) < 2){ // assume ESC prefix + content
fprintf(stderr, "Not an escape: %s (0x%x)\n", esc, special);
return -1;
@ -116,7 +116,7 @@ notcurses_add_input_escape(notcurses* nc, const char* esc, char32_t special){
// We received the CSI prefix. Extract the data payload.
static char32_t
handle_csi(notcurses* nc, ncinput* ni){
handle_csi(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin){
enum {
PARAM1, // reading first param (button + modifiers) plus delimiter
PARAM2, // reading second param (x coordinate) plus delimiter
@ -162,7 +162,7 @@ handle_csi(notcurses* nc, ncinput* ni){
break;
}
if(ni){
ni->x = param - 1 - nc->margin_l;
ni->x = param - 1 - leftmargin;
}
param = 0;
}else if(isdigit(candidate)){
@ -180,7 +180,7 @@ handle_csi(notcurses* nc, ncinput* ni){
break;
}
if(ni){
ni->y = param - 1 - nc->margin_t;
ni->y = param - 1 - topmargin;
ni->id = id;
}
return id;
@ -200,7 +200,7 @@ handle_csi(notcurses* nc, ncinput* ni){
// if there is a full UTF8 codepoint or keystroke (composed or otherwise),
// return it, and pop it from the queue.
static char32_t
handle_getc(notcurses* nc, int kpress, ncinput* ni){
handle_getc(ncinputlayer* nc, int kpress, ncinput* ni, int leftmargin, int topmargin){
//fprintf(stderr, "KEYPRESS: %d\n", kpress);
if(kpress < 0){
return -1;
@ -220,7 +220,7 @@ handle_getc(notcurses* nc, int kpress, ncinput* ni){
}
if(esc && esc->special != NCKEY_INVALID){
if(esc->special == NCKEY_CSI){
return handle_csi(nc, ni);
return handle_csi(nc, ni, leftmargin, topmargin);
}
return esc->special;
}
@ -291,12 +291,12 @@ block_on_input(FILE* fp, const struct timespec* ts, sigset_t* sigmask){
}
static bool
input_queue_full(const notcurses* nc){
input_queue_full(const ncinputlayer* nc){
return nc->inputbuf_occupied == sizeof(nc->inputbuf) / sizeof(*nc->inputbuf);
}
static char32_t
handle_input(notcurses* nc, ncinput* ni){
handle_input(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin){
int r;
// getc() returns unsigned chars cast to ints
while(!input_queue_full(nc) && (r = getc(nc->ttyinfp)) >= 0){
@ -317,15 +317,15 @@ handle_input(notcurses* nc, ncinput* ni){
return -1;
}
r = pop_input_keypress(nc);
return handle_getc(nc, r, ni);
return handle_getc(nc, r, ni, leftmargin, topmargin);
}
static char32_t
handle_ncinput(notcurses* nc, ncinput* ni){
handle_ncinput(ncinputlayer* nc, ncinput* ni, int leftmargin, int topmargin){
if(ni){
memset(ni, 0, sizeof(*ni));
}
char32_t r = handle_input(nc, ni);
char32_t r = handle_input(nc, ni, leftmargin, topmargin);
// ctrl (*without* alt) + letter maps to [1..26], and is independent of shift
// FIXME need to distinguish between:
// - Enter and ^J
@ -353,14 +353,15 @@ handle_ncinput(notcurses* nc, ncinput* ni){
// helper so we can do counter increment at a single location
static inline char32_t
notcurses_prestamp(notcurses* nc, const struct timespec *ts,
sigset_t* sigmask, ncinput* ni){
ncinputlayer_prestamp(ncinputlayer* nc, const struct timespec *ts,
sigset_t* sigmask, ncinput* ni, int leftmargin,
int topmargin){
errno = 0;
char32_t r = handle_ncinput(nc, ni);
char32_t r = handle_ncinput(nc, ni, leftmargin, topmargin);
if(r == (char32_t)-1){
if(errno == EAGAIN || errno == EWOULDBLOCK){
block_on_input(nc->ttyinfp, ts, sigmask);
r = handle_ncinput(nc, ni);
r = handle_ncinput(nc, ni, leftmargin, topmargin);
}
return r;
}
@ -370,9 +371,10 @@ notcurses_prestamp(notcurses* nc, const struct timespec *ts,
// infp has already been set non-blocking
char32_t notcurses_getc(notcurses* nc, const struct timespec *ts,
sigset_t* sigmask, ncinput* ni){
char32_t r = notcurses_prestamp(nc, ts, sigmask, ni);
char32_t r = ncinputlayer_prestamp(&nc->input, ts, sigmask, ni,
nc->margin_l, nc->margin_t);
if(r != (char32_t)-1){
uint64_t stamp = nc->input_events++; // need increment even if !ni
uint64_t stamp = nc->input.input_events++; // need increment even if !ni
if(ni){
ni->seqnum = stamp;
}
@ -380,7 +382,7 @@ char32_t notcurses_getc(notcurses* nc, const struct timespec *ts,
return r;
}
int prep_special_keys(notcurses* nc){
int prep_special_keys(ncinputlayer* nc){
static const struct {
const char* tinfo;
char32_t key;
@ -484,12 +486,12 @@ int prep_special_keys(notcurses* nc){
continue;
}
//fprintf(stderr, "support for terminfo's %s: %s\n", k->tinfo, seq);
if(notcurses_add_input_escape(nc, seq, k->key)){
if(ncinputlayer_add_input_escape(nc, seq, k->key)){
fprintf(stderr, "Couldn't add support for %s\n", k->tinfo);
return -1;
}
}
if(notcurses_add_input_escape(nc, CSIPREFIX, NCKEY_CSI)){
if(ncinputlayer_add_input_escape(nc, CSIPREFIX, NCKEY_CSI)){
fprintf(stderr, "Couldn't add support for %s\n", k->tinfo);
return -1;
}

@ -252,6 +252,23 @@ typedef struct tinfo {
char* rmcup; // restore primary mode
} tinfo;
typedef struct ncinputlayer {
FILE* ttyinfp; // FILE* for processing input
unsigned char inputbuf[BUFSIZ];
// we keep a wee ringbuffer of input queued up for delivery. if
// inputbuf_occupied == sizeof(inputbuf), there is no room. otherwise, data
// can be read to inputbuf_write_at until we fill up. the first datum
// available for the app is at inputbuf_valid_starts iff inputbuf_occupied is
// not 0. the main purpose is working around bad predictions of escapes.
unsigned inputbuf_occupied;
unsigned inputbuf_valid_starts;
unsigned inputbuf_write_at;
// number of input events seen. does not belong in ncstats, since it must not
// be reset (semantics are relied upon by widgets for mouse click detection).
uint64_t input_events;
struct esctrie* inputescapes; // trie of input escapes -> ncspecial_keys
} ncinputlayer;
typedef struct ncdirect {
palette256 palette; // 256-indexed palette can be used instead of/with RGB
FILE* ttyfp; // FILE* for output tty
@ -259,6 +276,7 @@ typedef struct ncdirect {
tinfo tcache; // terminfo cache
unsigned fgrgb, bgrgb; // last RGB values of foreground/background
uint16_t stylemask; // current styles
ncinputlayer input; // input layer; we're in cbreak mode
bool fgdefault, bgdefault; // are FG/BG currently using default colors?
bool utf8; // are we using utf-8 encoding, as hoped?
struct termios tpreserved; // terminal state upon entry
@ -288,34 +306,19 @@ typedef struct notcurses {
int truecols; // true number of columns in the physical rendering area.
// used only to see if output motion takes us to the next
// line thanks to terminal action alone.
tinfo tcache; // terminfo cache
FILE* ttyfp; // FILE* for writing rasterized data
int ttyfd; // file descriptor for controlling tty
FILE* ttyinfp; // FILE* for processing input
ncinputlayer input; // input layer; we're in cbreak mode
FILE* renderfp; // debugging FILE* to which renderings are written
tinfo tcache; // terminfo cache
struct termios tpreserved; // terminal state upon entry
bool suppress_banner; // from notcurses_options
unsigned char inputbuf[BUFSIZ];
// we keep a wee ringbuffer of input queued up for delivery. if
// inputbuf_occupied == sizeof(inputbuf), there is no room. otherwise, data
// can be read to inputbuf_write_at until we fill up. the first datum
// available for the app is at inputbuf_valid_starts iff inputbuf_occupied is
// not 0. the main purpose is working around bad predictions of escapes.
unsigned inputbuf_occupied;
unsigned inputbuf_valid_starts;
unsigned inputbuf_write_at;
// number of input events seen. does not belong in ncstats, since it must not
// be reset (semantics are relied upon by widgets for mouse click detection).
uint64_t input_events;
// desired margins (best-effort only), copied in from notcurses_options
int margin_t, margin_b, margin_r, margin_l;
int loglevel;
palette256 palette; // 256-indexed palette can be used instead of/with RGB
bool palette_damage[NCPALETTESIZE];
struct esctrie* inputescapes; // trie of input escapes -> ncspecial_keys
bool utf8; // are we using utf-8 encoding, as hoped?
bool libsixel; // do we have Sixel support?
} notcurses;
@ -362,7 +365,7 @@ ncplane_stdplane_const(const ncplane* n){
}
// load all known special keys from terminfo, and build the input sequence trie
int prep_special_keys(notcurses* nc);
int prep_special_keys(ncinputlayer* nc);
// free up the input escapes trie
void input_free_esctrie(struct esctrie** trie);

@ -888,8 +888,8 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
reset_stats(&ret->stashstats);
ret->ttyfp = outfp;
ret->renderfp = opts->renderfp;
ret->inputescapes = NULL;
ret->ttyinfp = stdin; // FIXME
ret->input.inputescapes = NULL;
ret->input.ttyinfp = stdin; // FIXME
memset(&ret->rstate, 0, sizeof(ret->rstate));
memset(&ret->palette_damage, 0, sizeof(ret->palette_damage));
memset(&ret->palette, 0, sizeof(ret->palette));
@ -898,14 +898,14 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
ret->lfdimx = 0;
ret->libsixel = false;
egcpool_init(&ret->pool);
if(make_nonblocking(ret->ttyinfp)){
if(make_nonblocking(ret->input.ttyinfp)){
free(ret);
return NULL;
}
ret->inputbuf_occupied = 0;
ret->inputbuf_valid_starts = 0;
ret->inputbuf_write_at = 0;
ret->input_events = 0;
ret->input.inputbuf_occupied = 0;
ret->input.inputbuf_valid_starts = 0;
ret->input.inputbuf_write_at = 0;
ret->input.input_events = 0;
if((ret->loglevel = opts->loglevel) > NCLOGLEVEL_TRACE || ret->loglevel < 0){
fprintf(stderr, "Invalid loglevel %d\n", ret->loglevel);
free(ret);
@ -951,7 +951,7 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){
if(interrogate_terminfo(&ret->tcache)){
goto err;
}
if(prep_special_keys(ret)){
if(prep_special_keys(&ret->input)){
goto err;
}
// Neither of these is supported on e.g. the "linux" virtual console.
@ -1039,7 +1039,7 @@ int notcurses_stop(notcurses* nc){
egcpool_dump(&nc->pool);
free(nc->lastframe);
free(nc->rstate.mstream);
input_free_esctrie(&nc->inputescapes);
input_free_esctrie(&nc->input.inputescapes);
stash_stats(nc);
if(!nc->suppress_banner){
if(nc->stashstats.renders){
@ -2134,7 +2134,7 @@ int notcurses_lex_margins(const char* op, notcurses_options* opts){
}
int notcurses_inputready_fd(notcurses* n){
return fileno(n->ttyinfp);
return fileno(n->input.ttyinfp);
}
uint32_t* ncplane_rgba(const ncplane* nc, ncblitter_e blit,

Loading…
Cancel
Save