Add support for setting the mouse protocol
This commit is contained in:
parent
70bcfde021
commit
f1f9a00cda
136
driver-ti.c
136
driver-ti.c
|
@ -1,4 +1,4 @@
|
||||||
// we want strdup()
|
// We want strdup()
|
||||||
#define _XOPEN_SOURCE 600
|
#define _XOPEN_SOURCE 600
|
||||||
|
|
||||||
#include "termo.h"
|
#include "termo.h"
|
||||||
|
@ -261,6 +261,21 @@ load_terminfo (termo_ti_t *ti, const char *term)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ti->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.
|
||||||
|
ti->tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_RXVT;
|
||||||
|
else
|
||||||
|
// SGR (1006) is the superior protocol. If it's not supported by the
|
||||||
|
// terminal, nothing much happens and we continue getting events via
|
||||||
|
// the original protocol (1000). We can't afford to enable the UTF-8
|
||||||
|
// protocol (1005) because it collides with the original (1000) and we
|
||||||
|
// have no way of knowing if it's supported by the terminal. Also both
|
||||||
|
// 1000 and 1005 are broken in that they may produce characters that
|
||||||
|
// are illegal in the current locale's charset.
|
||||||
|
ti->tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_SGR;
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -289,32 +304,6 @@ load_terminfo (termo_ti_t *ti, const char *term)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
|
||||||
new_driver (termo_t *tk, const char *term)
|
|
||||||
{
|
|
||||||
termo_ti_t *ti = calloc (1, sizeof *ti);
|
|
||||||
if (!ti)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ti->tk = tk;
|
|
||||||
ti->root = new_node_arr (0, 0xff);
|
|
||||||
if (!ti->root)
|
|
||||||
goto abort_free_ti;
|
|
||||||
|
|
||||||
if (!load_terminfo (ti, term))
|
|
||||||
goto abort_free_trie;
|
|
||||||
|
|
||||||
ti->root = compress_trie (ti->root);
|
|
||||||
return ti;
|
|
||||||
|
|
||||||
abort_free_trie:
|
|
||||||
free_trie (ti->root);
|
|
||||||
|
|
||||||
abort_free_ti:
|
|
||||||
free (ti);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
write_string (termo_t *tk, char *string)
|
write_string (termo_t *tk, char *string)
|
||||||
{
|
{
|
||||||
|
@ -352,32 +341,105 @@ set_mouse (termo_ti_t *ti, bool enable)
|
||||||
return write_string (ti->tk, start_string);
|
return write_string (ti->tk, start_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
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, "\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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mouse_set_tracking_mode (void *data,
|
||||||
|
termo_mouse_tracking_t tracking, 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");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
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;
|
||||||
// TODO: Don't start the mouse automatically, find a nice place to put
|
return write_string (tk, ti->start_string)
|
||||||
// a public function to be called by users.
|
&& ((!ti->have_mouse && tk->mouse_proto == TERMO_MOUSE_PROTO_NONE)
|
||||||
// TODO: Try to autodetect rxvt and use its protocol instead of mode 1000
|
|| mouse_reset (ti)) // We can never be sure
|
||||||
// TODO: Also give the user a choice to use 1005, 1006 or 1015
|
&& mouse_set_proto (ti, tk->mouse_proto, true)
|
||||||
if (ti->have_mouse && !set_mouse (ti, true))
|
&& mouse_set_tracking_mode (ti, tk->mouse_tracking, true);
|
||||||
return false;
|
|
||||||
return write_string (tk, ti->start_string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
||||||
if (ti->have_mouse && !set_mouse (ti, false))
|
return write_string (tk, ti->stop_string)
|
||||||
return false;
|
&& mouse_set_proto (ti, tk->mouse_proto, false)
|
||||||
return write_string (tk, ti->stop_string);
|
&& mouse_set_tracking_mode (ti, tk->mouse_tracking, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
new_driver (termo_t *tk, const char *term)
|
||||||
|
{
|
||||||
|
termo_ti_t *ti = calloc (1, sizeof *ti);
|
||||||
|
if (!ti)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ti->tk = tk;
|
||||||
|
ti->root = new_node_arr (0, 0xff);
|
||||||
|
if (!ti->root)
|
||||||
|
goto abort_free_ti;
|
||||||
|
|
||||||
|
if (!load_terminfo (ti, term))
|
||||||
|
goto abort_free_trie;
|
||||||
|
|
||||||
|
ti->root = compress_trie (ti->root);
|
||||||
|
|
||||||
|
tk->ti_data = ti;
|
||||||
|
tk->ti_method.set_mouse_proto = mouse_set_proto;
|
||||||
|
tk->ti_method.set_mouse_tracking_mode = mouse_set_tracking_mode;
|
||||||
|
return ti;
|
||||||
|
|
||||||
|
abort_free_trie:
|
||||||
|
free_trie (ti->root);
|
||||||
|
|
||||||
|
abort_free_ti:
|
||||||
|
free (ti);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_driver (void *info)
|
free_driver (void *info)
|
||||||
{
|
{
|
||||||
termo_ti_t *ti = info;
|
termo_ti_t *ti = info;
|
||||||
|
ti->tk->ti_data = NULL;
|
||||||
|
ti->tk->ti_method.set_mouse_proto = NULL;
|
||||||
|
ti->tk->ti_method.set_mouse_tracking_mode = NULL;
|
||||||
|
|
||||||
free_trie (ti->root);
|
free_trie (ti->root);
|
||||||
free (ti->set_mouse_string);
|
free (ti->set_mouse_string);
|
||||||
free (ti->start_string);
|
free (ti->start_string);
|
||||||
|
|
|
@ -80,6 +80,22 @@ struct termo
|
||||||
termo_key_t *key, size_t *nbytes);
|
termo_key_t *key, size_t *nbytes);
|
||||||
}
|
}
|
||||||
method;
|
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
|
||||||
|
|
||||||
|
// The mouse unfortunately directly depends on the terminfo driver to let
|
||||||
|
// it handle changes in the mouse protocol.
|
||||||
|
|
||||||
|
void *ti_data; // termo_ti_t pointer
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
bool (*set_mouse_proto) (void *, int, bool);
|
||||||
|
bool (*set_mouse_tracking_mode) (void *, termo_mouse_tracking_t, bool);
|
||||||
|
}
|
||||||
|
ti_method;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
54
termo.c
54
termo.c
|
@ -313,6 +313,14 @@ termo_alloc (void)
|
||||||
tk->method.emit_codepoint = &emit_codepoint;
|
tk->method.emit_codepoint = &emit_codepoint;
|
||||||
tk->method.peekkey_simple = &peekkey_simple;
|
tk->method.peekkey_simple = &peekkey_simple;
|
||||||
tk->method.peekkey_mouse = &peekkey_mouse;
|
tk->method.peekkey_mouse = &peekkey_mouse;
|
||||||
|
|
||||||
|
tk->mouse_proto = TERMO_MOUSE_PROTO_NONE;
|
||||||
|
tk->mouse_tracking = TERMO_MOUSE_TRACKING_NORMAL;
|
||||||
|
tk->guessed_mouse_proto = TERMO_MOUSE_PROTO_NONE;
|
||||||
|
|
||||||
|
tk->ti_data = NULL;
|
||||||
|
tk->ti_method.set_mouse_proto = NULL;
|
||||||
|
tk->ti_method.set_mouse_tracking_mode = NULL;
|
||||||
return tk;
|
return tk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,6 +633,52 @@ termo_get_buffer_remaining (termo_t *tk)
|
||||||
return tk->buffsize - tk->buffcount;
|
return tk->buffsize - tk->buffcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
termo_get_mouse_proto (termo_t *tk)
|
||||||
|
{
|
||||||
|
return tk->mouse_proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
termo_guess_mouse_proto (termo_t *tk)
|
||||||
|
{
|
||||||
|
return tk->guessed_mouse_proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
termo_set_mouse_proto (termo_t *tk, int proto)
|
||||||
|
{
|
||||||
|
int old_proto = tk->mouse_proto;
|
||||||
|
tk->mouse_proto = proto;
|
||||||
|
|
||||||
|
// Call the TI driver to apply the change if needed
|
||||||
|
if (!tk->is_started
|
||||||
|
|| !tk->ti_method.set_mouse_proto)
|
||||||
|
return true;
|
||||||
|
return tk->ti_method.set_mouse_proto (tk->ti_data, old_proto, false)
|
||||||
|
&& tk->ti_method.set_mouse_proto (tk->ti_data, proto, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
termo_mouse_tracking_t
|
||||||
|
termo_get_mouse_tracking_mode (termo_t *tk)
|
||||||
|
{
|
||||||
|
return tk->mouse_tracking;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
termo_set_mouse_tracking_mode (termo_t *tk, termo_mouse_tracking_t mode)
|
||||||
|
{
|
||||||
|
termo_mouse_tracking_t old_mode = tk->mouse_tracking;
|
||||||
|
tk->mouse_tracking = mode;
|
||||||
|
|
||||||
|
// Call the TI driver to apply the change if needed
|
||||||
|
if (!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);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
eat_bytes (termo_t *tk, size_t count)
|
eat_bytes (termo_t *tk, size_t count)
|
||||||
{
|
{
|
||||||
|
|
27
termo.h
27
termo.h
|
@ -121,6 +121,26 @@ enum termo_mouse_event
|
||||||
TERMO_MOUSE_RELEASE
|
TERMO_MOUSE_RELEASE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// You will want to handle GPM (incompatible license) and FreeBSD's sysmouse
|
||||||
|
// yourself. http://www.monkey.org/openbsd/archive/tech/0009/msg00018.html
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum termo_mouse_tracking termo_mouse_tracking_t;
|
||||||
|
enum termo_mouse_tracking
|
||||||
|
{
|
||||||
|
TERMO_MOUSE_TRACKING_NORMAL,
|
||||||
|
TERMO_MOUSE_TRACKING_DRAG,
|
||||||
|
TERMO_MOUSE_TRACKING_ANY
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
TERMO_KEYMOD_SHIFT = 1 << 0,
|
TERMO_KEYMOD_SHIFT = 1 << 0,
|
||||||
|
@ -209,6 +229,13 @@ 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);
|
||||||
|
int termo_set_mouse_proto (termo_t *tk, int proto);
|
||||||
|
int 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);
|
||||||
|
|
||||||
termo_result_t termo_getkey (termo_t *tk, termo_key_t *key);
|
termo_result_t termo_getkey (termo_t *tk, termo_key_t *key);
|
||||||
termo_result_t termo_getkey_force (termo_t *tk, termo_key_t *key);
|
termo_result_t termo_getkey_force (termo_t *tk, termo_key_t *key);
|
||||||
termo_result_t termo_waitkey (termo_t *tk, termo_key_t *key);
|
termo_result_t termo_waitkey (termo_t *tk, termo_key_t *key);
|
||||||
|
|
Loading…
Reference in New Issue