Add keytype indicator to notcurses-input #2182

pull/2197/head
nick black 3 years ago
parent 99007e128c
commit ea5da346f0
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -13,7 +13,7 @@ rearrangements of Notcurses.
continue reading). Likewise added `NCDIRECT_OPTION_DRAIN_INPUT`.
* Removed a bunch of deprecated `static inline` functions from the headers.
* A new field, `evtype`, has been added to `ncinput`. It takes a value
from among `EVTYPE_{UNKNOWN, PRESS, REPEAT, RELEASE}.`. Where possible,
from among `NCTYPE_{UNKNOWN, PRESS, REPEAT, RELEASE}.`. Where possible,
Notcurses will distinguish between a press, repeat, and release. This
cannot be done in all environments, nor with all inputs. The
`NCKEY_RELEASE` definition is no longer returned; instead, the

@ -685,10 +685,10 @@ typedef struct ncinput {
bool shift; // was shift held?
bool ctrl; // was ctrl held?
enum {
EVTYPE_UNKNOWN,
EVTYPE_PRESS,
EVTYPE_REPEAT,
EVTYPE_RELEASE,
NCTYPE_UNKNOWN,
NCTYPE_PRESS,
NCTYPE_REPEAT,
NCTYPE_RELEASE,
} evtype;
} ncinput;

@ -15,14 +15,22 @@ notcurses-input - Read and display input events
**notcurses-input** reads from stdin and decodes the input to stdout, including
synthesized events and mouse events. To exit, generate EOF (usually Ctrl+'d').
Each event will be printed on a single line. Leading that line is a series
of modifier indicators:
* 'A'/'a': Alt was or was not pressed.
* 'C'/'c': Ctrl was or was not pressed.
* 'S'/'s': Shift was or was not pressed.
* 'L'/'R'/'P'/'u': Key was a release, repeat, press, or of unknown type.
# OPTIONS
**-v**: Increase verbosity.
# NOTES
Mouse events are only generated for button presses, and for movement while a
button is held down.
Mouse events are only generated for button presses and releases, and for
movement while a button is held down.
# SEE ALSO

