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.
This commit is contained in:
Přemysl Eric Janouch 2014-11-19 02:41:36 +01:00
parent 5a80bceec9
commit 2d777dd67e
6 changed files with 104 additions and 79 deletions

View File

@ -165,7 +165,6 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
termo_set_mouse_proto (tk, termo_guess_mouse_proto (tk));
termo_set_mouse_tracking_mode (tk, TERMO_MOUSE_TRACKING_DRAG); termo_set_mouse_tracking_mode (tk, TERMO_MOUSE_TRACKING_DRAG);
// Set up curses for our drawing needs // Set up curses for our drawing needs

39
demo.c
View File

@ -5,6 +5,7 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <locale.h> #include <locale.h>
#include <strings.h>
#include "termo.h" #include "termo.h"
@ -14,31 +15,33 @@ main(int argc, char *argv[])
TERMO_CHECK_VERSION; TERMO_CHECK_VERSION;
setlocale (LC_CTYPE, ""); setlocale (LC_CTYPE, "");
int mouse = 0; termo_mouse_tracking_t mouse = TERMO_MOUSE_TRACKING_OFF;
int mouse_proto = 0;
termo_format_t format = TERMO_FORMAT_VIM; termo_format_t format = TERMO_FORMAT_VIM;
char buffer[50]; char buffer[50];
termo_t *tk; termo_t *tk;
int opt; int opt;
while ((opt = getopt (argc, argv, "m::p:")) != -1) while ((opt = getopt (argc, argv, "m::")) != -1)
{ {
switch (opt) switch (opt)
{ {
case 'm': case 'm':
if (optarg) if (!optarg)
mouse = atoi (optarg); mouse = TERMO_MOUSE_TRACKING_DRAG;
else else if (!strcasecmp (optarg, "off"))
mouse = 1000; mouse = TERMO_MOUSE_TRACKING_OFF;
break; else if (!strcasecmp (optarg, "click"))
mouse = TERMO_MOUSE_TRACKING_CLICK;
case 'p': else if (!strcasecmp (optarg, "drag"))
mouse_proto = atoi (optarg); mouse = TERMO_MOUSE_TRACKING_DRAG;
else if (!strcasecmp (optarg, "move"))
mouse = TERMO_MOUSE_TRACKING_MOVE;
break; break;
default: default:
fprintf (stderr, "Usage: %s [-m]\n", argv[0]); fprintf (stderr,
"Usage: %s [ -m [ off | click | drag | move ]]\n", argv[0]);
return 1; return 1;
} }
} }
@ -59,12 +62,9 @@ main(int argc, char *argv[])
termo_result_t ret; termo_result_t ret;
termo_key_t key; termo_key_t key;
if (mouse) termo_set_mouse_tracking_mode (tk, mouse);
{ if (mouse != TERMO_MOUSE_TRACKING_OFF)
printf ("\033[?%dhMouse mode active\n", mouse); printf ("Mouse mode active\n");
if (mouse_proto)
printf ("\033[?%dh", mouse_proto);
}
while ((ret = termo_waitkey (tk, &key)) != TERMO_RES_EOF) 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); termo_destroy (tk);
} }

View File

