aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-04-09 17:27:20 +0200
committerMattias Andrée <maandree@kth.se>2021-04-09 18:11:52 +0200
commit74f9d03d7be05f8a8aa2a90560c6ce4125b91121 (patch)
tree7973cecf9318cb998ac3ac173410e2aa391f1479
parentRemove macro key as it conflicts with mouse tracking (diff)
downloadlibterminput-74f9d03d7be05f8a8aa2a90560c6ce4125b91121.tar.gz
libterminput-74f9d03d7be05f8a8aa2a90560c6ce4125b91121.tar.bz2
libterminput-74f9d03d7be05f8a8aa2a90560c6ce4125b91121.tar.xz
Add mouse tracking support
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--interactive-test.c58
-rw-r--r--libterminput.c378
-rw-r--r--libterminput.h59
3 files changed, 477 insertions, 18 deletions
diff --git a/interactive-test.c b/interactive-test.c
index 2da5ae8..04616a4 100644
--- a/interactive-test.c
+++ b/interactive-test.c
@@ -1,5 +1,6 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
@@ -17,14 +18,19 @@ main(void)
memset(&ctx, 0, sizeof(ctx));
- if (tcgetattr(STDIN_FILENO, &stty)) {
- perror("tcgetattr STDIN_FILENO");
+ if (getenv("TEST_LIBTERMINPUT_DECSET_1005")) {
+ fprintf(stderr, "LIBTERMINPUT_DECSET_1005 set\n");
+ libterminput_set_flags(&ctx, LIBTERMINPUT_DECSET_1005);
+ }
+
+ if (tcgetattr(STDERR_FILENO, &stty)) {
+ perror("tcgetattr STDERR_FILENO");
return 1;
}
saved_stty = stty;
stty.c_lflag &= (tcflag_t)~(ECHO | ICANON);
- if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty)) {
- perror("tcsetattr STDIN_FILENO TCSAFLUSH");
+ if (tcsetattr(STDERR_FILENO, TCSAFLUSH, &stty)) {
+ perror("tcsetattr STDERR_FILENO TCSAFLUSH");
return 1;
}
@@ -97,6 +103,48 @@ main(void)
printf("text:\n");
printf("\tlength: %zu\n", input.text.nbytes);
printf("\tdata: %.512s\n", input.text.bytes);
+ } else if (input.type == LIBTERMINPUT_MOUSEEVENT) {
+ printf("mouseevent:\n");
+ switch (input.mouseevent.event) {
+ case LIBTERMINPUT_PRESS: printf("\t%s: %s\n", "event", "press"); break;
+ case LIBTERMINPUT_RELEASE: printf("\t%s: %s\n", "event", "release"); break;
+ case LIBTERMINPUT_MOTION: printf("\t%s: %s\n", "event", "motion"); break;
+ case LIBTERMINPUT_HIGHLIGHT_INSIDE: printf("\t%s: %s\n", "event", "highlight inside"); goto was_highlight;
+ case LIBTERMINPUT_HIGHLIGHT_OUTSIDE: printf("\t%s: %s\n", "event", "highlight outside"); goto was_highlight;
+ default:
+ printf("\t%s: %s\n", "event", "other");
+ break;
+ }
+ switch (input.mouseevent.button) {
+ case LIBTERMINPUT_NO_BUTTON: printf("\t%s: %s\n", "button", "none"); break;
+ case LIBTERMINPUT_BUTTON1: printf("\t%s: %s\n", "button", "button 1 (left)"); break;
+ case LIBTERMINPUT_BUTTON2: printf("\t%s: %s\n", "button", "button 2 (middle)"); break;
+ case LIBTERMINPUT_BUTTON3: printf("\t%s: %s\n", "button", "button 3 (right)"); break;
+ case LIBTERMINPUT_SCROLL_UP: printf("\t%s: %s\n", "button", "scroll up"); break;
+ case LIBTERMINPUT_SCROLL_DOWN: printf("\t%s: %s\n", "button", "scroll down"); break;
+ case LIBTERMINPUT_SCROLL_LEFT: printf("\t%s: %s\n", "button", "scroll left"); break;
+ case LIBTERMINPUT_SCROLL_RIGHT: printf("\t%s: %s\n", "button", "scroll right"); break;
+ case LIBTERMINPUT_XBUTTON1: printf("\t%s: %s\n", "button", "extended button 1 (X1; backward)"); break;
+ case LIBTERMINPUT_XBUTTON2: printf("\t%s: %s\n", "button", "extended button 2 (X2; forward)"); break;
+ case LIBTERMINPUT_XBUTTON3: printf("\t%s: %s\n", "button", "extended button 3 (X3)"); break;
+ case LIBTERMINPUT_XBUTTON4: printf("\t%s: %s\n", "button", "extended button 4 (X4)"); break;
+ default:
+ printf("\t%s: %s\n", "button", "other");
+ break;
+ }
+ printf("\t%s: %s\n", "shift", (input.mouseevent.mods & LIBTERMINPUT_SHIFT) ? "yes" : "no");
+ printf("\t%s: %s\n", "meta", (input.mouseevent.mods & LIBTERMINPUT_META) ? "yes" : "no");
+ printf("\t%s: %s\n", "ctrl", (input.mouseevent.mods & LIBTERMINPUT_CTRL) ? "yes" : "no");
+ was_highlight:
+ printf("\t%s: x=%zu, y=%zu\n", "position", input.mouseevent.x, input.mouseevent.y);
+ if (LIBTERMINPUT_HIGHLIGHT_OUTSIDE) {
+ printf("\t%s: x=%zu, y=%zu\n", "start", input.mouseevent.start_x, input.mouseevent.start_y);
+ printf("\t%s: x=%zu, y=%zu\n", "end", input.mouseevent.end_x, input.mouseevent.end_y);
+ }
+ if (input.mouseevent.event == LIBTERMINPUT_PRESS) {
+ printf("\033[1;4;4;10;10T");
+ fflush(stdout);
+ }
} else {
printf("other\n");
}
@@ -105,6 +153,6 @@ main(void)
if (r < 0)
perror("libterminput_read STDIN_FILENO");
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty);
+ tcsetattr(STDERR_FILENO, TCSAFLUSH, &saved_stty);
return -r;
}
diff --git a/libterminput.c b/libterminput.c
index 2068aaf..b444ea7 100644
--- a/libterminput.c
+++ b/libterminput.c
@@ -26,9 +26,14 @@ read_input(int fd, struct input *input, struct libterminput_state *ctx)
if (ctx->stored_tail == ctx->stored_head)
ctx->stored_tail = ctx->stored_head = 0;
} else {
- r = read(fd, &c, 1);
+ r = read(fd, ctx->stored, sizeof(ctx->stored));
if (r <= 0)
return r;
+ c = ctx->stored[0];
+ if (r > 1) {
+ ctx->stored_tail = 1;
+ ctx->stored_head = (size_t)r;
+ }
}
again:
@@ -135,16 +140,152 @@ encode_utf8(unsigned long long int codepoint, char buffer[7])
}
+static int
+check_utf8_char(const char *s, size_t *lenp, size_t size)
+{
+ size_t len;
+ *lenp = 0;
+ if (!size) {
+ return 0;
+ } else if ((*s & 0x80) == 0) {
+ *lenp = 1;
+ return 1;
+ } else if ((*s & 0xE0) == 0xC0) {
+ goto need_2;
+ } else if ((*s & 0xF0) == 0xE0) {
+ goto need_3;
+ } else if ((*s & 0xF8) == 0xF0) {
+ goto need_4;
+ } else if ((*s & 0xFC) == 0xF8) {
+ goto need_5;
+ } else if ((*s & 0xFE) == 0xFC) {
+ goto need_6;
+ } else {
+ *lenp = 0;
+ return -1;
+ }
+
+need_6:
+ if (!size--) return 0;
+ if ((s[5] & 0xC0) != 0x80) return -1;
+ ++*lenp;
+
+need_5:
+ if (!size--) return 0;
+ if ((s[4] & 0xC0) != 0x80) return -1;
+ ++*lenp;
+
+need_4:
+ if (!size--) return 0;
+ if ((s[3] & 0xC0) != 0x80) return -1;
+ ++*lenp;
+
+need_3:
+ if (!size--) return 0;
+ if ((s[2] & 0xC0) != 0x80) return -1;
+ ++*lenp;
+
+need_2:
+ if (!size--) return 0;
+ if ((s[1] & 0xC0) != 0x80) return -1;
+ ++*lenp;
+
+ if (!size--) return 0;
+ ++*lenp;
+ return 1;
+}
+
+
+static unsigned long long int
+utf8_decode(const char *s, size_t *ip)
+{
+ unsigned long long int cp = 0;
+ size_t len;
+
+ if ((s[*ip] & 0x80) == 0) {
+ return s[(*ip)++];
+ } else if ((s[*ip] & 0xE0) == 0xC0) {
+ cp = (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0xC0U);
+ len = 1;
+ goto need_1;
+ } else if ((s[*ip] & 0xF0) == 0xE0) {
+ cp = (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0xE0U);
+ len = 2;
+ goto need_2;
+ } else if ((s[*ip] & 0xF8) == 0xF0) {
+ cp = (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0xF0U);
+ len = 3;
+ goto need_3;
+ } else if ((s[*ip] & 0xFC) == 0xF8) {
+ cp = (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0xF8U);
+ len = 4;
+ goto need_4;
+ } else if ((s[*ip] & 0xFE) == 0xFC) {
+ cp = (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0xFCU);
+ len = 5;
+ goto need_5;
+ }
+
+need_5:
+ if ((s[*ip] & 0xC0) != 0x80) return 0;
+ cp <<= 6;
+ cp |= (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0x80U);
+
+need_4:
+ if ((s[*ip] & 0xC0) != 0x80) return 0;
+ cp <<= 6;
+ cp |= (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0x80U);
+
+need_3:
+ if ((s[*ip] & 0xC0) != 0x80) return 0;
+ cp <<= 6;
+ cp |= (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0x80U);
+
+need_2:
+ if ((s[*ip] & 0xC0) != 0x80) return 0;
+ cp <<= 6;
+ cp |= (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0x80U);
+
+need_1:
+ if ((s[*ip] & 0xC0) != 0x80) return 0;
+ cp <<= 6;
+ cp |= (unsigned long long int)((unsigned char)s[(*ip)++] ^ 0x80U);
+
+ /* Let's ignore the 0x10FFFF upper bound. */
+
+ if (cp < 1ULL << (7 + 0 * 6))
+ return len > 1 ? 0ULL : cp;
+ if (cp < 1ULL << (5 + 1 * 6))
+ return len > 1 ? 0ULL : cp;
+ if (cp < 1ULL << (4 + 2 * 6))
+ return len > 1 ? 0ULL : cp;
+ if (cp < 1ULL << (3 + 3 * 6))
+ return len > 1 ? 0ULL : cp;
+ if (cp < 1ULL << (2 + 4 * 6))
+ return len > 1 ? 0ULL : cp;
+ if (cp < 1ULL << (1 + 5 * 6))
+ return len > 1 ? 0ULL : cp;
+
+ return 0;
+}
+
+
static void
parse_sequence(union libterminput_input *input, struct libterminput_state *ctx)
{
- unsigned long long int *nums;
- size_t keylen, n;
+ unsigned long long int *nums, numsbuf[6];
+ size_t keylen, n, nnums = 0, pos;
char *p;
/* Get number of numbers in the sequence, and allocate an array of at least 2 */
- for (n = 2, p = ctx->key; *p; p++)
- n += *p == ';';
+ if (ctx->key[0] == '[' && (ctx->key[1] == '<' ? isdigit(ctx->key[2]) : isdigit(ctx->key[1])))
+ nnums += 1;
+ for (n = 2, p = ctx->key; *p; p++) {
+ if (*p == ';') {
+ n += 1;
+ nnums += 1;
+ }
+ }
nums = alloca(n * sizeof(*nums));
nums[0] = nums[1] = 0;
@@ -184,10 +325,103 @@ parse_sequence(union libterminput_input *input, struct libterminput_state *ctx)
case 'F': input->keypress.key = LIBTERMINPUT_END; break;
case 'G': input->keypress.key = LIBTERMINPUT_BEGIN; break;
case 'H': input->keypress.key = LIBTERMINPUT_HOME; break;
+ case 'M':
+ if (nnums >= 3) { /* Parsing for \e[?1000;1015h output. */
+ nums[0] -= 32ULL;
+ decimal_mouse_tracking_set_press:
+ input->mouseevent.event = LIBTERMINPUT_PRESS;
+ decimal_mouse_tracking:
+ input->mouseevent.type = LIBTERMINPUT_MOUSEEVENT;
+ input->mouseevent.x = (size_t)nums[1] + (size_t)!nums[1];
+ input->mouseevent.y = (size_t)nums[2] + (size_t)!nums[3];
+ input->mouseevent.mods = (enum libterminput_mod)((nums[0] >> 2) & 7ULL);
+ if (nums[0] & 32)
+ input->mouseevent.event = LIBTERMINPUT_MOTION;
+ nums[0] = (nums[0] & 3ULL) | ((nums[0] >> 4) & ~3ULL);
+ if (nums[0] < 4) {
+ nums[0] = (nums[0] + 1) & 3;
+ if (!nums[0] && input->mouseevent.event == LIBTERMINPUT_PRESS)
+ input->mouseevent.event = LIBTERMINPUT_RELEASE;
+ }
+ input->mouseevent.button = (enum libterminput_button)nums[0];
+ } else if (!nnums & !(ctx->flags & LIBTERMINPUT_DECSET_1005)) {
+ /* Parsing output for legacy mouse tracking output. */
+ ctx->mouse_tracking = 0;
+ nums = numsbuf;
+ nums[0] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[1] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[2] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[0] = (nums[0] - 32ULL) & 255ULL;
+ nums[1] = (nums[1] - 32ULL) & 255ULL;
+ nums[2] = (nums[2] - 32ULL) & 255ULL;
+ if (ctx->stored_head == ctx->stored_tail)
+ ctx->stored_head = ctx->stored_tail = 0;
+ goto decimal_mouse_tracking_set_press;
+ } else if (!nnums) {
+ /* Parsing for semi-legacy \e[?1000;1005h output. */
+ ctx->mouse_tracking = 0;
+ nums = numsbuf;
+ pos = ctx->stored_tail;
+ nums[0] = utf8_decode(ctx->stored, &ctx->stored_tail);
+ if (nums[0] <= 32) {
+ ctx->stored_tail = pos;
+ goto suppress;
+ }
+ pos = ctx->stored_tail;
+ nums[1] = utf8_decode(ctx->stored, &ctx->stored_tail);
+ if (nums[1] <= 32) {
+ ctx->stored_tail = pos;
+ goto suppress;
+ }
+ pos = ctx->stored_tail;
+ nums[2] = utf8_decode(ctx->stored, &ctx->stored_tail);
+ if (nums[2] <= 32) {
+ ctx->stored_tail = pos;
+ goto suppress;
+ }
+ nums[0] = nums[0] - 32ULL;
+ nums[1] = nums[1] - 32ULL;
+ nums[2] = nums[2] - 32ULL;
+ if (ctx->stored_head == ctx->stored_tail)
+ ctx->stored_head = ctx->stored_tail = 0;
+ goto decimal_mouse_tracking_set_press;
+ } else {
+ goto suppress;
+ }
+ break;
case 'P': input->keypress.key = LIBTERMINPUT_F1; break;
case 'Q': input->keypress.key = LIBTERMINPUT_F2; break;
case 'R': input->keypress.key = LIBTERMINPUT_F3; break;
case 'S': input->keypress.key = LIBTERMINPUT_F4; break;
+ case 'T':
+ /* Parsing output for legacy mouse highlight tracking output. (\e[?1001h) */
+ ctx->mouse_tracking = 0;
+ nums = numsbuf;
+ nums[0] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[1] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[2] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[3] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[4] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[5] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[0] = (nums[0] - 32ULL) & 255ULL;
+ nums[1] = (nums[1] - 32ULL) & 255ULL;
+ nums[2] = (nums[2] - 32ULL) & 255ULL;
+ nums[3] = (nums[3] - 32ULL) & 255ULL;
+ nums[4] = (nums[4] - 32ULL) & 255ULL;
+ nums[5] = (nums[5] - 32ULL) & 255ULL;
+ if (ctx->stored_head == ctx->stored_tail)
+ ctx->stored_head = ctx->stored_tail = 0;
+ input->mouseevent.type = LIBTERMINPUT_MOUSEEVENT;
+ input->mouseevent.event = LIBTERMINPUT_HIGHLIGHT_OUTSIDE;
+ input->mouseevent.mods = 0;
+ input->mouseevent.button = LIBTERMINPUT_BUTTON1;
+ input->mouseevent.start_x = (size_t)nums[0];
+ input->mouseevent.start_y = (size_t)nums[1];
+ input->mouseevent.end_x = (size_t)nums[2];
+ input->mouseevent.end_y = (size_t)nums[3];
+ input->mouseevent.x = (size_t)nums[4];
+ input->mouseevent.y = (size_t)nums[5];
+ break;
case 'U': input->keypress.key = LIBTERMINPUT_NEXT; break;
case 'V': input->keypress.key = LIBTERMINPUT_PRIOR; break;
case 'Z':
@@ -210,6 +444,23 @@ parse_sequence(union libterminput_input *input, struct libterminput_state *ctx)
input->keypress.key = LIBTERMINPUT_LEFT;
input->keypress.mods |= LIBTERMINPUT_SHIFT;
break;
+ case 't':
+ /* Parsing output for legacy mouse highlight tracking output (\e[?1001h). */
+ ctx->mouse_tracking = 0;
+ nums = numsbuf;
+ nums[0] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[1] = (unsigned long long int)(unsigned char)ctx->stored[ctx->stored_tail++];
+ nums[0] = (nums[0] - 32ULL) & 255ULL;
+ nums[1] = (nums[1] - 32ULL) & 255ULL;
+ if (ctx->stored_head == ctx->stored_tail)
+ ctx->stored_head = ctx->stored_tail = 0;
+ input->mouseevent.type = LIBTERMINPUT_MOUSEEVENT;
+ input->mouseevent.event = LIBTERMINPUT_HIGHLIGHT_INSIDE;
+ input->mouseevent.mods = 0;
+ input->mouseevent.button = LIBTERMINPUT_BUTTON1;
+ input->mouseevent.x = (size_t)nums[0];
+ input->mouseevent.y = (size_t)nums[1];
+ break;
case 'u':
if (nums[0] > 0x10FFFFULL) {
input->type = LIBTERMINPUT_NONE;
@@ -290,7 +541,15 @@ parse_sequence(union libterminput_input *input, struct libterminput_state *ctx)
case 'D': input->keypress.key = LIBTERMINPUT_F4; break;
case 'E': input->keypress.key = LIBTERMINPUT_F5; break;
default:
- goto suppress;
+ if (ctx->key[1] == '<' && (ctx->key[2] == 'M' || ctx->key[2] == 'm') && nnums >= 3) {
+ /* Parsing for \e[?1003;1006h output. */
+ input->mouseevent.event = LIBTERMINPUT_PRESS;
+ if (ctx->key[2] == 'm')
+ input->mouseevent.event = LIBTERMINPUT_RELEASE;
+ goto decimal_mouse_tracking;
+ } else {
+ goto suppress;
+ }
}
break;
default:
@@ -410,6 +669,7 @@ libterminput_read(int fd, union libterminput_input *input, struct libterminput_s
size_t n, m;
char *p;
int r;
+ ssize_t rd;
if (!ctx->inited) {
ctx->inited = 1;
@@ -421,10 +681,35 @@ libterminput_read(int fd, union libterminput_input *input, struct libterminput_s
if (ctx->bracketed_paste)
return read_bracketed_paste(fd, input, ctx);
-
- r = read_input(fd, &ret, ctx);
- if (r <= 0)
- return r;
+ if (!ctx->mouse_tracking) {
+ r = read_input(fd, &ret, ctx);
+ if (r <= 0)
+ return r;
+ } else if (ctx->mouse_tracking == 1) {
+ if (ctx->stored_tail == sizeof(ctx->stored)) {
+ memmove(ctx->stored, &ctx->stored[ctx->stored_tail], ctx->stored_head - ctx->stored_tail);
+ ctx->stored_tail -= ctx->stored_head;
+ ctx->stored_head = 0;
+ }
+ rd = read(fd, &ctx->stored[ctx->stored_head], 1);
+ if (rd <= 0)
+ return (int)rd;
+ ctx->stored_head += 1;
+ p = strchr(ctx->key, '\0');
+ goto continue_incomplete;
+ } else {
+ if (ctx->stored_tail > sizeof(ctx->stored) - (size_t)ctx->mouse_tracking) {
+ memmove(ctx->stored, &ctx->stored[ctx->stored_tail], ctx->stored_head - ctx->stored_tail);
+ ctx->stored_tail -= ctx->stored_head;
+ ctx->stored_head = 0;
+ }
+ rd = read(fd, &ctx->stored[ctx->stored_head], (size_t)ctx->mouse_tracking - (ctx->stored_head - ctx->stored_tail));
+ if (rd <= 0)
+ return (int)rd;
+ ctx->stored_head += (size_t)rd;
+ p = strchr(ctx->key, '\0');
+ goto continue_incomplete;
+ }
again:
if (!*ret.symbol) {
@@ -458,9 +743,65 @@ again:
}
p = stpcpy(&ctx->key[n], ret.symbol);
/* Check if sequence is complete */
+ continue_incomplete:
if (!isalpha(p[-1]) && p[-1] != '~') {
input->type = LIBTERMINPUT_NONE;
return 1;
+ } else if (ctx->key[0] == '[' && ctx->key[1] == '<' && p == &ctx->key[2]) {
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ } else if (ctx->key[0] == '[' && ctx->key[1] == 'M' && (ctx->flags & LIBTERMINPUT_DECSET_1005)) {
+ ctx->mouse_tracking = 1;
+ if (ctx->stored_head == ctx->stored_tail) {
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ }
+ n = 0;
+ r = check_utf8_char(&ctx->stored[ctx->stored_tail + n], &m, ctx->stored_head - (ctx->stored_tail + n));
+ n += m;
+ if (!r) {
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ } else if (r < 0) {
+ ctx->mouse_tracking = 0;
+ input->type = LIBTERMINPUT_NONE;
+ ctx->stored_tail + n;
+ return 1;
+ }
+ r = check_utf8_char(&ctx->stored[ctx->stored_tail + n], &m, ctx->stored_head - (ctx->stored_tail + n));
+ n += m;
+ if (!r) {
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ } else if (r < 0) {
+ ctx->mouse_tracking = 0;
+ input->type = LIBTERMINPUT_NONE;
+ ctx->stored_tail + n;
+ return 1;
+ }
+ r = check_utf8_char(&ctx->stored[ctx->stored_tail + n], &m, ctx->stored_head - (ctx->stored_tail + n));
+ n += m;
+ if (!r) {
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ } else if (r < 0) {
+ ctx->mouse_tracking = 0;
+ input->type = LIBTERMINPUT_NONE;
+ ctx->stored_tail + n;
+ return 1;
+ }
+ } else if (ctx->key[0] == '[' && ctx->key[1] == 'M' && ctx->stored_head - ctx->stored_tail < 3) {
+ ctx->mouse_tracking = 3;
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ } else if (ctx->key[0] == '[' && ctx->key[1] == 't' && ctx->stored_head - ctx->stored_tail < 2) {
+ ctx->mouse_tracking = 2;
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
+ } else if (ctx->key[0] == '[' && ctx->key[1] == 'T' && ctx->stored_head - ctx->stored_tail < 6) {
+ ctx->mouse_tracking = 6;
+ input->type = LIBTERMINPUT_NONE;
+ return 1;
}
/* Parse the complete sequence */
parse_sequence(input, ctx);
@@ -504,3 +845,20 @@ again:
return 1;
}
+
+
+int
+libterminput_set_flags(struct libterminput_state *ctx, enum libterminput_flags flags)
+{
+ ctx->flags |= flags;
+ return 0;
+}
+
+
+int
+libterminput_clear_flags(struct libterminput_state *ctx, enum libterminput_flags flags)
+{
+ ctx->flags |= flags;
+ ctx->flags ^= flags;
+ return 0;
+}
diff --git a/libterminput.h b/libterminput.h
index 313fd72..58c2976 100644
--- a/libterminput.h
+++ b/libterminput.h
@@ -5,6 +5,16 @@
#include <stddef.h>
+/**
+ * Flags for supporting incompatible input; the user must
+ * set or clear his flag after setting or clearing it on
+ * the terminal, and the use must make sure that the
+ * terminal support this flag if set.
+ */
+enum libterminput_flags {
+ LIBTERMINPUT_DECSET_1005 = 0x0001
+};
+
enum libterminput_mod {
LIBTERMINPUT_SHIFT = 0x01,
LIBTERMINPUT_META = 0x02,
@@ -60,12 +70,36 @@ enum libterminput_key {
LIBTERMINPUT_KEYPAD_ENTER,
};
+enum libterminput_button {
+ LIBTERMINPUT_NO_BUTTON,
+ LIBTERMINPUT_BUTTON1, /* left (assuming right-handed) */
+ LIBTERMINPUT_BUTTON2, /* middle */
+ LIBTERMINPUT_BUTTON3, /* right (assuming right-handed) */
+ LIBTERMINPUT_SCROLL_UP, /* no corresponding release event shall be generated */
+ LIBTERMINPUT_SCROLL_DOWN, /* no corresponding release event shall be generated */
+ LIBTERMINPUT_SCROLL_LEFT, /* may or may not have a corresponding release event */
+ LIBTERMINPUT_SCROLL_RIGHT, /* may or may not have a corresponding release event */
+ LIBTERMINPUT_XBUTTON1, /* extended button 1, also known as backward */
+ LIBTERMINPUT_XBUTTON2, /* extended button 2, also known as forward */
+ LIBTERMINPUT_XBUTTON3, /* extended button 3, you probably don't have this button */
+ LIBTERMINPUT_XBUTTON4 /* extended button 4, you probably don't have this button */
+};
+
enum libterminput_type {
LIBTERMINPUT_NONE,
LIBTERMINPUT_KEYPRESS,
LIBTERMINPUT_BRACKETED_PASTE_START,
LIBTERMINPUT_BRACKETED_PASTE_END,
- LIBTERMINPUT_TEXT
+ LIBTERMINPUT_TEXT,
+ LIBTERMINPUT_MOUSEEVENT
+};
+
+enum libterminput_event {
+ LIBTERMINPUT_PRESS,
+ LIBTERMINPUT_RELEASE,
+ LIBTERMINPUT_MOTION,
+ LIBTERMINPUT_HIGHLIGHT_INSIDE,
+ LIBTERMINPUT_HIGHLIGHT_OUTSIDE
};
struct libterminput_keypress {
@@ -76,6 +110,19 @@ struct libterminput_keypress {
char symbol[7]; /* use if .key == LIBTERMINPUT_SYMBOL */
};
+struct libterminput_mouseevent {
+ enum libterminput_type type;
+ enum libterminput_mod mods; /* Set to 0 for LIBTERMINPUT_HIGHLIGHT_INSIDE and LIBTERMINPUT_HIGHLIGHT_OUTSIDE */
+ enum libterminput_button button; /* Set to 1 for LIBTERMINPUT_HIGHLIGHT_INSIDE and LIBTERMINPUT_HIGHLIGHT_OUTSIDE */
+ enum libterminput_event event;
+ size_t x;
+ size_t y;
+ size_t start_x; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */
+ size_t start_y; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */
+ size_t end_x; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */
+ size_t end_y; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */
+};
+
struct libterminput_text {
enum libterminput_type type;
size_t nbytes;
@@ -84,8 +131,9 @@ struct libterminput_text {
union libterminput_input {
enum libterminput_type type;
- struct libterminput_keypress keypress; /* use if .type == LIBTERMINPUT_KEYPRESS */
- struct libterminput_text text; /* use if .type == LIBTERMINPUT_TEXT */
+ struct libterminput_keypress keypress; /* use if .type == LIBTERMINPUT_KEYPRESS */
+ struct libterminput_text text; /* use if .type == LIBTERMINPUT_TEXT */
+ struct libterminput_mouseevent mouseevent; /* use if .type == LIBTERMINPUT_MOUSEEVENT */
};
@@ -95,9 +143,11 @@ union libterminput_input {
struct libterminput_state {
int inited; /* whether the input in initialised, not this struct */
enum libterminput_mod mods;
+ enum libterminput_flags flags;
size_t stored_head;
size_t stored_tail;
char bracketed_paste;
+ char mouse_tracking;
char meta;
char n;
char npartial;
@@ -117,5 +167,8 @@ struct libterminput_state {
*/
int libterminput_read(int fd, union libterminput_input *input, struct libterminput_state *ctx);
+int libterminput_set_flags(struct libterminput_state *ctx, enum libterminput_flags flags);
+int libterminput_clear_flags(struct libterminput_state *ctx, enum libterminput_flags flags);
+
#endif