mirror of
https://github.com/tmux/tmux.git
synced 2025-01-07 16:28:48 +00:00
Support double and triple clicks (they are cumulative, so double is
fired then triple), and use for select-word and select-line in copy mode. Inspired by a different solution from Omar Sandoval.
This commit is contained in:
parent
76d6d3641f
commit
85d7afaefc
@ -263,6 +263,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode MouseDragEnd1Pane send -X copy-selection-and-cancel",
|
"bind -Tcopy-mode MouseDragEnd1Pane send -X copy-selection-and-cancel",
|
||||||
"bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up",
|
"bind -Tcopy-mode WheelUpPane send -N5 -X scroll-up",
|
||||||
"bind -Tcopy-mode WheelDownPane send -N5 -X scroll-down",
|
"bind -Tcopy-mode WheelDownPane send -N5 -X scroll-down",
|
||||||
|
"bind -Tcopy-mode DoubleClick1Pane send -X select-word",
|
||||||
|
"bind -Tcopy-mode TripleClick1Pane send -X select-line",
|
||||||
"bind -Tcopy-mode NPage send -X page-down",
|
"bind -Tcopy-mode NPage send -X page-down",
|
||||||
"bind -Tcopy-mode PPage send -X page-up",
|
"bind -Tcopy-mode PPage send -X page-up",
|
||||||
"bind -Tcopy-mode Up send -X cursor-up",
|
"bind -Tcopy-mode Up send -X cursor-up",
|
||||||
@ -359,6 +361,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel",
|
"bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel",
|
||||||
"bind -Tcopy-mode-vi WheelUpPane send -N5 -X scroll-up",
|
"bind -Tcopy-mode-vi WheelUpPane send -N5 -X scroll-up",
|
||||||
"bind -Tcopy-mode-vi WheelDownPane send -N5 -X scroll-down",
|
"bind -Tcopy-mode-vi WheelDownPane send -N5 -X scroll-down",
|
||||||
|
"bind -Tcopy-mode-vi DoubleClick1Pane send -X select-word",
|
||||||
|
"bind -Tcopy-mode-vi TripleClick1Pane send -X select-line",
|
||||||
"bind -Tcopy-mode-vi BSpace send -X cursor-left",
|
"bind -Tcopy-mode-vi BSpace send -X cursor-left",
|
||||||
"bind -Tcopy-mode-vi NPage send -X page-down",
|
"bind -Tcopy-mode-vi NPage send -X page-down",
|
||||||
"bind -Tcopy-mode-vi PPage send -X page-up",
|
"bind -Tcopy-mode-vi PPage send -X page-up",
|
||||||
|
@ -98,6 +98,12 @@ static const struct {
|
|||||||
KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
|
KEYC_MOUSE_STRING(MOUSEDRAGEND3, MouseDragEnd3),
|
||||||
KEYC_MOUSE_STRING(WHEELUP, WheelUp),
|
KEYC_MOUSE_STRING(WHEELUP, WheelUp),
|
||||||
KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
|
KEYC_MOUSE_STRING(WHEELDOWN, WheelDown),
|
||||||
|
KEYC_MOUSE_STRING(DOUBLECLICK1, DoubleClick1),
|
||||||
|
KEYC_MOUSE_STRING(DOUBLECLICK2, DoubleClick2),
|
||||||
|
KEYC_MOUSE_STRING(DOUBLECLICK3, DoubleClick3),
|
||||||
|
KEYC_MOUSE_STRING(TRIPLECLICK1, TripleClick1),
|
||||||
|
KEYC_MOUSE_STRING(TRIPLECLICK2, TripleClick2),
|
||||||
|
KEYC_MOUSE_STRING(TRIPLECLICK3, TripleClick3),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Find key string in table. */
|
/* Find key string in table. */
|
||||||
|
121
server-client.c
121
server-client.c
@ -37,6 +37,7 @@ static void server_client_check_focus(struct window_pane *);
|
|||||||
static void server_client_check_resize(struct window_pane *);
|
static void server_client_check_resize(struct window_pane *);
|
||||||
static key_code server_client_check_mouse(struct client *);
|
static key_code server_client_check_mouse(struct client *);
|
||||||
static void server_client_repeat_timer(int, short, void *);
|
static void server_client_repeat_timer(int, short, void *);
|
||||||
|
static void server_client_click_timer(int, short, void *);
|
||||||
static void server_client_check_exit(struct client *);
|
static void server_client_check_exit(struct client *);
|
||||||
static void server_client_check_redraw(struct client *);
|
static void server_client_check_redraw(struct client *);
|
||||||
static void server_client_set_title(struct client *);
|
static void server_client_set_title(struct client *);
|
||||||
@ -155,6 +156,7 @@ server_client_create(int fd)
|
|||||||
c->keytable->references++;
|
c->keytable->references++;
|
||||||
|
|
||||||
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
|
evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
|
||||||
|
evtimer_set(&c->click_timer, server_client_click_timer, c);
|
||||||
|
|
||||||
TAILQ_INSERT_TAIL(&clients, c, entry);
|
TAILQ_INSERT_TAIL(&clients, c, entry);
|
||||||
log_debug("new client %p", c);
|
log_debug("new client %p", c);
|
||||||
@ -223,6 +225,7 @@ server_client_lost(struct client *c)
|
|||||||
free((void *)c->cwd);
|
free((void *)c->cwd);
|
||||||
|
|
||||||
evtimer_del(&c->repeat_timer);
|
evtimer_del(&c->repeat_timer);
|
||||||
|
evtimer_del(&c->click_timer);
|
||||||
|
|
||||||
key_bindings_unref_table(c->keytable);
|
key_bindings_unref_table(c->keytable);
|
||||||
|
|
||||||
@ -299,14 +302,16 @@ server_client_detach(struct client *c, enum msgtype msgtype)
|
|||||||
static key_code
|
static key_code
|
||||||
server_client_check_mouse(struct client *c)
|
server_client_check_mouse(struct client *c)
|
||||||
{
|
{
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct mouse_event *m = &c->tty.mouse;
|
struct mouse_event *m = &c->tty.mouse;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
enum { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE;
|
u_int x, y, b;
|
||||||
enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE;
|
int flag;
|
||||||
u_int x, y, b;
|
key_code key;
|
||||||
key_code key;
|
struct timeval tv;
|
||||||
|
enum { NOTYPE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type = NOTYPE;
|
||||||
|
enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE;
|
||||||
|
|
||||||
log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y,
|
log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y,
|
||||||
m->lx, m->ly, c->tty.mouse_drag_flag);
|
m->lx, m->ly, c->tty.mouse_drag_flag);
|
||||||
@ -330,10 +335,45 @@ server_client_check_mouse(struct client *c)
|
|||||||
x = m->x, y = m->y, b = m->lb;
|
x = m->x, y = m->y, b = m->lb;
|
||||||
log_debug("up at %u,%u", x, y);
|
log_debug("up at %u,%u", x, y);
|
||||||
} else {
|
} else {
|
||||||
|
if (c->flags & CLIENT_DOUBLECLICK) {
|
||||||
|
evtimer_del(&c->click_timer);
|
||||||
|
c->flags &= ~CLIENT_DOUBLECLICK;
|
||||||
|
if (m->b == c->click_button) {
|
||||||
|
type = DOUBLE;
|
||||||
|
x = m->x, y = m->y, b = m->b;
|
||||||
|
log_debug("double-click at %u,%u", x, y);
|
||||||
|
flag = CLIENT_TRIPLECLICK;
|
||||||
|
goto add_timer;
|
||||||
|
}
|
||||||
|
} else if (c->flags & CLIENT_TRIPLECLICK) {
|
||||||
|
evtimer_del(&c->click_timer);
|
||||||
|
c->flags &= ~CLIENT_TRIPLECLICK;
|
||||||
|
if (m->b == c->click_button) {
|
||||||
|
type = TRIPLE;
|
||||||
|
x = m->x, y = m->y, b = m->b;
|
||||||
|
log_debug("triple-click at %u,%u", x, y);
|
||||||
|
goto have_event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type = DOWN;
|
type = DOWN;
|
||||||
x = m->x, y = m->y, b = m->b;
|
x = m->x, y = m->y, b = m->b;
|
||||||
log_debug("down at %u,%u", x, y);
|
log_debug("down at %u,%u", x, y);
|
||||||
|
flag = CLIENT_DOUBLECLICK;
|
||||||
|
|
||||||
|
add_timer:
|
||||||
|
if (KEYC_CLICK_TIMEOUT != 0) {
|
||||||
|
c->flags |= flag;
|
||||||
|
c->click_button = m->b;
|
||||||
|
|
||||||
|
tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000;
|
||||||
|
tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L;
|
||||||
|
evtimer_del(&c->click_timer);
|
||||||
|
evtimer_add(&c->click_timer, &tv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
have_event:
|
||||||
if (type == NOTYPE)
|
if (type == NOTYPE)
|
||||||
return (KEYC_UNKNOWN);
|
return (KEYC_UNKNOWN);
|
||||||
|
|
||||||
@ -546,6 +586,62 @@ server_client_check_mouse(struct client *c)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
switch (MOUSE_BUTTONS(b)) {
|
||||||
|
case 0:
|
||||||
|
if (where == PANE)
|
||||||
|
key = KEYC_DOUBLECLICK1_PANE;
|
||||||
|
if (where == STATUS)
|
||||||
|
key = KEYC_DOUBLECLICK1_STATUS;
|
||||||
|
if (where == BORDER)
|
||||||
|
key = KEYC_DOUBLECLICK1_BORDER;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (where == PANE)
|
||||||
|
key = KEYC_DOUBLECLICK2_PANE;
|
||||||
|
if (where == STATUS)
|
||||||
|
key = KEYC_DOUBLECLICK2_STATUS;
|
||||||
|
if (where == BORDER)
|
||||||
|
key = KEYC_DOUBLECLICK2_BORDER;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (where == PANE)
|
||||||
|
key = KEYC_DOUBLECLICK3_PANE;
|
||||||
|
if (where == STATUS)
|
||||||
|
key = KEYC_DOUBLECLICK3_STATUS;
|
||||||
|
if (where == BORDER)
|
||||||
|
key = KEYC_DOUBLECLICK3_BORDER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TRIPLE:
|
||||||
|
switch (MOUSE_BUTTONS(b)) {
|
||||||
|
case 0:
|
||||||
|
if (where == PANE)
|
||||||
|
key = KEYC_TRIPLECLICK1_PANE;
|
||||||
|
if (where == STATUS)
|
||||||
|
key = KEYC_TRIPLECLICK1_STATUS;
|
||||||
|
if (where == BORDER)
|
||||||
|
key = KEYC_TRIPLECLICK1_BORDER;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (where == PANE)
|
||||||
|
key = KEYC_TRIPLECLICK2_PANE;
|
||||||
|
if (where == STATUS)
|
||||||
|
key = KEYC_TRIPLECLICK2_STATUS;
|
||||||
|
if (where == BORDER)
|
||||||
|
key = KEYC_TRIPLECLICK2_BORDER;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (where == PANE)
|
||||||
|
key = KEYC_TRIPLECLICK3_PANE;
|
||||||
|
if (where == STATUS)
|
||||||
|
key = KEYC_TRIPLECLICK3_STATUS;
|
||||||
|
if (where == BORDER)
|
||||||
|
key = KEYC_TRIPLECLICK3_BORDER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (key == KEYC_UNKNOWN)
|
if (key == KEYC_UNKNOWN)
|
||||||
return (KEYC_UNKNOWN);
|
return (KEYC_UNKNOWN);
|
||||||
@ -945,6 +1041,15 @@ server_client_repeat_timer(__unused int fd, __unused short events, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Double-click callback. */
|
||||||
|
static void
|
||||||
|
server_client_click_timer(__unused int fd, __unused short events, void *data)
|
||||||
|
{
|
||||||
|
struct client *c = data;
|
||||||
|
|
||||||
|
c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if client should be exited. */
|
/* Check if client should be exited. */
|
||||||
static void
|
static void
|
||||||
server_client_check_exit(struct client *c)
|
server_client_check_exit(struct client *c)
|
||||||
|
4
tmux.1
4
tmux.1
@ -3334,10 +3334,12 @@ for a pane border or
|
|||||||
for the status line).
|
for the status line).
|
||||||
The following mouse events are available:
|
The following mouse events are available:
|
||||||
.Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent
|
.Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent
|
||||||
|
.It Li "WheelUp" Ta "WheelDown" Ta ""
|
||||||
.It Li "MouseDown1" Ta "MouseUp1" Ta "MouseDrag1" Ta "MouseDragEnd1"
|
.It Li "MouseDown1" Ta "MouseUp1" Ta "MouseDrag1" Ta "MouseDragEnd1"
|
||||||
.It Li "MouseDown2" Ta "MouseUp2" Ta "MouseDrag2" Ta "MouseDragEnd2"
|
.It Li "MouseDown2" Ta "MouseUp2" Ta "MouseDrag2" Ta "MouseDragEnd2"
|
||||||
.It Li "MouseDown3" Ta "MouseUp3" Ta "MouseDrag3" Ta "MouseDragEnd3"
|
.It Li "MouseDown3" Ta "MouseUp3" Ta "MouseDrag3" Ta "MouseDragEnd3"
|
||||||
.It Li "WheelUp" Ta "WheelDown" Ta "" Ta ""
|
.It Li "DoubleClick1" Ta "DoubleClick2" Ta "DoubleClick3" Ta "WheelUp"
|
||||||
|
.It Li "TripleClick1" Ta "TripleClick2" Ta "TripleClick3" Ta "WheelDown"
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Each should be suffixed with a location, for example
|
Each should be suffixed with a location, for example
|
||||||
|
14
tmux.h
14
tmux.h
@ -105,6 +105,9 @@ struct tmuxproc;
|
|||||||
#define KEYC_IS_MOUSE(key) (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \
|
#define KEYC_IS_MOUSE(key) (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \
|
||||||
((key) & KEYC_MASK_KEY) < KEYC_BSPACE)
|
((key) & KEYC_MASK_KEY) < KEYC_BSPACE)
|
||||||
|
|
||||||
|
/* Multiple click timeout. */
|
||||||
|
#define KEYC_CLICK_TIMEOUT 300
|
||||||
|
|
||||||
/* Mouse key codes. */
|
/* Mouse key codes. */
|
||||||
#define KEYC_MOUSE_KEY(name) \
|
#define KEYC_MOUSE_KEY(name) \
|
||||||
KEYC_ ## name ## _PANE, \
|
KEYC_ ## name ## _PANE, \
|
||||||
@ -143,6 +146,12 @@ enum {
|
|||||||
KEYC_MOUSE_KEY(MOUSEDRAGEND3),
|
KEYC_MOUSE_KEY(MOUSEDRAGEND3),
|
||||||
KEYC_MOUSE_KEY(WHEELUP),
|
KEYC_MOUSE_KEY(WHEELUP),
|
||||||
KEYC_MOUSE_KEY(WHEELDOWN),
|
KEYC_MOUSE_KEY(WHEELDOWN),
|
||||||
|
KEYC_MOUSE_KEY(DOUBLECLICK1),
|
||||||
|
KEYC_MOUSE_KEY(DOUBLECLICK2),
|
||||||
|
KEYC_MOUSE_KEY(DOUBLECLICK3),
|
||||||
|
KEYC_MOUSE_KEY(TRIPLECLICK1),
|
||||||
|
KEYC_MOUSE_KEY(TRIPLECLICK2),
|
||||||
|
KEYC_MOUSE_KEY(TRIPLECLICK3),
|
||||||
|
|
||||||
/* Backspace key. */
|
/* Backspace key. */
|
||||||
KEYC_BSPACE,
|
KEYC_BSPACE,
|
||||||
@ -1216,6 +1225,9 @@ struct client {
|
|||||||
|
|
||||||
struct event repeat_timer;
|
struct event repeat_timer;
|
||||||
|
|
||||||
|
struct event click_timer;
|
||||||
|
u_int click_button;
|
||||||
|
|
||||||
struct event status_timer;
|
struct event status_timer;
|
||||||
struct screen status;
|
struct screen status;
|
||||||
|
|
||||||
@ -1239,6 +1251,8 @@ struct client {
|
|||||||
#define CLIENT_256COLOURS 0x20000
|
#define CLIENT_256COLOURS 0x20000
|
||||||
#define CLIENT_IDENTIFIED 0x40000
|
#define CLIENT_IDENTIFIED 0x40000
|
||||||
#define CLIENT_STATUSFORCE 0x80000
|
#define CLIENT_STATUSFORCE 0x80000
|
||||||
|
#define CLIENT_DOUBLECLICK 0x100000
|
||||||
|
#define CLIENT_TRIPLECLICK 0x200000
|
||||||
int flags;
|
int flags;
|
||||||
struct key_table *keytable;
|
struct key_table *keytable;
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ void window_copy_cursor_previous_word(struct window_pane *, const char *);
|
|||||||
void window_copy_scroll_up(struct window_pane *, u_int);
|
void window_copy_scroll_up(struct window_pane *, u_int);
|
||||||
void window_copy_scroll_down(struct window_pane *, u_int);
|
void window_copy_scroll_down(struct window_pane *, u_int);
|
||||||
void window_copy_rectangle_toggle(struct window_pane *);
|
void window_copy_rectangle_toggle(struct window_pane *);
|
||||||
|
void window_copy_move_mouse(struct mouse_event *);
|
||||||
void window_copy_drag_update(struct client *, struct mouse_event *);
|
void window_copy_drag_update(struct client *, struct mouse_event *);
|
||||||
void window_copy_drag_release(struct client *, struct mouse_event *);
|
void window_copy_drag_release(struct client *, struct mouse_event *);
|
||||||
|
|
||||||
@ -479,6 +480,9 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
|
|||||||
return;
|
return;
|
||||||
command = args->argv[0];
|
command = args->argv[0];
|
||||||
|
|
||||||
|
if (m != NULL && m->valid)
|
||||||
|
window_copy_move_mouse(m);
|
||||||
|
|
||||||
if (args->argc == 1) {
|
if (args->argc == 1) {
|
||||||
if (strcmp(command, "append-selection") == 0) {
|
if (strcmp(command, "append-selection") == 0) {
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
@ -731,9 +735,17 @@ window_copy_command(struct window_pane *wp, struct client *c, struct session *s,
|
|||||||
window_copy_cursor_end_of_line(wp);
|
window_copy_cursor_end_of_line(wp);
|
||||||
window_copy_redraw_screen(wp);
|
window_copy_redraw_screen(wp);
|
||||||
}
|
}
|
||||||
if (strcmp(command, "start-of-line") == 0) {
|
if (strcmp(command, "select-word") == 0) {
|
||||||
window_copy_cursor_start_of_line(wp);
|
sn->sel.lineflag = LINE_SEL_LEFT_RIGHT;
|
||||||
|
data->rectflag = 0;
|
||||||
|
ws = options_get_string(s->options, "word-separators");
|
||||||
|
window_copy_cursor_previous_word(wp, ws);
|
||||||
|
window_copy_start_selection(wp);
|
||||||
|
window_copy_cursor_next_word_end(wp, ws);
|
||||||
|
window_copy_redraw_screen(wp);
|
||||||
}
|
}
|
||||||
|
if (strcmp(command, "start-of-line") == 0)
|
||||||
|
window_copy_cursor_start_of_line(wp);
|
||||||
if (strcmp(command, "top-line") == 0) {
|
if (strcmp(command, "top-line") == 0) {
|
||||||
data->cx = 0;
|
data->cx = 0;
|
||||||
data->cy = 0;
|
data->cy = 0;
|
||||||
@ -2105,6 +2117,22 @@ window_copy_rectangle_toggle(struct window_pane *wp)
|
|||||||
window_copy_redraw_screen(wp);
|
window_copy_redraw_screen(wp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
window_copy_move_mouse(struct mouse_event *m)
|
||||||
|
{
|
||||||
|
struct window_pane *wp;
|
||||||
|
u_int x, y;
|
||||||
|
|
||||||
|
wp = cmd_mouse_pane(m, NULL, NULL);
|
||||||
|
if (wp == NULL || wp->mode != &window_copy_mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cmd_mouse_at(wp, m, &x, &y, 1) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
window_copy_update_cursor(wp, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
window_copy_start_drag(struct client *c, struct mouse_event *m)
|
window_copy_start_drag(struct client *c, struct mouse_event *m)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user