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; - /* Have to cast away the const. But it's OK - we know terminfo won't - * 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 + for (int i = unibi_string_begin_ + 1; i < unibi_string_end_; i++) { - // Only care about the key_* constants -#ifdef HAVE_UNIBILIUM 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); #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]); #endif + // Only care about the key_* constants + if (strncmp (name, "key_", 4) != 0) + continue; 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;