From 74f9d03d7be05f8a8aa2a90560c6ce4125b91121 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Fri, 9 Apr 2021 17:27:20 +0200 Subject: Add mouse tracking support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- interactive-test.c | 58 +++++++- libterminput.c | 378 +++++++++++++++++++++++++++++++++++++++++++++++++++-- libterminput.h | 59 ++++++++- 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 +#include #include #include #include @@ -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 +/** + * 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 -- cgit v1.2.3-70-g09d2