@ -58,7 +58,6 @@ typedef struct
char *start_string; char *start_string;
char *stop_string; char *stop_string;
bool have_mouse;
char *set_mouse_string; char *set_mouse_string;
} }
termo_ti_t; termo_ti_t;
@ -243,11 +242,12 @@ load_terminfo (termo_ti_t *ti, const char *term)
else else
ti->set_mouse_string = strdup (set_mouse_string); ti->set_mouse_string = strdup (set_mouse_string);
bool have_mouse = false;
if (!mouse_report_string && strstr (term, "xterm")) if (!mouse_report_string && strstr (term, "xterm"))
mouse_report_string = "\x1b[M"; mouse_report_string = "\x1b[M";
if (mouse_report_string) if (mouse_report_string)
{ {
ti->have_mouse = true; have_mouse = true;
trie_node_t *node = malloc (sizeof *node); trie_node_t *node = malloc (sizeof *node);
if (!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; ti->tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_NONE;
else if (strstr (term, "rxvt") == term) else if (strstr (term, "rxvt") == term)
// urxvt generally doesn't understand the SGR protocol. // 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. // are illegal in the current locale's charset.
ti->tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_SGR; 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 // Take copies of these terminfo strings, in case we build multiple termo
// instances for multiple different termtypes, and it's different by the // instances for multiple different termtypes, and it's different by the
// time we want to use it // 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 // Disable everything, a de-facto reset for all terminal mouse protocols
return set_mouse (ti, false) return set_mouse (ti, false)
&& write_string (ti->tk, "\E[?1002l") && write_string (ti->tk, "\x1b[?1002l")
&& write_string (ti->tk, "\E[?1003l") && write_string (ti->tk, "\x1b[?1003l")
&& write_string (ti->tk, "\E[?1005l") && write_string (ti->tk, "\x1b[?1005l")
&& write_string (ti->tk, "\E[?1006l") && write_string (ti->tk, "\x1b[?1006l")
&& write_string (ti->tk, "\E[?1015l"); && write_string (ti->tk, "\x1b[?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;
} }
static bool static bool
@ -375,10 +362,26 @@ mouse_set_tracking_mode (void *data,
termo_mouse_tracking_t tracking, bool enable) termo_mouse_tracking_t tracking, bool enable)
{ {
termo_ti_t *ti = data; termo_ti_t *ti = data;
if (tracking == TERMO_MOUSE_TRACKING_CLICK)
return set_mouse (ti, enable);
if (tracking == TERMO_MOUSE_TRACKING_DRAG) if (tracking == TERMO_MOUSE_TRACKING_DRAG)
return write_string (ti->tk, enable ? "\E[?1002h" : "\E[?1002l"); return write_string (ti->tk, enable ? "\x1b[?1002h" : "\x1b[?1002l");
if (tracking == TERMO_MOUSE_TRACKING_ANY) if (tracking == TERMO_MOUSE_TRACKING_MOVE)
return write_string (ti->tk, enable ? "\E[?1003h" : "\E[?1003l"); 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; return true;
} }
@ -386,10 +389,17 @@ static int
start_driver (termo_t *tk, void *info) start_driver (termo_t *tk, void *info)
{ {
termo_ti_t *ti = info; termo_ti_t *ti = info;
return write_string (tk, ti->start_string) if (!write_string (tk, ti->start_string))
&& ((!ti->have_mouse && tk->mouse_proto == TERMO_MOUSE_PROTO_NONE) return false;
|| mouse_reset (ti)) // We can never be sure
&& mouse_set_proto (ti, tk->mouse_proto, true) // 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); && mouse_set_tracking_mode (ti, tk->mouse_tracking, true);
} }
@ -397,8 +407,13 @@ static int
stop_driver (termo_t *tk, void *info) stop_driver (termo_t *tk, void *info)
{ {
termo_ti_t *ti = info; termo_ti_t *ti = info;
return write_string (tk, ti->stop_string) if (!write_string (tk, ti->stop_string))
&& mouse_set_proto (ti, tk->mouse_proto, false) 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); && mouse_set_tracking_mode (ti, tk->mouse_tracking, false);
} }

View File

@ -81,9 +81,12 @@ struct termo
} }
method; method;
int guessed_mouse_proto; // What we think should be the mouse protocol // What we think should be the mouse protocol
int mouse_proto; // The active mouse protocol termo_mouse_proto_t guessed_mouse_proto;
termo_mouse_tracking_t mouse_tracking; // Mouse tracking mode // 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 // The mouse unfortunately directly depends on the terminfo driver to let
// it handle changes in the mouse protocol. // it handle changes in the mouse protocol.
@ -92,7 +95,7 @@ struct termo
struct 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); bool (*set_mouse_tracking_mode) (void *, termo_mouse_tracking_t, bool);
} }
ti_method; ti_method;

27
termo.c
View File