@ -92,13 +92,13 @@ action, but signals in the interim are permanently lost.
## Mice
For mouse events, the additional fields **y** and **x** are set. These fields
are not meaningful for keypress events. Mouse events can be distinguished using
the **nckey_mouse_p** predicate. Once enabled, mouse button presses are
detected, as are mouse motions made while a button is held down. If no button
is depressed, mouse movement _does not result in events_. This is known as
"button-event tracking" mode in the nomenclature of [Xterm Control
Sequences](https://www.xfree86.org/current/ctlseqs.html).
For mouse events, the additional fields **y** and **x** are set. These
fields are not meaningful for keypress events. Mouse events can be
distinguished using the **nckey_mouse_p** predicate. Once enabled, mouse
button presses and releases are detected, as are mouse motions made while a
button is held down. If no button is depressed, mouse movement _does not
result in events_. This is known as "button-event tracking" mode in the
nomenclature of [Xterm Control Sequences](https://www.xfree86.org/current/ctlseqs.html).
## Synthesized keypresses
@ -169,19 +169,20 @@ Failed escape sequences are not yet played back in their entirety; only an
ESC (ASCII 0x1b) will be seen by the application.
The Shift key is only indicated in conjunction with mouse button presses. If
e.g. Shift is used to generate a capital letter 'A', **id** will equal 'A', and
**shift** will be **false**. This should be fixed in the future.
e.g. Shift is used to generate a capital letter 'A', **id** will equal 'A',
and **shift** will be **false**. This should be fixed in the future.
When Ctrl is pressed along with a letter, the letter will currently always be
reported in its uppercase form. E.g., if Shift, Ctrl, and 'a' are all pressed,
this is indistinguishable from Ctrl and 'a' without Shift. This should be fixed
in the future.
Ctrl pressed along with 'J' or 'M', whether Shift is pressed or not, currently
registers as **NCKEY_ENTER**. This will likely change in the future.
Ctrl pressed along with 'J' or 'M', whether Shift is pressed or not,
currently registers as **NCKEY_ENTER**. This will likely change in the
future.
When the Kitty keyboard disambiguation protocol is used, most of these issues
are resolved.
When the Kitty keyboard disambiguation protocol is used, most of these
issues are resolved.
# SEE ALSO

@ -108,11 +108,15 @@ namespace ncpp
static constexpr char32_t Button9 = NCKEY_BUTTON9;
static constexpr char32_t Button10 = NCKEY_BUTTON10;
static constexpr char32_t Button11 = NCKEY_BUTTON11;
static constexpr char32_t Release = NCKEY_RELEASE;
static constexpr char32_t ScrollUp = NCKEY_SCROLL_UP;
static constexpr char32_t ScrollDown = NCKEY_SCROLL_DOWN;
static constexpr char32_t Return = NCKEY_RETURN;
static constexpr int TypeUnknown = ncinput::NCTYPE_UNKNOWN;
static constexpr int TypePress = ncinput::NCTYPE_PRESS;
static constexpr int TypeRepeat = ncinput::NCTYPE_REPEAT;
static constexpr int TypeRelease = ncinput::NCTYPE_RELEASE;
static bool IsMouse (char32_t ch) noexcept
{
return nckey_mouse_p (ch);

@ -112,10 +112,6 @@ extern "C" {
#define NCKEY_BUTTON9 suppuabize(209)
#define NCKEY_BUTTON10 suppuabize(210)
#define NCKEY_BUTTON11 suppuabize(211)
#define NCKEY_RELEASE suppuabize(212)
// never returned to the user -- when a cursor location report shows up on
// the input, it's picked up by our internals, and used.
#define NCKEY_CURSOR_LOCATION_REPORT suppuabize(213)
// Synonyms (so far as we're concerned)
#define NCKEY_SCROLL_UP NCKEY_BUTTON4

@ -1034,7 +1034,7 @@ nckey_supppuab_p(uint32_t w){
// Is the event a synthesized mouse event?
static inline bool
nckey_mouse_p(uint32_t r){
return r >= NCKEY_BUTTON1 && r <= NCKEY_RELEASE;
return r >= NCKEY_BUTTON1 && r <= NCKEY_BUTTON11;
}
// An input event. Cell coordinates are currently defined only for mouse
@ -1048,10 +1048,10 @@ typedef struct ncinput {
bool shift; // was shift held?
bool ctrl; // was ctrl held?
enum {
EVTYPE_UNKNOWN,
EVTYPE_PRESS,
EVTYPE_REPEAT,
EVTYPE_RELEASE,
NCTYPE_UNKNOWN,
NCTYPE_PRESS,
NCTYPE_REPEAT,
NCTYPE_RELEASE,
} evtype;
} ncinput;
@ -1067,7 +1067,7 @@ ncinput_equal_p(const ncinput* n1, const ncinput* n2){
if(n1->alt != n2->alt || n1->shift != n2->shift || n1->ctrl != n2->ctrl){
return false;
}
if(n1->keytype != n2->keytype){
if(n1->evtype != n2->evtype){
return false;
}
return true;

@ -244,7 +244,7 @@ bool menu_or_hud_key(struct notcurses *nc, const struct ncinput *ni){
if(sel == NULL){
return false;
}
}else if(menu && ni->id == NCKEY_RELEASE){
}else if(menu && ni->id == NCKEY_BUTTON1 && ni->evtype == NCTYPE_RELEASE){
const char* sel = ncmenu_mouse_selected(menu, ni, &tmpni);
if(sel == NULL){
memcpy(&tmpni, ni, sizeof(tmpni));

@ -22,11 +22,11 @@ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int
handle_mouse(const ncinput* ni){
if(ni->id != NCKEY_BUTTON1 && ni->id != NCKEY_RELEASE){
if(ni->id != NCKEY_BUTTON1){
return 0;
}
int ret;
if(ni->id == NCKEY_RELEASE){
if(ni->evtype == NCTYPE_RELEASE){
ret = hud_release();
if(ret < 0){
ret = fpsplot_release();

@ -125,18 +125,17 @@ const char* nckeystr(char32_t spkey){
case NCKEY_EXIT: return "exit";
case NCKEY_PRINT: return "print";
case NCKEY_REFRESH: return "refresh";
case NCKEY_BUTTON1: return "mouse (button 1 pressed)";
case NCKEY_BUTTON2: return "mouse (button 2 pressed)";
case NCKEY_BUTTON3: return "mouse (button 3 pressed)";
case NCKEY_BUTTON4: return "mouse (button 4 pressed)";
case NCKEY_BUTTON5: return "mouse (button 5 pressed)";
case NCKEY_BUTTON6: return "mouse (button 6 pressed)";
case NCKEY_BUTTON7: return "mouse (button 7 pressed)";
case NCKEY_BUTTON8: return "mouse (button 8 pressed)";
case NCKEY_BUTTON9: return "mouse (button 9 pressed)";
case NCKEY_BUTTON10: return "mouse (button 10 pressed)";
case NCKEY_BUTTON11: return "mouse (button 11 pressed)";
case NCKEY_RELEASE: return "mouse (button released)";
case NCKEY_BUTTON1: return "mouse (button 1)";
case NCKEY_BUTTON2: return "mouse (button 2)";
case NCKEY_BUTTON3: return "mouse (button 3)";
case NCKEY_BUTTON4: return "mouse (button 4)";
case NCKEY_BUTTON5: return "mouse (button 5)";
case NCKEY_BUTTON6: return "mouse (button 6)";
case NCKEY_BUTTON7: return "mouse (button 7)";
case NCKEY_BUTTON8: return "mouse (button 8)";
case NCKEY_BUTTON9: return "mouse (button 9)";
case NCKEY_BUTTON10: return "mouse (button 10)";
case NCKEY_BUTTON11: return "mouse (button 11)";
default: return "unknown";
}
}
@ -204,6 +203,20 @@ void Ticker(ncpp::NotCurses* nc) {
}while(!done);
}
char evtype_to_char(ncinput* ni){
switch(ni->evtype){
case NCKey::TypeUnknown:
return 'u';
case NCKey::TypePress:
return 'P';
case NCKey::TypeRepeat:
return 'R';
case NCKey::TypeRelease:
return 'L';
}
return 'X';
}
int input_demo(ncpp::NotCurses* nc) {
constexpr auto PLOTHEIGHT = 6;
auto n = nc->get_stdplane(&dimy, &dimx);
@ -285,8 +298,8 @@ int input_demo(ncpp::NotCurses* nc) {
break;
}
n->set_fg_rgb8(0xd0, 0xd0, 0xd0);
n->printf("%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
ni.shift ? 'S' : 's');
n->printf("%c%c%c%c ", ni.alt ? 'A' : 'a', ni.ctrl ? 'C' : 'c',
ni.shift ? 'S' : 's', evtype_to_char(&ni));
if(r < 0x80){
n->set_fg_rgb8(128, 250, 64);
if(n->printf("ASCII: [0x%02x (%03d)] '%lc'", r, r,

@ -847,9 +847,7 @@ mouse_click(inputctx* ictx, unsigned release){
return;
}
ncinput* ni = ictx->inputs + ictx->iwrite;
if(release){
ni->id = NCKEY_RELEASE;
}else if(ictx->p2 >= 0 && ictx->p2 < 64){
if(ictx->p2 >= 0 && ictx->p2 < 64){
ni->id = NCKEY_BUTTON1 + (ictx->p2 % 4);
}else if(ictx->p2 >= 64 && ictx->p2 < 128){
ni->id = NCKEY_BUTTON4 + (ictx->p2 % 4);
@ -859,6 +857,12 @@ mouse_click(inputctx* ictx, unsigned release){
ni->ctrl = ictx->p2 & 0x10;
ni->alt = ictx->p2 & 0x08;
ni->shift = ictx->p2 & 0x04;
// mice don't send repeat events, so we know it's either release or press
if(release){
ni->evtype = NCTYPE_RELEASE;
}else{
ni->evtype = NCTYPE_PRESS;
}
ni->x = x;
ni->y = y;
if(++ictx->iwrite == ictx->isize){

@ -587,7 +587,10 @@ const char* ncmenu_selected(const ncmenu* n, ncinput* ni){
const char* ncmenu_mouse_selected(const ncmenu* n, const ncinput* click,
ncinput* ni){
if(click->id != NCKEY_RELEASE){
if(click->id != NCKEY_BUTTON1){
return NULL;
}
if(click->evtype != NCTYPE_RELEASE){
return NULL;
}
int y, x, dimy, dimx;
@ -620,7 +623,7 @@ const char* ncmenu_mouse_selected(const ncmenu* n, const ncinput* click,
bool ncmenu_offer_input(ncmenu* n, const ncinput* nc){
// we can't actually select menu items in this function, since we need to
// invoke an arbitrary function as a result.
if(nc->id == NCKEY_RELEASE){
if(nc->id == NCKEY_BUTTON1 && nc->evtype == NCTYPE_RELEASE){
int y, x, dimy, dimx;
y = nc->y;
x = nc->x;

@ -483,7 +483,7 @@ bool ncselector_offer_input(ncselector* n, const ncinput* nc){
}
}
return true;
}else if(nc->id == NCKEY_RELEASE){
}else if(nc->id == NCKEY_BUTTON1 && nc->evtype == NCTYPE_RELEASE){
int y = nc->y, x = nc->x;
if(!ncplane_translate_abs(n->ncp, &y, &x)){
return false;
@ -762,7 +762,7 @@ bool ncmultiselector_offer_input(ncmultiselector* n, const ncinput* nc){
}else if(nc->id == NCKEY_SCROLL_DOWN){
ncmultiselector_nextitem(n);
return true;
}else if(nc->id == NCKEY_RELEASE){
}else if(nc->id == NCKEY_BUTTON1 && nc->evtype == NCTYPE_RELEASE){
int y = nc->y, x = nc->x;
if(!ncplane_translate_abs(n->ncp, &y, &x)){
return false;

@ -872,7 +872,8 @@ TEST_CASE("Plane") {
struct ncplane* n = ncplane_create(n_, &nopts);
REQUIRE(n);
ncinput ni{};
ni.id = NCKEY_RELEASE;
ni.id = NCKEY_BUTTON1;
ni.evtype = ncinput::NCTYPE_RELEASE;
int total = 0;
for(ni.y = 0 ; ni.y < 5 ; ++ni.y){
for(ni.x = 0 ; ni.x < 5 ; ++ni.x){

Loading…
Cancel
Save