From 76c9f46438f37575bfa7f696a95ab6e7d173fd70 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 23 May 2021 13:38:19 +0530 Subject: [PATCH] Disambiguate between click and doublepress A doubleprpess should not generate a click event --- kitty/config_data.py | 4 +++- kitty/mouse.c | 33 ++++++++++++++++++++++++++++++++- kitty/state.c | 18 ++++++++++++++++++ kitty/state.h | 2 ++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/kitty/config_data.py b/kitty/config_data.py index 032eb2817..ec1b43bed 100644 --- a/kitty/config_data.py +++ b/kitty/config_data.py @@ -157,7 +157,9 @@ number ``b1 ... b8`` can be used to refer to upto eight buttons on a mouse. ``event-type`` is one ``press``, ``release``, ``doublepress``, ``triplepress``, ``click`` and ``doubleclick``. ``modes`` indicates whether the action is performed when the mouse is grabbed by the terminal application or not. It can -have one or more or the values, ``grabbed,ungrabbed``. +have one or more or the values, ``grabbed,ungrabbed``. Note that the click +and double click events have a delay of :opt:`click_interval` to disambiguate +from double and triple presses. You can run kitty with the :option:`kitty --debug-input` command line option to see mouse events. See the builtin actions below to get a sense of what is possible. diff --git a/kitty/mouse.c b/kitty/mouse.c index 1f5d3641d..349484bf9 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -480,11 +480,42 @@ mouse_open_url(Window *w) { screen_open_url(screen); } +typedef struct PendingClick { + id_type window_id; + int button, count, modifiers; + bool grabbed; + monotonic_t at; +} PendingClick; + +static void +free_pending_click(id_type timer_id UNUSED, void *pc) { free(pc); } + +void +send_pending_click_to_window(Window *w, void *data) { + PendingClick *pc = (PendingClick*)data; + ClickQueue *q = &w->click_queues[pc->button]; + // only send click if no presses have happened since the release that triggered the click + if (q->length && q->clicks[q->length - 1].at <= pc->at) { + dispatch_mouse_event(w, pc->button, pc->count, pc->modifiers, pc->grabbed); + } +} + static void dispatch_possible_click(Window *w, int button, int modifiers) { Screen *screen = w->render_data.screen; int count = multi_click_count(w, button); - if (release_is_click(w, button)) dispatch_mouse_event(w, button, count == 2 ? -3 : -2, modifiers, screen->modes.mouse_tracking_mode != 0); + if (release_is_click(w, button)) { + PendingClick *pc = calloc(sizeof(PendingClick), 1); + if (pc) { + pc->window_id = w->id; + pc->at = monotonic(); + pc->button = button; + pc->count = count == 2 ? -3 : -2; + pc->modifiers = modifiers; + pc->grabbed = screen->modes.mouse_tracking_mode != 0; + add_main_loop_timer(OPT(click_interval), false, send_pending_click_to_window_id, pc, free_pending_click); + } + } } HANDLER(handle_button_event) { diff --git a/kitty/state.c b/kitty/state.c index f9cd0d37b..e6d0b4d36 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -525,6 +525,24 @@ make_window_context_current(id_type window_id) { return false; } +void +send_pending_click_to_window_id(id_type timer_id UNUSED, void *data) { + id_type window_id = *((id_type*)data); + for (size_t o = 0; o < global_state.num_os_windows; o++) { + OSWindow *osw = global_state.os_windows + o; + for (size_t t = 0; t < osw->num_tabs; t++) { + Tab *qtab = osw->tabs + t; + for (size_t w = 0; w < qtab->num_windows; w++) { + Window *window = qtab->windows + w; + if (window->id == window_id) { + send_pending_click_to_window(window, data); + return; + } + } + } + } +} + // Python API {{{ #define PYWRAP0(name) static PyObject* py##name(PYNOARG) diff --git a/kitty/state.h b/kitty/state.h index 18c93e891..7fd7fe373 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -292,3 +292,5 @@ Window* window_for_window_id(id_type kitty_window_id); void mouse_open_url(Window *w); void mouse_selection(Window *w, int code, int button); const char* format_mods(unsigned mods); +void send_pending_click_to_window_id(id_type, void*); +void send_pending_click_to_window(Window*, void*);