diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/curses.c | 249 |
1 files changed, 230 insertions, 19 deletions
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c index 08fe0099b..64ba356a1 100644 --- a/Src/Modules/curses.c +++ b/Src/Modules/curses.c @@ -92,6 +92,7 @@ static struct ttyinfo saved_tty_state; static struct ttyinfo curses_tty_state; static LinkList zcurses_windows; static HashTable zcurses_colorpairs = NULL; +static int zcurses_flags; #define ZCURSES_EINVALID 1 #define ZCURSES_EDEFINED 2 @@ -106,6 +107,11 @@ static HashTable zcurses_colorpairs = NULL; static int zc_errno, zc_color_phase=0; static short next_cp=0; +enum { + ZCF_MOUSE_ACTIVE, + ZCF_MOUSE_MASK_CHANGED +}; + static const struct zcurses_namenumberpair zcurses_attributes[] = { {"blink", A_BLINK}, {"bold", A_BOLD}, @@ -131,6 +137,70 @@ static const struct zcurses_namenumberpair zcurses_colors[] = { {NULL, 0} }; +#ifdef NCURSES_MOUSE_VERSION +enum zcurses_mouse_event_types { + ZCME_PRESSED, + ZCME_RELEASED, + ZCME_CLICKED, + ZCME_DOUBLE_CLICKED, + ZCME_TRIPLE_CLICKED +}; + +static const struct zcurses_namenumberpair zcurses_mouse_event_list[] = { + {"PRESSED", ZCME_PRESSED}, + {"RELEASED", ZCME_RELEASED}, + {"CLICKED", ZCME_CLICKED}, + {"DOUBLE_CLICKED", ZCME_DOUBLE_CLICKED}, + {"TRIPLE_CLICKED", ZCME_TRIPLE_CLICKED}, + {NULL, 0} +}; + +struct zcurses_mouse_event { + int button; + int what; + mmask_t event; +}; + +static const struct zcurses_mouse_event zcurses_mouse_map[] = { + { 1, ZCME_PRESSED, BUTTON1_PRESSED }, + { 1, ZCME_RELEASED, BUTTON1_RELEASED }, + { 1, ZCME_CLICKED, BUTTON1_CLICKED }, + { 1, ZCME_DOUBLE_CLICKED, BUTTON1_DOUBLE_CLICKED }, + { 1, ZCME_TRIPLE_CLICKED, BUTTON1_TRIPLE_CLICKED }, + + { 2, ZCME_PRESSED, BUTTON2_PRESSED }, + { 2, ZCME_RELEASED, BUTTON2_RELEASED }, + { 2, ZCME_CLICKED, BUTTON2_CLICKED }, + { 2, ZCME_DOUBLE_CLICKED, BUTTON2_DOUBLE_CLICKED }, + { 2, ZCME_TRIPLE_CLICKED, BUTTON2_TRIPLE_CLICKED }, + + { 3, ZCME_PRESSED, BUTTON3_PRESSED }, + { 3, ZCME_RELEASED, BUTTON3_RELEASED }, + { 3, ZCME_CLICKED, BUTTON3_CLICKED }, + { 3, ZCME_DOUBLE_CLICKED, BUTTON3_DOUBLE_CLICKED }, + { 3, ZCME_TRIPLE_CLICKED, BUTTON3_TRIPLE_CLICKED }, + + { 4, ZCME_PRESSED, BUTTON4_PRESSED }, + { 4, ZCME_RELEASED, BUTTON4_RELEASED }, + { 4, ZCME_CLICKED, BUTTON4_CLICKED }, + { 4, ZCME_DOUBLE_CLICKED, BUTTON4_DOUBLE_CLICKED }, + { 4, ZCME_TRIPLE_CLICKED, BUTTON4_TRIPLE_CLICKED }, + +#ifdef BUTTON5_PRESSED + /* Not defined if only 32 bits available */ + { 5, ZCME_PRESSED, BUTTON5_PRESSED }, + { 5, ZCME_RELEASED, BUTTON5_RELEASED }, + { 5, ZCME_CLICKED, BUTTON5_CLICKED }, + { 5, ZCME_DOUBLE_CLICKED, BUTTON5_DOUBLE_CLICKED }, + { 5, ZCME_TRIPLE_CLICKED, BUTTON5_TRIPLE_CLICKED }, +#endif + { 0, 0, 0 } +}; + +mmask_t zcurses_mouse_mask = ALL_MOUSE_EVENTS; + +#endif + /* Autogenerated keypad string/number mapping*/ #include "curses_keys.h" @@ -919,6 +989,7 @@ zccmd_input(const char *nam, char **args) ZCWin w; char *var; int keypadnum = -1; + int nargs = arrlen(args); #ifdef HAVE_WGET_WCH int ret; wint_t wi; @@ -936,12 +1007,37 @@ zccmd_input(const char *nam, char **args) w = (ZCWin)getdata(node); - if (args[1] && args[2]) { + if (nargs >= 3) { keypad(w->win, TRUE); } else { keypad(w->win, FALSE); } + if (nargs >= 4) { +#ifdef NCURSES_MOUSE_VERSION + if (!(zcurses_flags & ZCF_MOUSE_ACTIVE) || + (zcurses_flags & ZCF_MOUSE_MASK_CHANGED)) { + if (mousemask(zcurses_mouse_mask, NULL) == ERR) { + zwarnnam(nam, "current mouse mode is not supported"); + return 1; + } + zcurses_flags = (zcurses_flags & ~ZCF_MOUSE_MASK_CHANGED) | + ZCF_MOUSE_ACTIVE; + } +#else + zwarnnam(nam, "mouse events are not supported"); + return 1; +#endif + } +#ifdef NCURSES_MOUSE_VERSION + else { + if (zcurses_flags & ZCF_MOUSE_ACTIVE) { + mousemask((mmask_t)0, NULL); + zcurses_flags &= ~ZCF_MOUSE_ACTIVE; + } + } +#endif + #ifdef HAVE_WGET_WCH switch (wget_wch(w->win, &wi)) { case OK: @@ -988,32 +1084,97 @@ zccmd_input(const char *nam, char **args) var = "REPLY"; if (!setsparam(var, ztrdup(instr))) return 1; - if (args[1] && args[2]) { + if (nargs >= 3) { if (keypadnum > 0) { - const struct zcurses_namenumberpair *nnptr; - char fbuf[DIGBUFSIZE+1]; - - for (nnptr = keypad_names; nnptr->name; nnptr++) { - if (keypadnum == nnptr->number) { - if (!setsparam(args[2], ztrdup(nnptr->name))) - return 1; +#ifdef NCURSES_MOUSE_VERSION + if (nargs >= 4 && keypadnum == KEY_MOUSE) { + MEVENT mevent; + char digits[DIGBUFSIZE]; + LinkList margs; + const struct zcurses_mouse_event *zcmmp = zcurses_mouse_map; + + if (!setsparam(args[2], ztrdup("MOUSE"))) + return 1; + if (getmouse(&mevent) == ERR) { + /* + * This may happen if the mouse wasn't in + * the window, so set the array to empty + * but return success. + */ + setaparam(args[3], mkarray(NULL)); return 0; } - } - if (keypadnum > KEY_F0) { - /* assume it's a function key */ - sprintf(fbuf, "F%d", keypadnum - KEY_F0); + margs = newlinklist(); + sprintf(digits, "%d", (int)mevent.id); + addlinknode(margs, dupstring(digits)); + sprintf(digits, "%d", mevent.x); + addlinknode(margs, dupstring(digits)); + sprintf(digits, "%d", mevent.y); + addlinknode(margs, dupstring(digits)); + sprintf(digits, "%d", mevent.z); + addlinknode(margs, dupstring(digits)); + + /* + * We only expect one event, but it doesn't hurt + * to keep testing. + */ + for (; zcmmp->button; zcmmp++) { + if (mevent.bstate & zcmmp->event) { + const struct zcurses_namenumberpair *zcmelp = + zcurses_mouse_event_list; + for (; zcmelp->name; zcmelp++) { + if (zcmelp->number == zcmmp->what) { + char *evstr = zhalloc(strlen(zcmelp->name)+2); + sprintf(evstr, "%s%d", zcmelp->name, + zcmmp->button); + addlinknode(margs, evstr); + + break; + } + } + } + } + if (mevent.bstate & BUTTON_SHIFT) + addlinknode(margs, "SHIFT"); + if (mevent.bstate & BUTTON_CTRL) + addlinknode(margs, "CTRL"); + if (mevent.bstate & BUTTON_SHIFT) + addlinknode(margs, "ALT"); + if (!setaparam(args[3], zlinklist2array(margs))); + return 1; } else { - /* print raw number */ - sprintf(fbuf, "%d", keypadnum); +#endif + const struct zcurses_namenumberpair *nnptr; + char fbuf[DIGBUFSIZE+1]; + + for (nnptr = keypad_names; nnptr->name; nnptr++) { + if (keypadnum == nnptr->number) { + if (!setsparam(args[2], ztrdup(nnptr->name))) + return 1; + return 0; + } + } + if (keypadnum > KEY_F0) { + /* assume it's a function key */ + sprintf(fbuf, "F%d", keypadnum - KEY_F0); + } else { + /* print raw number */ + sprintf(fbuf, "%d", keypadnum); + } + if (!setsparam(args[2], ztrdup(fbuf))) + return 1; +#ifdef NCURSES_MOUSE_VERSION } - if (!setsparam(args[2], ztrdup(fbuf))) - return 1; +#endif } else { if (!setsparam(args[2], ztrdup(""))) return 1; } } +#ifdef NCURSES_MOUSE_VERSION + if (keypadnum != KEY_MOUSE && nargs >= 4) + setaparam(args[3], mkarray(NULL)); +#endif return 0; } @@ -1058,6 +1219,55 @@ zccmd_timeout(const char *nam, char **args) static int +zccmd_mouse(const char *nam, char **args) +{ +#ifdef NCURSES_MOUSE_VERSION + int ret = 0; + + for (; *args; args++) { + if (!strcmp(*args, "delay")) { + char *eptr; + zlong delay; + + if (!*++args || + ((delay = zstrtol(*args, &eptr, 10)), eptr != NULL)) { + zwarnnam(nam, "mouse delay requires an integer argument"); + return 1; + } + if (mouseinterval((int)delay) != OK) + ret = 1; + } else { + char *arg = *args; + int onoff = 1; + if (*arg == '+') + arg++; + else if (*arg == '-') { + arg++; + onoff = 0; + } + if (!strcmp(arg, "motion")) { + mmask_t old_mask = zcurses_mouse_mask; + if (onoff) + zcurses_mouse_mask |= REPORT_MOUSE_POSITION; + else + zcurses_mouse_mask &= ~REPORT_MOUSE_POSITION; + if (old_mask != zcurses_mouse_mask) + zcurses_flags |= ZCF_MOUSE_MASK_CHANGED; + } else { + zwarnnam(nam, "unrecognised mouse command: %s", *arg); + return 1; + } + } + } + + return ret; +#else + return 1; +#endif +} + + +static int zccmd_position(const char *nam, char **args) { LinkNode node; @@ -1141,8 +1351,9 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func)) {"attr", zccmd_attr, 2, -1}, {"bg", zccmd_bg, 2, -1}, {"scroll", zccmd_scroll, 2, 2}, - {"input", zccmd_input, 1, 3}, + {"input", zccmd_input, 1, 4}, {"timeout", zccmd_timeout, 2, 2}, + {"mouse", zccmd_mouse, 0, -1}, {"touch", zccmd_touch, 1, -1}, {NULL, (zccmd_t)0, 0, 0} }; @@ -1165,7 +1376,7 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func)) zwarnnam(nam, "too few arguments for subcommand: %s", args[0]); return 1; } else if (zcsc->maxargs >= 0 && num_args > zcsc->maxargs) { - zwarnnam(nam, "too may arguments for subcommand: %s", args[0]); + zwarnnam(nam, "too many arguments for subcommand: %s", args[0]); return 1; } |