mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
Add keytype indicator to notcurses-input #2182
This commit is contained in:
parent
99007e128c
commit
ea5da346f0
2
NEWS.md
2
NEWS.md
@ -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
|
||||
|
8
USAGE.md
8
USAGE.md
@ -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,
|
||||
|
10
src/lib/in.c
10
src/lib/in.c
@ -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…
x
Reference in New Issue
Block a user