From 20f0334e1314508683651b0e5c59fd637d1d13f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 11 Aug 2020 09:55:33 +0200 Subject: [PATCH] config: add mouse specific bind actions This extends the "normal" bind action enum with mouse specific actions. When parsing key bindings, we only check up to the last valid keyboard binding, while mouse bindings support *both* key actions and mouse actions. The new actions are: * select-begin: starts an interactive selection * select-extend: interactively extend an existing selection * select-word: select word under cursor * select-word-whitespace: select word under cursor, where the only word separating characters are whitespace characters. The old hard-coded selection "bindings" have been converted to instead use these actions, via default bindings added to the configuration. --- config.c | 24 +++++++++++++++++---- footrc | 4 ++++ input.c | 61 ++++++++++++++++++++++++----------------------------- selection.c | 7 ++++++ terminal.h | 1 + wayland.h | 9 ++++++++ 6 files changed, 68 insertions(+), 38 deletions(-) diff --git a/config.c b/config.c index 8e51b608..69883b68 100644 --- a/config.c +++ b/config.c @@ -69,6 +69,12 @@ static const char *const binding_action_map[] = { [BIND_ACTION_PIPE_SCROLLBACK] = "pipe-scrollback", [BIND_ACTION_PIPE_VIEW] = "pipe-visible", [BIND_ACTION_PIPE_SELECTED] = "pipe-selected", + + /* Mouse-specific actions */ + [BIND_ACTION_SELECT_BEGIN] = "select-begin", + [BIND_ACTION_SELECT_WORD] = "select-word", + [BIND_ACTION_SELECT_WORD_WS] = "select-word-whitespace", + [BIND_ACTION_SELECT_EXTEND] = "select-extend", }; static_assert(ALEN(binding_action_map) == BIND_ACTION_COUNT, @@ -643,7 +649,8 @@ parse_section_csd(const char *key, const char *value, struct config *conf, } else { - LOG_AND_NOTIFY_ERR("%s:%u: [csd]: %s: invalid key", path, lineno, key); + LOG_AND_NOTIFY_ERR("%s:%u: [csd]: %s: invalid action", + path, lineno, key); return false; } @@ -859,7 +866,7 @@ parse_section_key_bindings( } for (enum bind_action_normal action = 0; - action < BIND_ACTION_COUNT; + action < BIND_ACTION_KEY_COUNT; action++) { if (binding_action_map[action] == NULL) @@ -932,7 +939,8 @@ parse_section_key_bindings( return true; } - LOG_AND_NOTIFY_ERR("%s:%u: [key-bindings]: %s: invalid key", path, lineno, key); + LOG_AND_NOTIFY_ERR("%s:%u: [key-bindings]: %s: invalid action", + path, lineno, key); return false; } @@ -1121,7 +1129,10 @@ parse_section_mouse_bindings( const char *key, const char *value, struct config *conf, const char *path, unsigned lineno) { - for (enum bind_action_normal action = 0; action < BIND_ACTION_COUNT; action++) { + for (enum bind_action_normal action = 0; + action < BIND_ACTION_COUNT; + action++) + { if (binding_action_map[action] == NULL) continue; @@ -1519,8 +1530,13 @@ add_default_mouse_bindings(struct config *conf) } while (0) const struct config_key_modifiers none = {}; + const struct config_key_modifiers ctrl = {.ctrl = true}; add_binding(BIND_ACTION_PRIMARY_PASTE, none, BTN_MIDDLE, 1); + add_binding(BIND_ACTION_SELECT_BEGIN, none, BTN_LEFT, 1); + add_binding(BIND_ACTION_SELECT_WORD, none, BTN_LEFT, 2); + add_binding(BIND_ACTION_SELECT_WORD_WS, ctrl, BTN_LEFT, 2); + add_binding(BIND_ACTION_SELECT_EXTEND, none, BTN_RIGHT, 1); #undef add_binding } diff --git a/footrc b/footrc index ec36bbc1..062b9177 100644 --- a/footrc +++ b/footrc @@ -93,3 +93,7 @@ [mouse-bindings] # primary-paste=BTN_MIDDLE +# select-begin=BTN_LEFT +# select-word=BTN_LEFT-2 +# select-word-whitespace=Control+BTN_LEFT-2 +# select-extend=BTN_RIGHT diff --git a/input.c b/input.c index b7c5031a..9e260e69 100644 --- a/input.c +++ b/input.c @@ -254,6 +254,31 @@ execute_binding(struct seat *seat, struct terminal *term, break; } + case BIND_ACTION_SELECT_BEGIN: + selection_start( + term, seat->mouse.col, seat->mouse.row, + seat->kbd.ctrl ? SELECTION_BLOCK : SELECTION_NORMAL); + break; + + case BIND_ACTION_SELECT_WORD: + selection_mark_word( + seat, term, seat->mouse.col, seat->mouse.row, false, serial); + break; + + case BIND_ACTION_SELECT_WORD_WS: + selection_mark_word( + seat, term, seat->mouse.col, seat->mouse.row, true, serial); + break; + + case BIND_ACTION_SELECT_EXTEND: { + bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0; + if (selection_enabled(term, seat) && cursor_is_on_grid) { + selection_extend( + seat, term, seat->mouse.col, seat->mouse.row, serial); + } + break; + } + case BIND_ACTION_COUNT: assert(false); break; @@ -1442,38 +1467,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, switch (state) { case WL_POINTER_BUTTON_STATE_PRESSED: { - if (button == BTN_LEFT && seat->mouse.count <= 3 && mods == 0) { - selection_cancel(term); - - if (selection_enabled(term, seat) && cursor_is_on_grid) { - switch (seat->mouse.count) { - case 1: - selection_start( - term, seat->mouse.col, seat->mouse.row, - seat->kbd.ctrl ? SELECTION_BLOCK : SELECTION_NORMAL); - break; - - case 2: - selection_mark_word( - seat, term, seat->mouse.col, seat->mouse.row, - seat->kbd.ctrl, serial); - break; - - case 3: - selection_mark_row(seat, term, seat->mouse.row, serial); - break; - } - } - } - - else if (button == BTN_RIGHT && seat->mouse.count == 1 && mods == 0) { - if (selection_enabled(term, seat) && cursor_is_on_grid) { - selection_extend( - seat, term, seat->mouse.col, seat->mouse.row, serial); - } - } - - else if (seat->wl_keyboard != NULL) { + if (seat->wl_keyboard != NULL) { /* Seat has keyboard - use mouse bindings *with* modifiers */ tll_foreach(seat->mouse.bindings, it) { const struct mouse_binding *binding = &it->item; @@ -1533,8 +1527,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, } case WL_POINTER_BUTTON_STATE_RELEASED: - if (button == BTN_LEFT && term->selection.end.col != -1) - selection_finalize(seat, term, serial); + selection_finalize(seat, term, serial); if (!term_mouse_grabbed(term, seat) && cursor_is_on_grid) { term_mouse_up( diff --git a/selection.c b/selection.c index a078a698..3eadf2ea 100644 --- a/selection.c +++ b/selection.c @@ -237,6 +237,7 @@ selection_start(struct terminal *term, int col, int row, term->selection.kind = kind; term->selection.start = (struct coord){col, term->grid->view + row}; term->selection.end = (struct coord){-1, -1}; + term->selection.ongoing = true; } static bool @@ -566,6 +567,11 @@ selection_finalize(struct seat *seat, struct terminal *term, uint32_t serial) if (term->selection.start.row < 0 || term->selection.end.row < 0) return; + if (!term->selection.ongoing) + return; + + term->selection.ongoing = false; + assert(term->selection.start.row != -1); assert(term->selection.end.row != -1); @@ -600,6 +606,7 @@ selection_cancel(struct terminal *term) term->selection.start = (struct coord){-1, -1}; term->selection.end = (struct coord){-1, -1}; term->selection.direction = SELECTION_UNDIR; + term->selection.ongoing = false; } void diff --git a/terminal.h b/terminal.h index 8509634a..2f2d8881 100644 --- a/terminal.h +++ b/terminal.h @@ -311,6 +311,7 @@ struct terminal { enum selection_direction direction; struct coord start; struct coord end; + bool ongoing; } selection; bool is_searching; diff --git a/wayland.h b/wayland.h index b08c25fd..b7528a7f 100644 --- a/wayland.h +++ b/wayland.h @@ -42,6 +42,15 @@ enum bind_action_normal { BIND_ACTION_PIPE_SCROLLBACK, BIND_ACTION_PIPE_VIEW, BIND_ACTION_PIPE_SELECTED, + + BIND_ACTION_KEY_COUNT = BIND_ACTION_PIPE_SELECTED, + + /* Mouse specific actions - i.e. they require a mouse coordinate */ + BIND_ACTION_SELECT_BEGIN, + BIND_ACTION_SELECT_WORD, + BIND_ACTION_SELECT_WORD_WS, + BIND_ACTION_SELECT_EXTEND, + BIND_ACTION_COUNT, };