diff options
Diffstat (limited to 'src/nvim/os/input.c')
-rw-r--r-- | src/nvim/os/input.c | 113 |
1 files changed, 106 insertions, 7 deletions
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 686fe1f06d..cddc28fac9 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -46,7 +46,7 @@ void input_init(void) { input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); - if (embedded_mode) { + if (abstract_ui) { return; } @@ -57,7 +57,7 @@ void input_init(void) void input_teardown(void) { - if (embedded_mode) { + if (abstract_ui) { return; } @@ -67,7 +67,7 @@ void input_teardown(void) // Listen for input void input_start(void) { - if (embedded_mode) { + if (abstract_ui) { return; } @@ -77,7 +77,7 @@ void input_start(void) // Stop listening for input void input_stop(void) { - if (embedded_mode) { + if (abstract_ui) { return; } @@ -180,11 +180,110 @@ void input_buffer_restore(String str) size_t input_enqueue(String keys) { - size_t rv = rbuffer_write(input_buffer, keys.data, keys.size); + char *ptr = keys.data, *end = ptr + keys.size; + + while (rbuffer_available(input_buffer) >= 6 && ptr < end) { + uint8_t buf[6] = {0}; + int new_size = trans_special((uint8_t **)&ptr, buf, false); + + if (!new_size) { + // copy the character unmodified + *buf = (uint8_t)*ptr++; + new_size = 1; + } + + new_size = handle_mouse_event(&ptr, buf, new_size); + // TODO(tarruda): Don't produce past unclosed '<' characters, except if + // there's a lot of characters after the '<' + rbuffer_write(input_buffer, (char *)buf, (size_t)new_size); + } + + size_t rv = (size_t)(ptr - keys.data); process_interrupts(); return rv; } +// Mouse event handling code(Extract row/col if available and detect multiple +// clicks) +static int handle_mouse_event(char **ptr, uint8_t *buf, int bufsize) +{ + int mouse_code = 0; + + if (bufsize == 3) { + mouse_code = buf[2]; + } else if (bufsize == 6) { + // prefixed with K_SPECIAL KS_MODIFIER mod + mouse_code = buf[5]; + } + + if (mouse_code < KE_LEFTMOUSE || mouse_code > KE_RIGHTRELEASE) { + return bufsize; + } + + // a <[COL],[ROW]> sequence can follow and will set the mouse_row/mouse_col + // global variables. This is ugly but its how the rest of the code expects to + // find mouse coordinates, and it would be too expensive to refactor this + // now. + int col, row, advance; + if (sscanf(*ptr, "<%d,%d>%n", &col, &row, &advance)) { + if (col >= 0 && row >= 0) { + mouse_row = row; + mouse_col = col; + } + *ptr += advance; + } + + static int orig_num_clicks = 0; + static int orig_mouse_code = 0; + static int orig_mouse_col = 0; + static int orig_mouse_row = 0; + static uint64_t orig_mouse_time = 0; // time of previous mouse click + uint64_t mouse_time = os_hrtime(); // time of current mouse click + + // compute the time elapsed since the previous mouse click and + // convert p_mouse from ms to ns + uint64_t timediff = mouse_time - orig_mouse_time; + uint64_t mouset = (uint64_t)p_mouset * 1000000; + if (mouse_code == orig_mouse_code + && timediff < mouset + && orig_num_clicks != 4 + && orig_mouse_col == mouse_col + && orig_mouse_row == mouse_row) { + orig_num_clicks++; + } else { + orig_num_clicks = 1; + } + orig_mouse_code = mouse_code; + orig_mouse_col = mouse_col; + orig_mouse_row = mouse_row; + orig_mouse_time = mouse_time; + + int modifiers = 0; + if (orig_num_clicks == 2) { + modifiers |= MOD_MASK_2CLICK; + } else if (orig_num_clicks == 3) { + modifiers |= MOD_MASK_3CLICK; + } else if (orig_num_clicks == 4) { + modifiers |= MOD_MASK_4CLICK; + } + + if (modifiers) { + if (buf[1] != KS_MODIFIER) { + // no modifiers in the buffer yet, shift the bytes 3 positions + memcpy(buf + 3, buf, 3); + // add the modifier sequence + buf[0] = K_SPECIAL; + buf[1] = KS_MODIFIER; + buf[2] = (uint8_t)modifiers; + bufsize += 3; + } else { + buf[2] |= (uint8_t)modifiers; + } + } + + return bufsize; +} + static bool input_poll(int ms) { if (do_profiling == PROF_YES && ms) { @@ -255,7 +354,7 @@ static void read_cb(RStream *rstream, void *data, bool at_eof) static void convert_input(void) { - if (embedded_mode || !rbuffer_available(input_buffer)) { + if (abstract_ui || !rbuffer_available(input_buffer)) { // No input buffer space return; } @@ -335,7 +434,7 @@ static bool input_ready(void) return typebuf_was_filled || // API call filled typeahead rbuffer_pending(input_buffer) > 0 || // Stdin input event_has_deferred() || // Events must be processed - (!embedded_mode && eof); // Stdin closed + (!abstract_ui && eof); // Stdin closed } // Exit because of an input read error. |