aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/os/input.c')
-rw-r--r--src/nvim/os/input.c113
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.