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,28 +349,12 @@ 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"); -} - -static bool -mouse_set_proto (void *data, int proto, 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; + && write_string (ti->tk, "\x1b[?1005l") + && write_string (ti->tk, "\x1b[?1006l") + && write_string (ti->tk, "\x1b[?1015l"); } static bool @@ -375,10 +362,26 @@ mouse_set_tracking_mode (void *data, termo_mouse_tracking_t tracking, bool enable) { termo_ti_t *ti = data; + if (tracking == TERMO_MOUSE_TRACKING_CLICK) + return set_mouse (ti, enable); 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"); + 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_proto (void *data, termo_mouse_proto_t proto, bool enable) +{ + termo_ti_t *ti = data; + // 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);