about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/curses.c249
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;
     }