diff options
Diffstat (limited to 'src/nvim/tui/input.c')
-rw-r--r-- | src/nvim/tui/input.c | 126 |
1 files changed, 78 insertions, 48 deletions
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index c41107d4d3..e0dd4022ed 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + #include "nvim/tui/input.h" #include "nvim/vim.h" @@ -6,15 +9,13 @@ #include "nvim/ascii.h" #include "nvim/charset.h" #include "nvim/main.h" -#include "nvim/misc2.h" +#include "nvim/aucmd.h" #include "nvim/option.h" #include "nvim/os/os.h" #include "nvim/os/input.h" #include "nvim/event/rstream.h" #define PASTETOGGLE_KEY "<Paste>" -#define FOCUSGAINED_KEY "<FocusGained>" -#define FOCUSLOST_KEY "<FocusLost>" #define KEY_BUFFER_SIZE 0xfff #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -34,13 +35,28 @@ void term_input_init(TermInput *input, Loop *loop) if (!term) { term = ""; // termkey_new_abstract assumes non-null (#2745) } - int enc_flag = enc_utf8 ? TERMKEY_FLAG_UTF8 : TERMKEY_FLAG_RAW; - input->tk = termkey_new_abstract(term, enc_flag); + +#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 + input->tk = termkey_new_abstract(term, + TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART); + termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, NULL); + termkey_start(input->tk); +#else + input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8); +#endif int curflags = termkey_get_canonflags(input->tk); termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS); // setup input handle - rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff, input); +#ifdef WIN32 + uv_tty_init(&loop->uv, &input->tty_in, 0, 1); + uv_tty_set_mode(&input->tty_in, UV_TTY_MODE_RAW); + rstream_init_stream(&input->read_stream, + (uv_stream_t *)&input->tty_in, + 0xfff); +#else + rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff); +#endif // initialize a timer handle for handling ESC with libtermkey time_watcher_init(loop, &input->timer_handle, input); } @@ -51,13 +67,13 @@ void term_input_destroy(TermInput *input) uv_mutex_destroy(&input->key_buffer_mutex); uv_cond_destroy(&input->key_buffer_cond); time_watcher_close(&input->timer_handle, NULL); - stream_close(&input->read_stream, NULL); + stream_close(&input->read_stream, NULL, NULL); termkey_destroy(input->tk); } void term_input_start(TermInput *input) { - rstream_start(&input->read_stream, read_cb); + rstream_start(&input->read_stream, read_cb, input); } void term_input_stop(TermInput *input) @@ -95,7 +111,7 @@ static void flush_input(TermInput *input, bool wait_until_empty) size_t drain_boundary = wait_until_empty ? 0 : 0xff; do { uv_mutex_lock(&input->key_buffer_mutex); - loop_schedule(&main_loop, event_create(1, wait_input_enqueue, 1, input)); + loop_schedule(&main_loop, event_create(wait_input_enqueue, 1, input)); input->waiting = true; while (input->waiting) { uv_cond_wait(&input->key_buffer_cond, &input->key_buffer_mutex); @@ -156,11 +172,21 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) char buf[64]; size_t len = 0; int button, row, col; + static int last_pressed_button = 0; TermKeyMouseEvent ev; termkey_interpret_mouse(input->tk, key, &ev, &button, &row, &col); - if (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG - && ev != TERMKEY_MOUSE_RELEASE) { + if ((ev == TERMKEY_MOUSE_RELEASE || ev == TERMKEY_MOUSE_DRAG) + && button == 0) { + // Some terminals (like urxvt) don't report which button was released. + // libtermkey reports button 0 in this case. + // For drag and release, we can reasonably infer the button to be the last + // pressed one. + button = last_pressed_button; + } + + if (button == 0 || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG + && ev != TERMKEY_MOUSE_RELEASE)) { return; } @@ -187,18 +213,26 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key) len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Right"); } - if (ev == TERMKEY_MOUSE_PRESS) { - if (button == 4) { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp"); - } else if (button == 5) { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelDown"); - } else { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse"); - } - } else if (ev == TERMKEY_MOUSE_DRAG) { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag"); - } else if (ev == TERMKEY_MOUSE_RELEASE) { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release"); + switch (ev) { + case TERMKEY_MOUSE_PRESS: + if (button == 4) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp"); + } else if (button == 5) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, + "ScrollWheelDown"); + } else { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse"); + last_pressed_button = button; + } + break; + case TERMKEY_MOUSE_DRAG: + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag"); + break; + case TERMKEY_MOUSE_RELEASE: + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release"); + break; + case TERMKEY_MOUSE_UNKNOWN: + assert(false); } len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row); @@ -216,12 +250,14 @@ static int get_key_code_timeout(void) { Integer ms = -1; // Check 'ttimeout' to determine if we should send ESC after 'ttimeoutlen'. - // See :help 'ttimeout' for more information Error err = ERROR_INIT; - if (vim_get_option(cstr_as_string("ttimeout"), &err).data.boolean) { - ms = vim_get_option(cstr_as_string("ttimeoutlen"), &err).data.integer; + if (nvim_get_option(cstr_as_string("ttimeout"), &err).data.boolean) { + Object rv = nvim_get_option(cstr_as_string("ttimeoutlen"), &err); + if (!ERROR_SET(&err)) { + ms = rv.data.integer; + } } - + api_clear_error(&err); return (int)ms; } @@ -265,9 +301,9 @@ static void timer_cb(TimeWatcher *watcher, void *data) /// Handle focus events. /// -/// If the upcoming sequence of bytes in the input stream matches either the -/// escape code for focus gained `<ESC>[I` or focus lost `<ESC>[O` then consume -/// that sequence and push the appropriate event into the input queue +/// If the upcoming sequence of bytes in the input stream matches the termcode +/// for "focus gained" or "focus lost", consume that sequence and schedule an +/// event on the main loop. /// /// @param input the input stream /// @return true iff handle_focus_event consumed some input @@ -279,11 +315,7 @@ static bool handle_focus_event(TermInput *input) // Advance past the sequence bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I'; rbuffer_consumed(input->read_stream.buffer, 3); - if (focus_gained) { - enqueue_input(input, FOCUSGAINED_KEY, sizeof(FOCUSGAINED_KEY) - 1); - } else { - enqueue_input(input, FOCUSLOST_KEY, sizeof(FOCUSLOST_KEY) - 1); - } + aucmd_schedule_focusgained(focus_gained); return true; } return false; @@ -326,8 +358,8 @@ static void set_bg_deferred(void **argv) { char *bgvalue = argv[0]; set_string_default("bg", bgvalue, false); - if (!option_was_set((char_u *)"bg")) { - set_option_value((char_u *)"bg", 0, (char_u *)bgvalue, 0); + if (!option_was_set("bg")) { + set_option_value("bg", 0, bgvalue, 0); } } @@ -373,19 +405,17 @@ static bool handle_background_color(TermInput *input) double r = (double)rgb[0] / (double)rgb_max[0]; double g = (double)rgb[1] / (double)rgb_max[1]; double b = (double)rgb[2] / (double)rgb_max[2]; - double luminance = 0.299*r + 0.587*g + 0.114*b; // CCIR 601 + double luminance = (0.299 * r) + (0.587 * g) + (0.114 * b); // CCIR 601 char *bgvalue = luminance < 0.5 ? "dark" : "light"; - loop_schedule(&main_loop, event_create(1, set_bg_deferred, 1, bgvalue)); + loop_schedule(&main_loop, event_create(set_bg_deferred, 1, bgvalue)); } return true; } return false; } -static void restart_reading(void **argv); - -static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, - bool eof) +static void read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, + bool eof) { TermInput *input = data; @@ -402,10 +432,10 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, // // ls *.md | xargs nvim input->in_fd = 2; - stream_close(&input->read_stream, NULL); - queue_put(input->loop->fast_events, restart_reading, 1, input); + stream_close(&input->read_stream, NULL, NULL); + multiqueue_put(input->loop->fast_events, restart_reading, 1, input); } else { - loop_schedule(&main_loop, event_create(1, input_done_event, 0)); + loop_schedule(&main_loop, event_create(input_done_event, 0)); } return; } @@ -454,6 +484,6 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, static void restart_reading(void **argv) { TermInput *input = argv[0]; - rstream_init_fd(input->loop, &input->read_stream, input->in_fd, 0xfff, input); - rstream_start(&input->read_stream, read_cb); + rstream_init_fd(input->loop, &input->read_stream, input->in_fd, 0xfff); + rstream_start(&input->read_stream, read_cb, input); } |