Shell integration: Allow sending click events to shells using y co-ordinates relative to prompts

Note that I havent actually tested the implementation, I leave that to
@okapia.

Fixes #9500
This commit is contained in:
Kovid Goyal 2026-02-15 10:12:22 +05:30
parent be325ccfcb
commit 66a9963fe9
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
5 changed files with 29 additions and 8 deletions

View file

@ -222,6 +222,9 @@ Detailed list of changes
- :ac:`goto_session`: Add a ``--active-only`` option to select from only active
sessions (:pull:`9503`)
- Shell integration: Allow sending click events to shells using y co-ordinates
relative to prompts (:iss:`9500`)
0.45.0 [2025-12-24]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -468,13 +468,21 @@ to control its behavior, separated by semi-colons. They are:
this tells kitty that the secondary (PS2) prompt is starting at the
current line.
``click_events=1``
``click_events=1|2``
this tells kitty that the shell is capable of handling
mouse click events. kitty will thus send a click event to the shell when
the user clicks somewhere in the prompt. The shell can then move the cursor
to that position or perform some other appropriate action. Without this,
kitty will instead generate a number of fake key events to move the cursor
to the clicked location, which is not fully robust.
to the clicked location, which is not fully robust. A value of ``1`` will
cause the click events to have absolute y co-ordinates, a value of ``2``
will cause them to have y-coordinates relative to the top line of the
current prompt. In relative mode, y is zero for cells on the top line of
the current prompt. The current prompt here is either the secondary (PS2) or
primary prompt. If the secondary prompt is on the same line or above the
mouse position, then the reported y will be with respect to that, otherwise
with respect to the primary prompt. The click event is encoded in the SGR
encoding from xterm.
kitty also optionally supports sending the cmdline going to be executed with ``<OSC>133;C`` as:

View file

@ -740,14 +740,16 @@ move_cursor_to_mouse_if_at_shell_prompt(Window *w) {
int y = screen_cursor_at_a_shell_prompt(screen);
if (y < 0 || (unsigned)y > w->mouse_pos.cell_y) return false;
if (screen_prompt_supports_click_events(screen)) {
int sz = encode_mouse_event_impl(&w->mouse_pos, SGR_PROTOCOL, 1, PRESS, 0);
bool is_relative;
if (screen_prompt_supports_click_events(screen, &is_relative)) {
MousePosition mpos = w->mouse_pos;
if (is_relative) mpos.cell_y -= y;
int sz = encode_mouse_event_impl(&mpos, SGR_PROTOCOL, 1, PRESS, 0);
if (sz > 0) {
mouse_event_buf[sz] = 0;
write_escape_code_to_child(screen, ESC_CSI, mouse_event_buf);
return true;
}
return false;
} else {
return screen_fake_move_cursor_to_position(screen, w->mouse_pos.cell_x, w->mouse_pos.cell_y);

View file

@ -2318,7 +2318,8 @@ screen_cursor_at_a_shell_prompt(const Screen *self) {
}
bool
screen_prompt_supports_click_events(const Screen *self) {
screen_prompt_supports_click_events(const Screen *self, bool *is_relative) {
*is_relative = (bool) self->prompt_settings.relative_click_events;
return (bool) self->prompt_settings.supports_click_events;
}
@ -3065,7 +3066,13 @@ parse_prompt_mark(Screen *self, char *buf, PromptKind *pk) {
if (strcmp(token, "k=s") == 0) *pk = SECONDARY_PROMPT;
else if (strcmp(token, "redraw=0") == 0) self->prompt_settings.redraws_prompts_at_all = 0;
else if (strcmp(token, "special_key=1") == 0) self->prompt_settings.uses_special_keys_for_cursor_movement = 1;
else if (strcmp(token, "click_events=1") == 0) self->prompt_settings.supports_click_events = 1;
else if (strcmp(token, "click_events=1") == 0) {
self->prompt_settings.supports_click_events = 1;
self->prompt_settings.relative_click_events = 0;
} else if (strcmp(token, "click_events=2") == 0) {
self->prompt_settings.supports_click_events = 1;
self->prompt_settings.relative_click_events = 1;
}
}
}

View file

@ -154,6 +154,7 @@ typedef struct {
unsigned int redraws_prompts_at_all: 1;
unsigned int uses_special_keys_for_cursor_movement: 1;
unsigned int supports_click_events: 1;
unsigned int relative_click_events: 1;
};
unsigned int val;
} prompt_settings;
@ -307,7 +308,7 @@ void screen_modify_other_keys(Screen *self, unsigned, unsigned);
void screen_report_key_encoding_flags(Screen *self);
int screen_detect_url(Screen *screen, unsigned int x, unsigned int y);
int screen_cursor_at_a_shell_prompt(const Screen *);
bool screen_prompt_supports_click_events(const Screen *);
bool screen_prompt_supports_click_events(const Screen *, bool *is_relative);
bool screen_fake_move_cursor_to_position(Screen *, index_type x, index_type y);
bool screen_send_signal_for_key(Screen *, char key);
bool get_line_edge_colors(Screen *self, color_type *left, color_type *right);