Work on mouse support, it's a mess

This commit is contained in:
Přemysl Eric Janouch 2014-10-13 01:03:13 +02:00
parent 5692f32bcf
commit 456093e4ed
4 changed files with 93 additions and 51 deletions

View File

@ -196,7 +196,7 @@ handle_csi_u (termkey_t *tk, termkey_key_t *key, int cmd, long *arg, int args)
} }
/* /*
* Handler for CSI M / CSI m mouse events in SRG and rxvt encodings * Handler for CSI M / CSI m mouse events in SGR and rxvt encodings
* Note: This does not handle X10 encoding * Note: This does not handle X10 encoding
*/ */
@ -262,6 +262,7 @@ termkey_interpret_mouse (termkey_t *tk, const termkey_key_t *key,
termkey_key_get_linecol (key, line, col); termkey_key_get_linecol (key, line, col);
// XXX: WTF is this logic?
if (!event) if (!event)
return TERMKEY_RES_KEY; return TERMKEY_RES_KEY;

View File

@ -58,6 +58,9 @@ typedef struct
char *start_string; char *start_string;
char *stop_string; char *stop_string;
bool have_mouse;
char *set_mouse_string;
} }
termkey_ti_t; termkey_ti_t;
@ -172,56 +175,41 @@ compress_trie (struct trie_node *n)
return n; return n;
} }
static int static bool
load_terminfo (termkey_ti_t *ti, const char *term) load_terminfo (termkey_ti_t *ti, const char *term)
{ {
int i; const char *mouse_report_string = NULL;
#ifdef HAVE_UNIBILIUM #ifdef HAVE_UNIBILIUM
unibi_term *unibi = unibi_from_term (term); unibi_term *unibi = unibi_from_term (term);
if (!unibi) if (!unibi)
return 0; return false;
#else
int err;
/* Have to cast away the const. But it's OK - we know terminfo won't for (int i = unibi_string_begin_ + 1; i < unibi_string_end_; i++)
* really modify term */
if (setupterm ((char *) term, 1, &err) != OK)
return 0;
#endif
#ifdef HAVE_UNIBILIUM
for (i = unibi_string_begin_ + 1; i < unibi_string_end_; i++)
#else
for (i = 0; strfnames[i]; i++)
#endif
{ {
// Only care about the key_* constants
#ifdef HAVE_UNIBILIUM
const char *name = unibi_name_str (i); const char *name = unibi_name_str (i);
#else
const char *name = strfnames[i];
#endif
if (strncmp (name, "key_", 4) != 0)
continue;
#ifdef HAVE_UNIBILIUM
const char *value = unibi_get_str (unibi, i); const char *value = unibi_get_str (unibi, i);
#else #else
/* Have to cast away the const. But it's OK - we know terminfo won't
* really modify term */
int err;
if (setupterm ((char *) term, 1, &err) != OK)
return false;
for (int i = 0; strfnames[i]; i++)
{
const char *name = strfnames[i];
const char *value = tigetstr (strnames[i]); const char *value = tigetstr (strnames[i]);
#endif #endif
// Only care about the key_* constants
if (strncmp (name, "key_", 4) != 0)
continue;
if (!value || value == (char*) -1) if (!value || value == (char*) -1)
continue; continue;
struct trie_node *node = NULL; trie_node_t *node = NULL;
if (strcmp (name + 4, "mouse") == 0) if (!strcmp (name + 4, "mouse"))
{ mouse_report_string = value;
node = malloc (sizeof *node);
if (!node)
return 0;
node->type = TYPE_MOUSE;
}
else else
{ {
termkey_type_t type; termkey_type_t type;
@ -241,7 +229,36 @@ load_terminfo (termkey_ti_t *ti, const char *term)
if (node && !insert_seq (ti, value, node)) if (node && !insert_seq (ti, value, node))
{ {
free (node); free (node);
return 0; return false;
}
}
// Clone the behaviour of ncurses for xterm mouse support
#ifdef HAVE_UNIBILIUM
const char *set_mouse_string = unibi_get_str (unibi, "XM");
#else
const char *set_mouse_string = tigetstr ("XM");
#endif
if (!set_mouse_string || set_mouse_string == (char *) -1)
ti->set_mouse_string = strdup ("\E[?1000%?%p1%{1}%=%th%el%;");
else
ti->set_mouse_string = strdup (set_mouse_string);
if (!mouse_report_string && strstr (term, "xterm"))
mouse_report_string = "\x1b[M";
if (mouse_report_string)
{
ti->have_mouse = true;
trie_node_t *node = malloc (sizeof *node);
if (!node)
return false;
node->type = TYPE_MOUSE;
if (!insert_seq (ti, mouse_report_string, node))
{
free (node);
return false;
} }
} }
@ -271,13 +288,13 @@ load_terminfo (termkey_ti_t *ti, const char *term)
unibi_destroy (unibi); unibi_destroy (unibi);
#endif #endif
return 1; return true;
} }
static void * static void *
new_driver (termkey_t *tk, const char *term) new_driver (termkey_t *tk, const char *term)
{ {
termkey_ti_t *ti = malloc (sizeof *ti); termkey_ti_t *ti = calloc (1, sizeof *ti);
if (!ti) if (!ti)
return NULL; return NULL;
@ -300,15 +317,14 @@ abort_free_ti:
return NULL; return NULL;
} }
static int static bool
write_string (termkey_t *tk, char *string) write_string (termkey_t *tk, char *string)
{ {
if (tk->fd == -1 || !isatty (tk->fd) || !string) if (tk->fd == -1 || !isatty (tk->fd) || !string)
return 1; return true;
/* The terminfo database will contain keys in application cursor key mode. // The terminfo database will contain keys in application cursor key mode.
* We may need to enable that mode // We may need to enable that mode
*/
// Can't call putp or tputs because they suck and don't give us fd control // Can't call putp or tputs because they suck and don't give us fd control
size_t len = strlen (string); size_t len = strlen (string);
@ -316,17 +332,38 @@ write_string (termkey_t *tk, char *string)
{ {
ssize_t written = write (tk->fd, string, len); ssize_t written = write (tk->fd, string, len);
if (written == -1) if (written == -1)
return 0; return false;
string += written; string += written;
len -= written; len -= written;
} }
return 1; return true;
}
static bool
set_mouse (termkey_ti_t *ti, bool enable)
{
#ifdef HAVE_UNIBILIUM
unibi_var_t params[9] = { enable, 0, 0, 0, 0, 0, 0, 0, 0 };
char start_string[unibi_run (ti->set_mouse_string, params, NULL, 0)];
unibi_run (ti->set_mouse_string, params,
start_string, sizeof start_string);
#else
char *start_string = tparm (ti->set_mouse_string,
enable, 0, 0, 0, 0, 0, 0, 0, 0);
#endif
return write_string (ti->tk, start_string);
} }
static int static int
start_driver (termkey_t *tk, void *info) start_driver (termkey_t *tk, void *info)
{ {
termkey_ti_t *ti = info; termkey_ti_t *ti = info;
// TODO: Don't start the mouse automatically, find a nice place to put
// a public function to be called by users.
// TODO: Try to autodetect rxvt and use its protocol instead of mode 1000
// TODO: Also give the user a choice to use 1005, 1006 or 1015
if (ti->have_mouse && !set_mouse (ti, true))
return false;
return write_string (tk, ti->start_string); return write_string (tk, ti->start_string);
} }
@ -334,6 +371,8 @@ static int
stop_driver (termkey_t *tk, void *info) stop_driver (termkey_t *tk, void *info)
{ {
termkey_ti_t *ti = info; termkey_ti_t *ti = info;
if (ti->have_mouse && !set_mouse (ti, false))
return false;
return write_string (tk, ti->stop_string); return write_string (tk, ti->stop_string);
} }
@ -342,6 +381,7 @@ free_driver (void *info)
{ {
termkey_ti_t *ti = info; termkey_ti_t *ti = info;
free_trie (ti->root); free_trie (ti->root);
free (ti->set_mouse_string);
free (ti->start_string); free (ti->start_string);
free (ti->stop_string); free (ti->stop_string);
free (ti); free (ti);

View File

@ -86,21 +86,21 @@ static inline void
termkey_key_get_linecol (const termkey_key_t *key, int *line, int *col) termkey_key_get_linecol (const termkey_key_t *key, int *line, int *col)
{ {
if (col) if (col)
*col = (unsigned char) key->code.mouse[1] *col = ((unsigned char) key->code.mouse[1]
| ((unsigned char) key->code.mouse[3] & 0x0f) << 8; | ((unsigned char) key->code.mouse[3] & 0x0f) << 8) - 1;
if (line) if (line)
*line = (unsigned char) key->code.mouse[2] *line = ((unsigned char) key->code.mouse[2]
| ((unsigned char) key->code.mouse[3] & 0x70) << 4; | ((unsigned char) key->code.mouse[3] & 0x70) << 4) - 1;
} }
static inline void static inline void
termkey_key_set_linecol (termkey_key_t *key, int line, int col) termkey_key_set_linecol (termkey_key_t *key, int line, int col)
{ {
if (line > 0xfff) if (++line > 0xfff)
line = 0xfff; line = 0xfff;
if (col > 0x7ff) if (++col > 0x7ff)
col = 0x7ff; col = 0x7ff;
key->code.mouse[1] = (line & 0x0ff); key->code.mouse[1] = (line & 0x0ff);

View File

@ -137,6 +137,7 @@ struct termkey_key
uint32_t codepoint; /* TERMKEY_TYPE_KEY */ uint32_t codepoint; /* TERMKEY_TYPE_KEY */
int number; /* TERMKEY_TYPE_FUNCTION */ int number; /* TERMKEY_TYPE_FUNCTION */
termkey_sym_t sym; /* TERMKEY_TYPE_KEYSYM */ termkey_sym_t sym; /* TERMKEY_TYPE_KEYSYM */
// TODO: rewrite this insanity
char mouse[4]; /* TERMKEY_TYPE_MOUSE */ char mouse[4]; /* TERMKEY_TYPE_MOUSE */
/* opaque, see termkey_interpret_mouse() */ /* opaque, see termkey_interpret_mouse() */
} code; } code;