@ -315,7 +315,7 @@ termo_alloc (void)
tk->method.peekkey_mouse = &peekkey_mouse; tk->method.peekkey_mouse = &peekkey_mouse;
tk->mouse_proto = TERMO_MOUSE_PROTO_NONE; 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->guessed_mouse_proto = TERMO_MOUSE_PROTO_NONE;
tk->ti_data = NULL; tk->ti_data = NULL;
@ -638,28 +638,35 @@ termo_get_buffer_remaining (termo_t *tk)
return tk->buffsize - tk->buffcount; return tk->buffsize - tk->buffcount;
} }
int termo_mouse_proto_t
termo_get_mouse_proto (termo_t *tk) termo_get_mouse_proto(termo_t *tk)
{ {
return tk->mouse_proto; return tk->mouse_proto;
} }
int termo_mouse_proto_t
termo_guess_mouse_proto (termo_t *tk) termo_guess_mouse_proto(termo_t *tk)
{ {
return tk->guessed_mouse_proto; return tk->guessed_mouse_proto;
} }
int 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; tk->mouse_proto = proto;
// Call the TI driver to apply the change if needed // 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) || !tk->ti_method.set_mouse_proto)
return true; 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) return tk->ti_method.set_mouse_proto (tk->ti_data, old_proto, false)
&& tk->ti_method.set_mouse_proto (tk->ti_data, proto, true); && 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; tk->mouse_tracking = mode;
// Call the TI driver to apply the change if needed // 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) || !tk->ti_method.set_mouse_tracking_mode)
return true; return true;
return tk->ti_method.set_mouse_tracking_mode (tk->ti_data, old_mode, false) 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); && tk->ti_method.set_mouse_tracking_mode (tk->ti_data, mode, true);
} }

24
termo.h
View File

@ -124,21 +124,23 @@ enum termo_mouse_event
// You will want to handle GPM (incompatible license) and FreeBSD's sysmouse // You will want to handle GPM (incompatible license) and FreeBSD's sysmouse
// yourself. http://www.monkey.org/openbsd/archive/tech/0009/msg00018.html // 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_NONE,
TERMO_MOUSE_PROTO_VT200 = 1 << 0, TERMO_MOUSE_PROTO_XTERM,
TERMO_MOUSE_PROTO_UTF8 = 1 << 1 | TERMO_MOUSE_PROTO_VT200, TERMO_MOUSE_PROTO_UTF8,
TERMO_MOUSE_PROTO_SGR = 1 << 2 | TERMO_MOUSE_PROTO_VT200, TERMO_MOUSE_PROTO_SGR,
TERMO_MOUSE_PROTO_RXVT = 1 << 3 | TERMO_MOUSE_PROTO_VT200 TERMO_MOUSE_PROTO_RXVT
}; };
typedef enum termo_mouse_tracking termo_mouse_tracking_t; typedef enum termo_mouse_tracking termo_mouse_tracking_t;
enum termo_mouse_tracking enum termo_mouse_tracking
{ {
TERMO_MOUSE_TRACKING_NORMAL, TERMO_MOUSE_TRACKING_OFF,
TERMO_MOUSE_TRACKING_CLICK,
TERMO_MOUSE_TRACKING_DRAG, TERMO_MOUSE_TRACKING_DRAG,
TERMO_MOUSE_TRACKING_ANY TERMO_MOUSE_TRACKING_MOVE
}; };
enum enum
@ -229,9 +231,9 @@ size_t termo_get_buffer_remaining (termo_t *tk);
void termo_canonicalise (termo_t *tk, termo_key_t *key); void termo_canonicalise (termo_t *tk, termo_key_t *key);
int termo_get_mouse_proto (termo_t *tk); termo_mouse_proto_t termo_get_mouse_proto (termo_t *tk);
int termo_set_mouse_proto (termo_t *tk, int proto); int termo_set_mouse_proto (termo_t *tk, termo_mouse_proto_t proto);
int termo_guess_mouse_proto (termo_t *tk); termo_mouse_proto_t termo_guess_mouse_proto (termo_t *tk);
termo_mouse_tracking_t termo_get_mouse_tracking_mode (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); int termo_set_mouse_tracking_mode (termo_t *tk, termo_mouse_tracking_t mode);