From 9a3d99515f79989d6058747ee01fd1d4da71154d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 28 Sep 2021 11:41:35 +0530 Subject: [PATCH] Add support for reporting mouse events with pixel co-ordinates using the SGR_PIXEL_PROTOCOL introduced in xterm 359 --- docs/changelog.rst | 3 +++ kitty/data-types.h | 2 +- kitty/modes.h | 1 + kitty/mouse.c | 18 ++++++++++++------ kitty/screen.c | 5 +++++ 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6b583b812..9a1e2a659 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,9 @@ To update |kitty|, :doc:`follow the instructions `. - Allow the user to supply a custom Python function to draw tab bar. See :opt:`tab_bar_style` +- Add support for reporting mouse events with pixel co-ordinates using the + ``SGR_PIXEL_PROTOCOL`` introduced in xterm 359 + - When programs ask to read from the clipboard prompt the user to allow the request by default instead of denying by default. See :opt:`clipboard_control` for details (:iss:`4022`) diff --git a/kitty/data-types.h b/kitty/data-types.h index 0f2880165..5e827c5f4 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -60,7 +60,7 @@ typedef enum { DISABLE_LIGATURES_NEVER, DISABLE_LIGATURES_CURSOR, DISABLE_LIGATU #define ERROR_PREFIX "[PARSE ERROR]" typedef enum MouseTrackingModes { NO_TRACKING, BUTTON_MODE, MOTION_MODE, ANY_MODE } MouseTrackingMode; -typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL} MouseTrackingProtocol; +typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL, SGR_PIXEL_PROTOCOL} MouseTrackingProtocol; typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape; typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn; typedef enum { TILING, SCALED, MIRRORED } BackgroundImageLayout; diff --git a/kitty/modes.h b/kitty/modes.h index b4c5a09e0..a6db16ad4 100644 --- a/kitty/modes.h +++ b/kitty/modes.h @@ -66,6 +66,7 @@ #define MOUSE_UTF8_MODE (1005 << 5) #define MOUSE_SGR_MODE (1006 << 5) #define MOUSE_URXVT_MODE (1015 << 5) +#define MOUSE_SGR_PIXEL_MODE (1016 << 5) // Save cursor (DECSC) #define SAVE_CURSOR (1048 << 5) diff --git a/kitty/mouse.c b/kitty/mouse.c index d72f4ec5f..c1ea3d810 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -66,7 +66,7 @@ encode_button(unsigned int button) { static char mouse_event_buf[64]; static int -encode_mouse_event_impl(unsigned int x, unsigned int y, int mouse_tracking_protocol, int button, MouseAction action, int mods) { +encode_mouse_event_impl(const MousePosition *mpos, int mouse_tracking_protocol, int button, MouseAction action, int mods) { unsigned int cb = 0; if (action == MOVE) { cb = 3; @@ -79,7 +79,12 @@ encode_mouse_event_impl(unsigned int x, unsigned int y, int mouse_tracking_proto if (mods & GLFW_MOD_SHIFT) cb |= SHIFT_INDICATOR; if (mods & GLFW_MOD_ALT) cb |= ALT_INDICATOR; if (mods & GLFW_MOD_CONTROL) cb |= CONTROL_INDICATOR; + int x = mpos->cell_x + 1, y = mpos->cell_y + 1; switch(mouse_tracking_protocol) { + case SGR_PIXEL_PROTOCOL: + x = (unsigned int)round(mpos->x); + y = (unsigned int)round(mpos->y); + /* fallthrough */ case SGR_PROTOCOL: return snprintf(mouse_event_buf, sizeof(mouse_event_buf), "<%d;%d;%d%s", cb, x, y, action == RELEASE ? "m" : "M"); break; @@ -106,9 +111,8 @@ encode_mouse_event_impl(unsigned int x, unsigned int y, int mouse_tracking_proto static int encode_mouse_event(Window *w, int button, MouseAction action, int mods) { - unsigned int x = w->mouse_pos.cell_x + 1, y = w->mouse_pos.cell_y + 1; // 1 based indexing Screen *screen = w->render_data.screen; - return encode_mouse_event_impl(x, y, screen->modes.mouse_tracking_protocol, button, action, mods); + return encode_mouse_event_impl(&w->mouse_pos, screen->modes.mouse_tracking_protocol, button, action, mods); } static int @@ -337,7 +341,7 @@ HANDLER(handle_move_event) { if (handle_in_kitty) { handle_mouse_movement_in_kitty(w, button, mouse_cell_changed | cell_half_changed); } else { - if (!mouse_cell_changed) return; + if (!mouse_cell_changed && screen->modes.mouse_tracking_protocol != SGR_PIXEL_PROTOCOL) return; int sz = encode_mouse_button(w, MAX(0, button), button >=0 ? DRAG : MOVE, modifiers); if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); } } @@ -799,7 +803,8 @@ send_mouse_event(PyObject *self UNUSED, PyObject *args) { MouseTrackingMode mode = screen->modes.mouse_tracking_mode; if (mode == ANY_MODE || (mode == MOTION_MODE && action != MOVE) || (mode == BUTTON_MODE && (action == PRESS || action == RELEASE))) { - int sz = encode_mouse_event_impl(x + 1, y + 1, screen->modes.mouse_tracking_protocol, button, action, mods); + MousePosition mpos = {.cell_x = x, .cell_y = y}; + int sz = encode_mouse_event_impl(&mpos, screen->modes.mouse_tracking_protocol, button, action, mods); if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); @@ -814,7 +819,8 @@ test_encode_mouse(PyObject *self UNUSED, PyObject *args) { unsigned int x, y; int mouse_tracking_protocol, button, action, mods; if (!PyArg_ParseTuple(args, "IIiiii", &x, &y, &mouse_tracking_protocol, &button, &action, &mods)) return NULL; - int sz = encode_mouse_event_impl(x, y, mouse_tracking_protocol, button, action, mods); + MousePosition mpos = {.cell_x = x - 1, .cell_y = y - 1}; + int sz = encode_mouse_event_impl(&mpos, mouse_tracking_protocol, button, action, mods); return PyUnicode_FromStringAndSize(mouse_event_buf, sz); } diff --git a/kitty/screen.c b/kitty/screen.c index 52b574d86..edaa9fca9 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -921,6 +921,7 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) { MOUSE_MODE(MOUSE_MOVE_TRACKING, mouse_tracking_mode, ANY_MODE) MOUSE_MODE(MOUSE_UTF8_MODE, mouse_tracking_protocol, UTF8_PROTOCOL) MOUSE_MODE(MOUSE_SGR_MODE, mouse_tracking_protocol, SGR_PROTOCOL) + MOUSE_MODE(MOUSE_SGR_PIXEL_MODE, mouse_tracking_protocol, SGR_PIXEL_PROTOCOL) MOUSE_MODE(MOUSE_URXVT_MODE, mouse_tracking_protocol, URXVT_PROTOCOL) case DECSCLM: @@ -1816,6 +1817,10 @@ report_mode_status(Screen *self, unsigned int which, bool private) { ans = self->modes.mouse_tracking_mode == ANY_MODE ? 1 : 2; break; case MOUSE_SGR_MODE: ans = self->modes.mouse_tracking_protocol == SGR_PROTOCOL ? 1 : 2; break; + case MOUSE_UTF8_MODE: + ans = self->modes.mouse_tracking_protocol == UTF8_PROTOCOL ? 1 : 2; break; + case MOUSE_SGR_PIXEL_MODE: + ans = self->modes.mouse_tracking_protocol == SGR_PIXEL_PROTOCOL ? 1 : 2; break; case PENDING_UPDATE: ans = self->pending_mode.activated_at ? 1 : 2; break; }