From 2d777dd67e9be3c5bfd36660ade94710de0f4a0d Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Wed, 19 Nov 2014 02:41:36 +0100 Subject: Rewrite the mouse API I wasn't aware of the fact that 1000, 1002 and 1003 are mutually exclusive and turn each other off. Also now it's not needed to set the protocol, it gets set by default. --- demo-draw.c | 1 - demo.c | 39 +++++++++++++--------------- driver-ti.c | 77 +++++++++++++++++++++++++++++++++----------------------- termo-internal.h | 11 +++++--- termo.c | 27 +++++++++++++------- termo.h | 24 ++++++++++-------- 6 files changed, 102 insertions(+), 77 deletions(-) diff --git a/demo-draw.c b/demo-draw.c index 10cbe3b..26b583f 100644 --- a/demo-draw.c +++ b/demo-draw.c @@ -165,7 +165,6 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } - termo_set_mouse_proto (tk, termo_guess_mouse_proto (tk)); termo_set_mouse_tracking_mode (tk, TERMO_MOUSE_TRACKING_DRAG); // Set up curses for our drawing needs diff --git a/demo.c b/demo.c index d74892c..bc416c0 100644 --- a/demo.c +++ b/demo.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "termo.h" @@ -14,31 +15,33 @@ main(int argc, char *argv[]) TERMO_CHECK_VERSION; setlocale (LC_CTYPE, ""); - int mouse = 0; - int mouse_proto = 0; + termo_mouse_tracking_t mouse = TERMO_MOUSE_TRACKING_OFF; termo_format_t format = TERMO_FORMAT_VIM; char buffer[50]; termo_t *tk; int opt; - while ((opt = getopt (argc, argv, "m::p:")) != -1) + while ((opt = getopt (argc, argv, "m::")) != -1) { switch (opt) { case 'm': - if (optarg) - mouse = atoi (optarg); - else - mouse = 1000; - break; - - case 'p': - mouse_proto = atoi (optarg); + if (!optarg) + mouse = TERMO_MOUSE_TRACKING_DRAG; + else if (!strcasecmp (optarg, "off")) + mouse = TERMO_MOUSE_TRACKING_OFF; + else if (!strcasecmp (optarg, "click")) + mouse = TERMO_MOUSE_TRACKING_CLICK; + else if (!strcasecmp (optarg, "drag")) + mouse = TERMO_MOUSE_TRACKING_DRAG; + else if (!strcasecmp (optarg, "move")) + mouse = TERMO_MOUSE_TRACKING_MOVE; break; default: - fprintf (stderr, "Usage: %s [-m]\n", argv[0]); + fprintf (stderr, + "Usage: %s [ -m [ off | click | drag | move ]]\n", argv[0]); return 1; } } @@ -59,12 +62,9 @@ main(int argc, char *argv[]) termo_result_t ret; termo_key_t key; - if (mouse) - { - printf ("\033[?%dhMouse mode active\n", mouse); - if (mouse_proto) - printf ("\033[?%dh", mouse_proto); - } + termo_set_mouse_tracking_mode (tk, mouse); + if (mouse != TERMO_MOUSE_TRACKING_OFF) + printf ("Mouse mode active\n"); while ((ret = termo_waitkey (tk, &key)) != TERMO_RES_EOF) { @@ -130,8 +130,5 @@ main(int argc, char *argv[]) } } - if (mouse) - printf ("\033[?%dlMouse mode deactivated\n", mouse); - termo_destroy (tk); } diff --git a/driver-ti.c b/driver-ti.c index e31de47..6ac213f 100644 --- a/driver-ti.c +++ b/driver-ti.c @@ -58,7 +58,6 @@ typedef struct char *start_string; char *stop_string; - bool have_mouse; char *set_mouse_string; } termo_ti_t; @@ -243,11 +242,12 @@ load_terminfo (termo_ti_t *ti, const char *term) else ti->set_mouse_string = strdup (set_mouse_string); + bool have_mouse = false; if (!mouse_report_string && strstr (term, "xterm")) mouse_report_string = "\x1b[M"; if (mouse_report_string) { - ti->have_mouse = true; + have_mouse = true; trie_node_t *node = malloc (sizeof *node); if (!node) @@ -261,7 +261,7 @@ load_terminfo (termo_ti_t *ti, const char *term) } } - if (!ti->have_mouse) + if (!have_mouse) ti->tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_NONE; else if (strstr (term, "rxvt") == term) // urxvt generally doesn't understand the SGR protocol. @@ -276,6 +276,9 @@ load_terminfo (termo_ti_t *ti, const char *term) // are illegal in the current locale's charset. ti->tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_SGR; + // Preset the active protocol to our wild guess + ti->tk->mouse_proto = ti->tk->guessed_mouse_proto; + // Take copies of these terminfo strings, in case we build multiple termo // instances for multiple different termtypes, and it's different by the // time we want to use it @@ -346,39 +349,39 @@ mouse_reset (termo_ti_t *ti) { // Disable everything, a de-facto reset for all terminal mouse protocols return set_mouse (ti, false) - && write_string (ti->tk, "\E[?1002l") - && write_string (ti->tk, "\E[?1003l") + && write_string (ti->tk, "\x1b[?1002l") + && write_string (ti->tk, "\x1b[?1003l") - && write_string (ti->tk, "\E[?1005l") - && write_string (ti->tk, "\E[?1006l") - && write_string (ti->tk, "\E[?1015l"); + && write_string (ti->tk, "\x1b[?1005l") + && write_string (ti->tk, "\x1b[?1006l") + && write_string (ti->tk, "\x1b[?1015l"); } static bool -mouse_set_proto (void *data, int proto, bool enable) +mouse_set_tracking_mode (void *data, + termo_mouse_tracking_t tracking, bool enable) { termo_ti_t *ti = data; - bool success = true; - if (proto & TERMO_MOUSE_PROTO_VT200) - success &= set_mouse (ti, enable); - if (proto & TERMO_MOUSE_PROTO_UTF8) - success &= write_string (ti->tk, enable ? "\E[?1005h" : "\E[?1005l"); - if (proto & TERMO_MOUSE_PROTO_SGR) - success &= write_string (ti->tk, enable ? "\E[?1006h" : "\E[?1006l"); - if (proto & TERMO_MOUSE_PROTO_RXVT) - success &= write_string (ti->tk, enable ? "\E[?1015h" : "\E[?1015l"); - return success; + if (tracking == TERMO_MOUSE_TRACKING_CLICK) + return set_mouse (ti, enable); + if (tracking == TERMO_MOUSE_TRACKING_DRAG) + return write_string (ti->tk, enable ? "\x1b[?1002h" : "\x1b[?1002l"); + if (tracking == TERMO_MOUSE_TRACKING_MOVE) + return write_string (ti->tk, enable ? "\x1b[?1003h" : "\x1b[?1003l"); + return true; } static bool -mouse_set_tracking_mode (void *data, - termo_mouse_tracking_t tracking, bool enable) +mouse_set_proto (void *data, termo_mouse_proto_t proto, bool enable) { termo_ti_t *ti = data; - if (tracking == TERMO_MOUSE_TRACKING_DRAG) - return write_string (ti->tk, enable ? "\E[?1002h" : "\E[?1002l"); - if (tracking == TERMO_MOUSE_TRACKING_ANY) - return write_string (ti->tk, enable ? "\E[?1003h" : "\E[?1003l"); + // TERMO_MOUSE_PROTO_XTERM is ignored here; it is the default protocol + if (proto == TERMO_MOUSE_PROTO_UTF8) + return write_string (ti->tk, enable ? "\x1b[?1005h" : "\x1b[?1005l"); + if (proto == TERMO_MOUSE_PROTO_SGR) + return write_string (ti->tk, enable ? "\x1b[?1006h" : "\x1b[?1006l"); + if (proto == TERMO_MOUSE_PROTO_RXVT) + return write_string (ti->tk, enable ? "\x1b[?1015h" : "\x1b[?1015l"); return true; } @@ -386,10 +389,17 @@ static int start_driver (termo_t *tk, void *info) { termo_ti_t *ti = info; - return write_string (tk, ti->start_string) - && ((!ti->have_mouse && tk->mouse_proto == TERMO_MOUSE_PROTO_NONE) - || mouse_reset (ti)) // We can never be sure - && mouse_set_proto (ti, tk->mouse_proto, true) + if (!write_string (tk, ti->start_string)) + return false; + + // If there's no protocol, it doesn't make sense to try anything else + if (tk->mouse_proto == TERMO_MOUSE_PROTO_NONE) + return true; + + // Disable everything mouse-related first + if (!mouse_reset (ti)) + return false; + return mouse_set_proto (ti, tk->mouse_proto, true) && mouse_set_tracking_mode (ti, tk->mouse_tracking, true); } @@ -397,8 +407,13 @@ static int stop_driver (termo_t *tk, void *info) { termo_ti_t *ti = info; - return write_string (tk, ti->stop_string) - && mouse_set_proto (ti, tk->mouse_proto, false) + if (!write_string (tk, ti->stop_string)) + return false; + + // If there's no protocol, it doesn't make sense to try anything else + if (tk->mouse_proto == TERMO_MOUSE_PROTO_NONE) + return true; + return mouse_set_proto (ti, tk->mouse_proto, false) && mouse_set_tracking_mode (ti, tk->mouse_tracking, false); } diff --git a/termo-internal.h b/termo-internal.h index b2b1c3a..adf3e8f 100644 --- a/termo-internal.h +++ b/termo-internal.h @@ -81,9 +81,12 @@ struct termo } method; - int guessed_mouse_proto; // What we think should be the mouse protocol - int mouse_proto; // The active mouse protocol - termo_mouse_tracking_t mouse_tracking; // Mouse tracking mode + // What we think should be the mouse protocol + termo_mouse_proto_t guessed_mouse_proto; + // The active mouse protocol + termo_mouse_proto_t mouse_proto; + // Mouse tracking mode + termo_mouse_tracking_t mouse_tracking; // The mouse unfortunately directly depends on the terminfo driver to let // it handle changes in the mouse protocol. @@ -92,7 +95,7 @@ struct termo struct { - bool (*set_mouse_proto) (void *, int, bool); + bool (*set_mouse_proto) (void *, termo_mouse_proto_t, bool); bool (*set_mouse_tracking_mode) (void *, termo_mouse_tracking_t, bool); } ti_method; diff --git a/termo.c b/termo.c index 063a5a7..e88e74d 100644 --- a/termo.c +++ b/termo.c @@ -315,7 +315,7 @@ termo_alloc (void) tk->method.peekkey_mouse = &peekkey_mouse; tk->mouse_proto = TERMO_MOUSE_PROTO_NONE; - tk->mouse_tracking = TERMO_MOUSE_TRACKING_NORMAL; + tk->mouse_tracking = TERMO_MOUSE_TRACKING_CLICK; tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_NONE; tk->ti_data = NULL; @@ -638,28 +638,35 @@ termo_get_buffer_remaining (termo_t *tk) return tk->buffsize - tk->buffcount; } -int -termo_get_mouse_proto (termo_t *tk) +termo_mouse_proto_t +termo_get_mouse_proto(termo_t *tk) { return tk->mouse_proto; } -int -termo_guess_mouse_proto (termo_t *tk) +termo_mouse_proto_t +termo_guess_mouse_proto(termo_t *tk) { return tk->guessed_mouse_proto; } int -termo_set_mouse_proto (termo_t *tk, int proto) +termo_set_mouse_proto (termo_t *tk, termo_mouse_proto_t proto) { - int old_proto = tk->mouse_proto; + termo_mouse_proto_t old_proto = tk->mouse_proto; tk->mouse_proto = proto; // Call the TI driver to apply the change if needed - if (!tk->is_started + if (proto == old_proto + || !tk->is_started || !tk->ti_method.set_mouse_proto) return true; + + // Unsetting the protocol disables tracking; this is a bit hackish + if (!tk->ti_method.set_mouse_tracking_mode (tk->ti_data, + tk->mouse_tracking, proto != TERMO_MOUSE_PROTO_NONE)) + return false; + return tk->ti_method.set_mouse_proto (tk->ti_data, old_proto, false) && tk->ti_method.set_mouse_proto (tk->ti_data, proto, true); } @@ -677,9 +684,11 @@ termo_set_mouse_tracking_mode (termo_t *tk, termo_mouse_tracking_t mode) tk->mouse_tracking = mode; // Call the TI driver to apply the change if needed - if (!tk->is_started + if (mode == old_mode + || !tk->is_started || !tk->ti_method.set_mouse_tracking_mode) return true; + return tk->ti_method.set_mouse_tracking_mode (tk->ti_data, old_mode, false) && tk->ti_method.set_mouse_tracking_mode (tk->ti_data, mode, true); } diff --git a/termo.h b/termo.h index f6a82b1..9df3e73 100644 --- a/termo.h +++ b/termo.h @@ -124,21 +124,23 @@ enum termo_mouse_event // You will want to handle GPM (incompatible license) and FreeBSD's sysmouse // yourself. http://www.monkey.org/openbsd/archive/tech/0009/msg00018.html -enum +typedef enum termo_mouse_proto termo_mouse_proto_t; +enum termo_mouse_proto { - TERMO_MOUSE_PROTO_NONE = 0, - TERMO_MOUSE_PROTO_VT200 = 1 << 0, - TERMO_MOUSE_PROTO_UTF8 = 1 << 1 | TERMO_MOUSE_PROTO_VT200, - TERMO_MOUSE_PROTO_SGR = 1 << 2 | TERMO_MOUSE_PROTO_VT200, - TERMO_MOUSE_PROTO_RXVT = 1 << 3 | TERMO_MOUSE_PROTO_VT200 + TERMO_MOUSE_PROTO_NONE, + TERMO_MOUSE_PROTO_XTERM, + TERMO_MOUSE_PROTO_UTF8, + TERMO_MOUSE_PROTO_SGR, + TERMO_MOUSE_PROTO_RXVT }; typedef enum termo_mouse_tracking termo_mouse_tracking_t; enum termo_mouse_tracking { - TERMO_MOUSE_TRACKING_NORMAL, + TERMO_MOUSE_TRACKING_OFF, + TERMO_MOUSE_TRACKING_CLICK, TERMO_MOUSE_TRACKING_DRAG, - TERMO_MOUSE_TRACKING_ANY + TERMO_MOUSE_TRACKING_MOVE }; enum @@ -229,9 +231,9 @@ size_t termo_get_buffer_remaining (termo_t *tk); void termo_canonicalise (termo_t *tk, termo_key_t *key); -int termo_get_mouse_proto (termo_t *tk); -int termo_set_mouse_proto (termo_t *tk, int proto); -int termo_guess_mouse_proto (termo_t *tk); +termo_mouse_proto_t termo_get_mouse_proto (termo_t *tk); +int termo_set_mouse_proto (termo_t *tk, termo_mouse_proto_t proto); +termo_mouse_proto_t termo_guess_mouse_proto (termo_t *tk); termo_mouse_tracking_t termo_get_mouse_tracking_mode (termo_t *tk); int termo_set_mouse_tracking_mode (termo_t *tk, termo_mouse_tracking_t mode); -- cgit v1.2.3-70-g09d2