From 456093e4edf513d0f1509db048623f6e1b209112 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Mon, 13 Oct 2014 01:03:13 +0200
Subject: Work on mouse support, it's a mess
---
driver-csi.c | 3 +-
driver-ti.c | 122 ++++++++++++++++++++++++++++++++++------------------
termkey2-internal.h | 12 +++---
termkey2.h | 1 +
4 files changed, 90 insertions(+), 48 deletions(-)
diff --git a/driver-csi.c b/driver-csi.c
index 23f38e7..9f822f0 100644
--- a/driver-csi.c
+++ b/driver-csi.c
@@ -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
*/
@@ -262,6 +262,7 @@ termkey_interpret_mouse (termkey_t *tk, const termkey_key_t *key,
termkey_key_get_linecol (key, line, col);
+ // XXX: WTF is this logic?
if (!event)
return TERMKEY_RES_KEY;
diff --git a/driver-ti.c b/driver-ti.c
index 93fda30..1b026fa 100644
--- a/driver-ti.c
+++ b/driver-ti.c
@@ -58,6 +58,9 @@ typedef struct
char *start_string;
char *stop_string;
+
+ bool have_mouse;
+ char *set_mouse_string;
}
termkey_ti_t;
@@ -172,56 +175,41 @@ compress_trie (struct trie_node *n)
return n;
}
-static int
+static bool
load_terminfo (termkey_ti_t *ti, const char *term)
{
- int i;
+ const char *mouse_report_string = NULL;
#ifdef HAVE_UNIBILIUM
unibi_term *unibi = unibi_from_term (term);
if (!unibi)
- return 0;
-#else
- int err;
+ return false;
+ for (int i = unibi_string_begin_ + 1; i < unibi_string_end_; i++)
+ {
+ const char *name = unibi_name_str (i);
+ const char *value = unibi_get_str (unibi, i);
+#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 0;
-#endif
+ return false;
-#ifdef HAVE_UNIBILIUM
- for (i = unibi_string_begin_ + 1; i < unibi_string_end_; i++)
-#else
- for (i = 0; strfnames[i]; i++)
-#endif
+ for (int i = 0; strfnames[i]; i++)
{
- // Only care about the key_* constants
-#ifdef HAVE_UNIBILIUM
- const char *name = unibi_name_str (i);
-#else
const char *name = strfnames[i];
+ const char *value = tigetstr (strnames[i]);
#endif
+ // Only care about the key_* constants
if (strncmp (name, "key_", 4) != 0)
continue;
-
-#ifdef HAVE_UNIBILIUM
- const char *value = unibi_get_str (unibi, i);
-#else
- const char *value = tigetstr (strnames[i]);
-#endif
if (!value || value == (char*) -1)
continue;
- struct trie_node *node = NULL;
- if (strcmp (name + 4, "mouse") == 0)
- {
- node = malloc (sizeof *node);
- if (!node)
- return 0;
-
- node->type = TYPE_MOUSE;
- }
+ trie_node_t *node = NULL;
+ if (!strcmp (name + 4, "mouse"))
+ mouse_report_string = value;
else
{
termkey_type_t type;
@@ -241,7 +229,36 @@ load_terminfo (termkey_ti_t *ti, const char *term)
if (node && !insert_seq (ti, value, 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);
#endif
- return 1;
+ return true;
}
static void *
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)
return NULL;
@@ -300,15 +317,14 @@ abort_free_ti:
return NULL;
}
-static int
+static bool
write_string (termkey_t *tk, char *string)
{
if (tk->fd == -1 || !isatty (tk->fd) || !string)
- return 1;
+ return true;
- /* The terminfo database will contain keys in application cursor key mode.
- * We may need to enable that mode
- */
+ // The terminfo database will contain keys in application cursor key mode.
+ // We may need to enable that mode
// Can't call putp or tputs because they suck and don't give us fd control
size_t len = strlen (string);
@@ -316,17 +332,38 @@ write_string (termkey_t *tk, char *string)
{
ssize_t written = write (tk->fd, string, len);
if (written == -1)
- return 0;
+ return false;
string += 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
start_driver (termkey_t *tk, void *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);
}
@@ -334,6 +371,8 @@ static int
stop_driver (termkey_t *tk, void *info)
{
termkey_ti_t *ti = info;
+ if (ti->have_mouse && !set_mouse (ti, false))
+ return false;
return write_string (tk, ti->stop_string);
}
@@ -342,6 +381,7 @@ free_driver (void *info)
{
termkey_ti_t *ti = info;
free_trie (ti->root);
+ free (ti->set_mouse_string);
free (ti->start_string);
free (ti->stop_string);
free (ti);
diff --git a/termkey2-internal.h b/termkey2-internal.h
index b76ba79..3881865 100644
--- a/termkey2-internal.h
+++ b/termkey2-internal.h
@@ -86,21 +86,21 @@ static inline void
termkey_key_get_linecol (const termkey_key_t *key, int *line, int *col)
{
if (col)
- *col = (unsigned char) key->code.mouse[1]
- | ((unsigned char) key->code.mouse[3] & 0x0f) << 8;
+ *col = ((unsigned char) key->code.mouse[1]
+ | ((unsigned char) key->code.mouse[3] & 0x0f) << 8) - 1;
if (line)
- *line = (unsigned char) key->code.mouse[2]
- | ((unsigned char) key->code.mouse[3] & 0x70) << 4;
+ *line = ((unsigned char) key->code.mouse[2]
+ | ((unsigned char) key->code.mouse[3] & 0x70) << 4) - 1;
}
static inline void
termkey_key_set_linecol (termkey_key_t *key, int line, int col)
{
- if (line > 0xfff)
+ if (++line > 0xfff)
line = 0xfff;
- if (col > 0x7ff)
+ if (++col > 0x7ff)
col = 0x7ff;
key->code.mouse[1] = (line & 0x0ff);
diff --git a/termkey2.h b/termkey2.h
index 9362215..60a3038 100644
--- a/termkey2.h
+++ b/termkey2.h
@@ -137,6 +137,7 @@ struct termkey_key
uint32_t codepoint; /* TERMKEY_TYPE_KEY */
int number; /* TERMKEY_TYPE_FUNCTION */
termkey_sym_t sym; /* TERMKEY_TYPE_KEYSYM */
+ // TODO: rewrite this insanity
char mouse[4]; /* TERMKEY_TYPE_MOUSE */
/* opaque, see termkey_interpret_mouse() */
} code;
--
cgit v1.2.3-70-g09d2