diff options
author | Sébastien Helleu <flashcode@flashtux.org> | 2024-02-24 21:31:48 +0100 |
---|---|---|
committer | Sébastien Helleu <flashcode@flashtux.org> | 2024-03-06 20:33:17 +0100 |
commit | 5c88ee9c45411ae22b16d66d92c48323546aa761 (patch) | |
tree | c2ea0182c4c759c387aa8ebdffc9c4cca299e759 /src/gui/curses | |
parent | a8a005321181df14f78f1213c3d8e20e9b59090d (diff) | |
download | weechat-5c88ee9c45411ae22b16d66d92c48323546aa761.zip |
core: add support of SGR mouse events, remove option weechat.look.mouse_timer_delay (closes #2082)
Diffstat (limited to 'src/gui/curses')
-rw-r--r-- | src/gui/curses/gui-curses-key.c | 16 | ||||
-rw-r--r-- | src/gui/curses/gui-curses-mouse.c | 450 | ||||
-rw-r--r-- | src/gui/curses/gui-curses-mouse.h | 7 |
3 files changed, 314 insertions, 159 deletions
diff --git a/src/gui/curses/gui-curses-key.c b/src/gui/curses/gui-curses-key.c index c20e417fb..2c1f7acf9 100644 --- a/src/gui/curses/gui-curses-key.c +++ b/src/gui/curses/gui-curses-key.c @@ -331,14 +331,7 @@ gui_key_flush (int paste) insert_ok = 1; utf_partial_char[0] = '\0'; - if (!paste && gui_mouse_event_pending) - { - insert_ok = 0; - key_str[0] = (char)key; - key_str[1] = '\0'; - length_key_str = 1; - } - else if (!paste && (key < 32)) + if (!paste && (key < 32)) { insert_ok = 0; key_str[0] = '\x01'; @@ -353,6 +346,13 @@ gui_key_flush (int paste) key_str[2] = '\0'; length_key_str = 2; } + else if (!paste && gui_mouse_event_pending) + { + insert_ok = 0; + key_str[0] = (char)key; + key_str[1] = '\0'; + length_key_str = 1; + } else if (!paste && (key == 127)) { insert_ok = 0; diff --git a/src/gui/curses/gui-curses-mouse.c b/src/gui/curses/gui-curses-mouse.c index caa2aab1c..5f282b988 100644 --- a/src/gui/curses/gui-curses-mouse.c +++ b/src/gui/curses/gui-curses-mouse.c @@ -23,8 +23,10 @@ #include "config.h" #endif +#include <stdlib.h> #include <stdio.h> #include <string.h> +#include <ctype.h> #include <math.h> #include "../../core/weechat.h" @@ -46,7 +48,7 @@ #include "gui-curses-mouse.h" -char *gui_mouse_wheel_codes[][2] = +char *gui_mouse_wheel_utf8_codes[][2] = { { "`", "wheelup" }, { "p", "ctrl-wheelup" }, { "h", "alt-wheelup" }, @@ -57,7 +59,7 @@ char *gui_mouse_wheel_codes[][2] = { "y", "alt-ctrl-wheeldown" }, { NULL, NULL } }; -char *gui_mouse_button_codes[][2] = +char *gui_mouse_button_utf8_codes[][2] = { { " ", "button1" }, { "\"", "button2" }, { "!", "button3" }, @@ -87,7 +89,7 @@ void gui_mouse_enable () { gui_mouse_enabled = 1; - fprintf (stderr, "\033[?1005h\033[?1000h\033[?1002h"); + fprintf (stderr, "\033[?1005h\033[?1006h\033[?1000h\033[?1002h"); fflush (stderr); (void) hook_signal_send ("mouse_enabled", @@ -102,7 +104,7 @@ void gui_mouse_disable () { gui_mouse_enabled = 0; - fprintf (stderr, "\033[?1002l\033[?1000l\033[?1005l"); + fprintf (stderr, "\033[?1002l\033[?1000l\033[?1006l\033[?1005l"); fflush (stderr); (void) hook_signal_send ("mouse_disabled", @@ -212,87 +214,321 @@ gui_mouse_grab_end (const char *mouse_key) } /* - * Timer for grabbing mouse code. + * Returns size of mouse event (SGR and UTF-8 events are supported): + * -1: not a mouse event + * 0: incomplete mouse event + * > 0: complete mouse event */ int -gui_mouse_event_timer_cb (const void *pointer, void *data, int remaining_calls) +gui_mouse_event_size (const char *key) { - /* make C compiler happy */ - (void) pointer; - (void) data; - (void) remaining_calls; + const char *ptr_key; + int i, key_valid_utf8; - gui_mouse_event_end (); + if (!key || !key[0]) + return -1; - return WEECHAT_RC_OK; + if (strncmp (key, "\x01[[<", 4) == 0) + { + /* + * SGR event: digits separated by ';', ending by 'M' (pressed) + * or 'm' (released), example: "0;71;21M" + */ + for (ptr_key = key + 4; ptr_key[0]; ptr_key++) + { + if ((ptr_key[0] != ';') && !isdigit ((unsigned char)ptr_key[0])) + return ptr_key - key + 1; + } + return 0; + } + else if (strncmp (key, "\x01[[M", 4) == 0) + { + /* UTF-8 event: 3 UTF-8 chars, example: "!4&" */ + ptr_key = key + 4; + key_valid_utf8 = utf8_is_valid (ptr_key, -1, NULL); + for (i = 0; i < 3; i++) + { + if (!ptr_key[0]) + return 0; + ptr_key = (key_valid_utf8) ? utf8_next_char (ptr_key) : ptr_key + 1; + if (!ptr_key) + return 0; + } + return ptr_key - key; + } + + /* invalid mouse event, or not supported */ + return -1; } /* - * Initializes mouse event. + * Concatenates the mouse event gesture in a key (containing the button name). + * + * Note: *key must be long enough for the gesture added by this function + * (see below). + * + * Mouse gesture: if (x,y) on release is different from (x,y) on click, + * compute distance and angle between 2 points. + * + * Distance: sqrt((x2-x1)²+(y2-y1)²) + * Angle : atan2(x1-x1, y2-y1) + * + * Angle: + * + * 3.14 pi + * /\ + * -2.35 || 2.35 3/4 * pi + * || + * -1.57 /----++----\ 1.57 1/2 * pi + * \----++----/ + * || + * -0.78 || 0.78 1/4 * pi + * \/ + * 0.00 0 + * + * Possible returned gestures are: + * + * value returned | dist. | angle + * ----------------------+-------+-------------------------- + * "-gesture-up" | 3..19 | -2.35..-3.14 + 2.35..3.14 + * "-gesture-up-long" | >= 20 | + * "-gesture-down" | 3..19 | -0.78..0.78 + * "-gesture-down-long" | >= 20 | + * "-gesture-left" | 3..39 | -0.78..-2.35 + * "-gesture-left-long" | >= 40 | + * "-gesture-right" | 3..39 | 0.78..2.35 + * "-gesture-right-long" | >= 40 | */ void -gui_mouse_event_init () +gui_mouse_event_concat_gesture (char *key) { - gui_mouse_event_pending = 1; + double diff_x, diff_y, distance, angle, pi4; - if (gui_mouse_event_timer) - unhook (gui_mouse_event_timer); + /* (x, y) == (x2, y2) => no gesture, do not add anything */ + if ((gui_mouse_event_x[0] == gui_mouse_event_x[1]) + && (gui_mouse_event_y[0] == gui_mouse_event_y[1])) + return; - gui_mouse_event_timer = hook_timer (NULL, - CONFIG_INTEGER(config_look_mouse_timer_delay), - 0, 1, - &gui_mouse_event_timer_cb, NULL, NULL); + diff_x = gui_mouse_event_x[1] - gui_mouse_event_x[0]; + diff_y = gui_mouse_event_y[1] - gui_mouse_event_y[0]; + distance = sqrt ((diff_x * diff_x) + (diff_y * diff_y)); + if (distance >= 3) + { + angle = atan2 ((double)(gui_mouse_event_x[1] - gui_mouse_event_x[0]), + (double)(gui_mouse_event_y[1] - gui_mouse_event_y[0])); + pi4 = 3.14159265358979 / 4; + if ((angle <= pi4 * (-3)) || (angle >= pi4 * 3)) + { + strcat (key, "-gesture-up"); + if (distance >= 20) + strcat (key, "-long"); + } + else if ((angle >= pi4 * (-1)) && (angle <= pi4)) + { + strcat (key, "-gesture-down"); + if (distance >= 20) + strcat (key, "-long"); + } + else if ((angle >= pi4 * (-3)) && (angle <= pi4 * (-1))) + { + strcat (key, "-gesture-left"); + if (distance >= 40) + strcat (key, "-long"); + } + else if ((angle >= pi4) && (angle <= pi4 * 3)) + { + strcat (key, "-gesture-right"); + if (distance >= 40) + strcat (key, "-long"); + } + } } /* - * Gets key name with a mouse code. + * Gets mouse event name with a SGR mouse event. */ const char * -gui_mouse_event_code2key (const char *code) +gui_mouse_event_name_sgr (const char *key) { - int i, x, y, code_utf8, length; - double diff_x, diff_y, distance, angle, pi4; - static char key[128]; - const char *ptr_code; + int length, num_items, is_release; + char **items, *error; + static char mouse_key[128]; + long button, x, y; + + if (!key || !key[0]) + return NULL; + + mouse_key[0] = '\0'; + + items = string_split (key, ";", NULL, 0, 0, &num_items); + if (!items) + return NULL; + + if (num_items < 3) + goto error; + + error = NULL; + button = strtol (items[0], &error, 10); + if (!error || error[0]) + goto error; + + error = NULL; + x = strtol (items[1], &error, 10); + if (!error || error[0]) + goto error; + x = (x >= 1) ? x - 1 : 0; + + length = (int)strlen (items[2]); + if (length <= 0) + goto error; + is_release = (items[2][length - 1] == 'm') ? 1 : 0; + items[2][length - 1] = '\0'; + error = NULL; + y = strtol (items[2], &error, 10); + if (!error || error[0]) + goto error; + y = (y >= 1) ? y - 1 : 0; + + /* set data in "gui_mouse_event_xxx" */ + gui_mouse_event_x[gui_mouse_event_index] = x; + gui_mouse_event_y[gui_mouse_event_index] = y; + + /* keep same coordinates if it's release code received as first event */ + if ((gui_mouse_event_index == 0) && is_release) + { + gui_mouse_event_index = 1; + gui_mouse_event_x[1] = gui_mouse_event_x[0]; + gui_mouse_event_y[1] = gui_mouse_event_y[0]; + } + + if (gui_mouse_event_index == 0) + gui_mouse_event_index = 1; + + if (button & 8) + strcat (mouse_key, "alt-"); + if (button & 16) + strcat (mouse_key, "ctrl-"); + if (button & 4) + strcat (mouse_key, "shift-"); + + if (button & 64) + { + if ((button & 3) == 0) + strcat (mouse_key, "wheelup"); + else if ((button & 3) == 1) + strcat (mouse_key, "wheeldown"); + /* not yet supported: wheel left/right */ + /* + else if ((button & 3) == 2) + strcat (mouse_key, "wheelleft"); + else if ((button & 3) == 3) + strcat (mouse_key, "wheelright"); + */ + gui_mouse_event_x[1] = gui_mouse_event_x[0]; + gui_mouse_event_y[1] = gui_mouse_event_y[0]; + goto end; + } + else if (button & 128) + { + if ((button & 3) == 0) + strcat (mouse_key, "button8"); + else if ((button & 3) == 1) + strcat (mouse_key, "button9"); + else if ((button & 3) == 2) + strcat (mouse_key, "button10"); + else if ((button & 3) == 3) + strcat (mouse_key, "button11"); + } + else + { + if ((button & 3) == 0) + strcat (mouse_key, "button1"); + else if ((button & 3) == 1) + strcat (mouse_key, "button3"); + else if ((button & 3) == 2) + strcat (mouse_key, "button2"); + } + + if (!is_release && !(button & 64)) + { + strcat (mouse_key, "-event-"); + if (button & 32) + { + strcat (mouse_key, "drag"); + } + else + { + gui_mouse_event_x[1] = gui_mouse_event_x[0]; + gui_mouse_event_y[1] = gui_mouse_event_y[0]; + strcat (mouse_key, "down"); + } + goto end; + } + + gui_mouse_event_concat_gesture (mouse_key); + +end: + string_free_split (items); + return mouse_key; - key[0] = '\0'; +error: + string_free_split (items); + return NULL; +} + +/* + * Gets mouse event name with a UTF-8 mouse event: if the key is invalid UTF-8, + * use the 3 bytes, otherwise 3 UTF-8 chars. + */ + +const char * +gui_mouse_event_name_utf8 (const char *key) +{ + int i, x, y, key_valid_utf8, length; + static char mouse_key[128]; + const char *ptr_key; + + if (!key || !key[0]) + return NULL; + + mouse_key[0] = '\0'; /* - * mouse code must have at least: + * key must have at least: * one code (for event) + X + Y == 3 bytes or 3 UTF-8 chars */ - code_utf8 = utf8_is_valid (code, -1, NULL); - length = (code_utf8) ? utf8_strlen (code) : (int)strlen (code); + key_valid_utf8 = utf8_is_valid (key, -1, NULL); + length = (key_valid_utf8) ? utf8_strlen (key) : (int)strlen (key); if (length < 3) return NULL; /* get coordinates and button */ - if (code_utf8) + if (key_valid_utf8) { - /* get coordinates using UTF-8 chars in code */ - x = utf8_char_int (code + 1) - 33; - ptr_code = utf8_next_char (code + 1); - if (!ptr_code) + /* get coordinates using UTF-8 chars in key */ + x = utf8_char_int (key + 1) - 33; + ptr_key = (char *)utf8_next_char (key + 1); + if (!ptr_key) return NULL; - y = utf8_char_int (ptr_code) - 33; + y = utf8_char_int (ptr_key) - 33; } else { - /* get coordinates using ISO chars in code */ - x = ((unsigned char)code[1]) - 33; - y = ((unsigned char)code[2]) - 33; + /* get coordinates using ISO chars in key */ + x = ((unsigned char)key[1]) - 33; + y = ((unsigned char)key[2]) - 33; } if (x < 0) x = 0; if (y < 0) y = 0; - /* ignore code if it's motion/end code received as first event */ + /* ignore key if it's motion/end code received as first event */ if ((gui_mouse_event_index == 0) - && (MOUSE_CODE_MOTION(code[0]) || MOUSE_CODE_END(code[0]))) + && (MOUSE_CODE_UTF8_MOTION(key[0]) || MOUSE_CODE_UTF8_END(key[0]))) { return NULL; } @@ -301,7 +537,7 @@ gui_mouse_event_code2key (const char *code) gui_mouse_event_x[gui_mouse_event_index] = x; gui_mouse_event_y[gui_mouse_event_index] = y; if (gui_mouse_event_index == 0) - gui_mouse_event_button = code[0]; + gui_mouse_event_button = key[0]; if (gui_mouse_event_index == 0) gui_mouse_event_index = 1; @@ -309,149 +545,71 @@ gui_mouse_event_code2key (const char *code) /* * browse wheel codes, if one code is found, return event name immediately */ - for (i = 0; gui_mouse_wheel_codes[i][0]; i++) + for (i = 0; gui_mouse_wheel_utf8_codes[i][0]; i++) { - if (code[0] == gui_mouse_wheel_codes[i][0][0]) + if (key[0] == gui_mouse_wheel_utf8_codes[i][0][0]) { - strcat (key, gui_mouse_wheel_codes[i][1]); + strcat (mouse_key, gui_mouse_wheel_utf8_codes[i][1]); gui_mouse_event_x[1] = gui_mouse_event_x[0]; gui_mouse_event_y[1] = gui_mouse_event_y[0]; - return key; + return mouse_key; } } /* add name of button event */ - for (i = 0; gui_mouse_button_codes[i][0]; i++) + for (i = 0; gui_mouse_button_utf8_codes[i][0]; i++) { - if (gui_mouse_event_button == gui_mouse_button_codes[i][0][0]) + if (gui_mouse_event_button == gui_mouse_button_utf8_codes[i][0][0]) { - strcat (key, gui_mouse_button_codes[i][1]); + strcat (mouse_key, gui_mouse_button_utf8_codes[i][1]); break; } } /* nothing found, reset now or mouse will be stuck */ - if (!key[0]) + if (!mouse_key[0]) { gui_mouse_event_reset (); return NULL; } - if (!MOUSE_CODE_END(code[0])) + if (!MOUSE_CODE_UTF8_END(key[0])) { - strcat (key, "-event-"); - if (MOUSE_CODE_MOTION(code[0])) { - strcat (key, "drag"); + strcat (mouse_key, "-event-"); + if (MOUSE_CODE_UTF8_MOTION(key[0])) { + strcat (mouse_key, "drag"); } else { gui_mouse_event_x[1] = gui_mouse_event_x[0]; gui_mouse_event_y[1] = gui_mouse_event_y[0]; - strcat (key, "down"); + strcat (mouse_key, "down"); } - return key; + return mouse_key; } - /* - * Mouse gesture: if (x,y) on release is different from (x,y) on click, - * compute distance and angle between 2 points. - * - * Distance: sqrt((x2-x1)²+(y2-y1)²) - * Angle : atan2(x1-x1, y2-y1) - * - * Angle: - * - * 3.14 pi - * /\ - * -2.35 || 2.35 3/4 * pi - * || - * -1.57 /----++----\ 1.57 1/2 * pi - * \----++----/ - * || - * -0.78 || 0.78 1/4 * pi - * \/ - * 0.00 0 - * - * Possible returned gestures are: - * - * key name | dist. | angle - * ---------------------------+-------+-------------------------- - * buttonX-gesture-up | 3..19 | -2.35..-3.14 + 2.35..3.14 - * buttonX-gesture-up-long | >= 20 | - * buttonX-gesture-down | 3..19 | -0.78..0.78 - * buttonX-gesture-down-long | >= 20 | - * buttonX-gesture-left | 3..39 | -0.78..-2.35 - * buttonX-gesture-left-long | >= 40 | - * buttonX-gesture-right | 3..39 | 0.78..2.35 - * buttonX-gesture-right-long | >= 40 | - */ - - if (key[0] - && ((gui_mouse_event_x[0] != gui_mouse_event_x[1]) - || (gui_mouse_event_y[0] != gui_mouse_event_y[1]))) - { - diff_x = gui_mouse_event_x[1] - gui_mouse_event_x[0]; - diff_y = gui_mouse_event_y[1] - gui_mouse_event_y[0]; - distance = sqrt ((diff_x * diff_x) + (diff_y * diff_y)); - if (distance >= 3) - { - angle = atan2 ((double)(gui_mouse_event_x[1] - gui_mouse_event_x[0]), - (double)(gui_mouse_event_y[1] - gui_mouse_event_y[0])); - pi4 = 3.14159265358979 / 4; - if ((angle <= pi4 * (-3)) || (angle >= pi4 * 3)) - { - strcat (key, "-gesture-up"); - if (distance >= 20) - strcat (key, "-long"); - } - else if ((angle >= pi4 * (-1)) && (angle <= pi4)) - { - strcat (key, "-gesture-down"); - if (distance >= 20) - strcat (key, "-long"); - } - else if ((angle >= pi4 * (-3)) && (angle <= pi4 * (-1))) - { - strcat (key, "-gesture-left"); - if (distance >= 40) - strcat (key, "-long"); - } - else if ((angle >= pi4) && (angle <= pi4 * 3)) - { - strcat (key, "-gesture-right"); - if (distance >= 40) - strcat (key, "-long"); - } - } - } + gui_mouse_event_concat_gesture (mouse_key); - return key; + return mouse_key; } /* - * Ends mouse event. + * Processes a mouse event. */ void -gui_mouse_event_end () +gui_mouse_event_process (const char *key) { const char *mouse_key; int bare_event; - if (gui_key_debug) - gui_key_debug_print_key (gui_key_combo, NULL, NULL, NULL, 1); + /* get mouse event name */ + mouse_key = NULL; + if (strncmp (key, "\x01[[<", 4) == 0) + mouse_key = gui_mouse_event_name_sgr (key + 4); + else if (strncmp (key, "\x01[[M", 4) == 0) + mouse_key = gui_mouse_event_name_utf8 (key + 4); - gui_mouse_event_pending = 0; - - /* end mouse event timer */ - if (gui_mouse_event_timer) - { - unhook (gui_mouse_event_timer); - gui_mouse_event_timer = NULL; - } - - /* get key from mouse code */ - mouse_key = gui_mouse_event_code2key (gui_key_combo); if (mouse_key && mouse_key[0]) { bare_event = string_match (mouse_key, "*-event-*", 1); @@ -468,6 +626,4 @@ gui_mouse_event_end () if (!bare_event) gui_mouse_event_reset (); } - - gui_key_combo[0] = '\0'; } diff --git a/src/gui/curses/gui-curses-mouse.h b/src/gui/curses/gui-curses-mouse.h index 0fe47d894..35f4201b9 100644 --- a/src/gui/curses/gui-curses-mouse.h +++ b/src/gui/curses/gui-curses-mouse.h @@ -20,9 +20,8 @@ #ifndef WEECHAT_GUI_CURSES_MOUSE_H #define WEECHAT_GUI_CURSES_MOUSE_H -#define MOUSE_CODE_BUTTON(code) ((code >= 32) && (code < 64)) -#define MOUSE_CODE_MOTION(code) ((code >= 64) && (code < 96)) -#define MOUSE_CODE_END(code) ((code == '#') || (code == '3') \ - || (code == '+') || (code == ';')) +#define MOUSE_CODE_UTF8_MOTION(code) ((code >= 64) && (code < 96)) +#define MOUSE_CODE_UTF8_END(code) ((code == '#') || (code == '3') \ + || (code == '+') || (code == ';')) #endif /* WEECHAT_GUI_CURSES_MOUSE_H */ |