mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-06 01:40:22 -05:00
commit
e8a8d122f0
9 changed files with 273 additions and 71 deletions
|
|
@ -74,6 +74,10 @@
|
||||||
timing can be tweaked, or completely disabled, by setting
|
timing can be tweaked, or completely disabled, by setting
|
||||||
`resize-delay-ms` (https://codeberg.org/dnkl/foot/issues/301).
|
`resize-delay-ms` (https://codeberg.org/dnkl/foot/issues/301).
|
||||||
* `CSI 13 ; 2 t` now reports (0,0).
|
* `CSI 13 ; 2 t` now reports (0,0).
|
||||||
|
* Key binding matching logic; key combinations like `Control+Shift+C`
|
||||||
|
**must** now be written as either `Control+C` or `Control+Shift+c`,
|
||||||
|
the latter being the preferred
|
||||||
|
variant. (https://codeberg.org/dnkl/foot/issues/376)
|
||||||
|
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
|
||||||
38
config.c
38
config.c
|
|
@ -1168,6 +1168,7 @@ out:
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_key_combos(struct config *conf, const char *combos, key_combo_list_t *key_combos,
|
parse_key_combos(struct config *conf, const char *combos, key_combo_list_t *key_combos,
|
||||||
|
const char *section, const char *option,
|
||||||
const char *path, unsigned lineno)
|
const char *path, unsigned lineno)
|
||||||
{
|
{
|
||||||
xassert(tll_length(*key_combos) == 0);
|
xassert(tll_length(*key_combos) == 0);
|
||||||
|
|
@ -1179,7 +1180,7 @@ parse_key_combos(struct config *conf, const char *combos, key_combo_list_t *key_
|
||||||
combo = strtok_r(NULL, " ", &tok_ctx))
|
combo = strtok_r(NULL, " ", &tok_ctx))
|
||||||
{
|
{
|
||||||
struct config_key_modifiers modifiers = {0};
|
struct config_key_modifiers modifiers = {0};
|
||||||
const char *key = strrchr(combo, '+');
|
char *key = strrchr(combo, '+');
|
||||||
|
|
||||||
if (key == NULL) {
|
if (key == NULL) {
|
||||||
/* No modifiers */
|
/* No modifiers */
|
||||||
|
|
@ -1190,11 +1191,27 @@ parse_key_combos(struct config *conf, const char *combos, key_combo_list_t *key_
|
||||||
key++; /* Skip past the '+' */
|
key++; /* Skip past the '+' */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (modifiers.shift && strlen(key) == 1 && (*key >= 'A' && *key <= 'Z')) {
|
||||||
|
LOG_WARN(
|
||||||
|
"%s:%d: [%s]: %s: %s: "
|
||||||
|
"upper case keys not supported with explicit 'Shift' modifier",
|
||||||
|
path, lineno, section, option, combo);
|
||||||
|
user_notification_add(
|
||||||
|
&conf->notifications, USER_NOTIFICATION_DEPRECATED,
|
||||||
|
"%s:%d: [%s]: %s: \033[1m%s\033[m: "
|
||||||
|
"shifted keys not supported with explicit \033[1mShift\033[m "
|
||||||
|
"modifier",
|
||||||
|
path, lineno, section, option, combo);
|
||||||
|
*key = *key - 'A' + 'a';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* Translate key name to symbol */
|
/* Translate key name to symbol */
|
||||||
xkb_keysym_t sym = xkb_keysym_from_name(key, 0);
|
xkb_keysym_t sym = xkb_keysym_from_name(key, 0);
|
||||||
if (sym == XKB_KEY_NoSymbol) {
|
if (sym == XKB_KEY_NoSymbol) {
|
||||||
LOG_AND_NOTIFY_ERR("%s:%d: %s: key is not a valid XKB key name",
|
LOG_AND_NOTIFY_ERR(
|
||||||
path, lineno, key);
|
"%s:%d: [%s]: %s: ]%s: key is not a valid XKB key name",
|
||||||
|
path, lineno, section, option, key);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1373,7 +1390,8 @@ parse_key_binding_section(
|
||||||
}
|
}
|
||||||
|
|
||||||
key_combo_list_t key_combos = tll_init();
|
key_combo_list_t key_combos = tll_init();
|
||||||
if (!parse_key_combos(conf, value, &key_combos, path, lineno) ||
|
if (!parse_key_combos(
|
||||||
|
conf, value, &key_combos, section, key, path, lineno) ||
|
||||||
has_key_binding_collisions(
|
has_key_binding_collisions(
|
||||||
conf, action, binding_action_map, bindings, &key_combos,
|
conf, action, binding_action_map, bindings, &key_combos,
|
||||||
path, lineno))
|
path, lineno))
|
||||||
|
|
@ -2040,10 +2058,10 @@ add_default_key_bindings(struct config *conf)
|
||||||
|
|
||||||
add_binding(BIND_ACTION_SCROLLBACK_UP_PAGE, shift, XKB_KEY_Page_Up);
|
add_binding(BIND_ACTION_SCROLLBACK_UP_PAGE, shift, XKB_KEY_Page_Up);
|
||||||
add_binding(BIND_ACTION_SCROLLBACK_DOWN_PAGE, shift, XKB_KEY_Page_Down);
|
add_binding(BIND_ACTION_SCROLLBACK_DOWN_PAGE, shift, XKB_KEY_Page_Down);
|
||||||
add_binding(BIND_ACTION_CLIPBOARD_COPY, ctrl_shift, XKB_KEY_C);
|
add_binding(BIND_ACTION_CLIPBOARD_COPY, ctrl_shift, XKB_KEY_c);
|
||||||
add_binding(BIND_ACTION_CLIPBOARD_PASTE, ctrl_shift, XKB_KEY_V);
|
add_binding(BIND_ACTION_CLIPBOARD_PASTE, ctrl_shift, XKB_KEY_v);
|
||||||
add_binding(BIND_ACTION_PRIMARY_PASTE, shift, XKB_KEY_Insert);
|
add_binding(BIND_ACTION_PRIMARY_PASTE, shift, XKB_KEY_Insert);
|
||||||
add_binding(BIND_ACTION_SEARCH_START, ctrl_shift, XKB_KEY_R);
|
add_binding(BIND_ACTION_SEARCH_START, ctrl_shift, XKB_KEY_r);
|
||||||
add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_plus);
|
add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_plus);
|
||||||
add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_equal);
|
add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_equal);
|
||||||
add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_KP_Add);
|
add_binding(BIND_ACTION_FONT_SIZE_UP, ctrl, XKB_KEY_KP_Add);
|
||||||
|
|
@ -2051,8 +2069,8 @@ add_default_key_bindings(struct config *conf)
|
||||||
add_binding(BIND_ACTION_FONT_SIZE_DOWN, ctrl, XKB_KEY_KP_Subtract);
|
add_binding(BIND_ACTION_FONT_SIZE_DOWN, ctrl, XKB_KEY_KP_Subtract);
|
||||||
add_binding(BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_0);
|
add_binding(BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_0);
|
||||||
add_binding(BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_KP_0);
|
add_binding(BIND_ACTION_FONT_SIZE_RESET, ctrl, XKB_KEY_KP_0);
|
||||||
add_binding(BIND_ACTION_SPAWN_TERMINAL, ctrl_shift, XKB_KEY_N);
|
add_binding(BIND_ACTION_SPAWN_TERMINAL, ctrl_shift, XKB_KEY_n);
|
||||||
add_binding(BIND_ACTION_SHOW_URLS_LAUNCH, ctrl_shift, XKB_KEY_U);
|
add_binding(BIND_ACTION_SHOW_URLS_LAUNCH, ctrl_shift, XKB_KEY_u);
|
||||||
|
|
||||||
#undef add_binding
|
#undef add_binding
|
||||||
}
|
}
|
||||||
|
|
@ -2097,7 +2115,7 @@ add_default_search_bindings(struct config *conf)
|
||||||
add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, ctrl, XKB_KEY_Delete);
|
add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, ctrl, XKB_KEY_Delete);
|
||||||
add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, alt, XKB_KEY_d);
|
add_binding(BIND_ACTION_SEARCH_DELETE_NEXT_WORD, alt, XKB_KEY_d);
|
||||||
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD, ctrl, XKB_KEY_w);
|
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD, ctrl, XKB_KEY_w);
|
||||||
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD_WS, ctrl_shift, XKB_KEY_W);
|
add_binding(BIND_ACTION_SEARCH_EXTEND_WORD_WS, ctrl_shift, XKB_KEY_w);
|
||||||
add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_v);
|
add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_v);
|
||||||
add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_y);
|
add_binding(BIND_ACTION_SEARCH_CLIPBOARD_PASTE, ctrl, XKB_KEY_y);
|
||||||
add_binding(BIND_ACTION_SEARCH_PRIMARY_PASTE, shift, XKB_KEY_Insert);
|
add_binding(BIND_ACTION_SEARCH_PRIMARY_PASTE, shift, XKB_KEY_Insert);
|
||||||
|
|
|
||||||
|
|
@ -437,9 +437,9 @@ may have one or more key combinations, space separated. Each
|
||||||
combination is on the form _mod1+mod2+key_. The names of the modifiers
|
combination is on the form _mod1+mod2+key_. The names of the modifiers
|
||||||
and the key *must* be valid XKB key names.
|
and the key *must* be valid XKB key names.
|
||||||
|
|
||||||
Note that if *Shift* is one of the modifiers, the _key_ *must* be in
|
Note that if *Shift* is one of the modifiers, the _key_ *must not* be
|
||||||
upper case. For example, *Control+Shift+v* will never trigger, but
|
in upper case. For example, *Control+Shift+V* will never trigger, but
|
||||||
*Control+Shift+V* will.
|
*Control+Shift+v* will.
|
||||||
|
|
||||||
Note that *Alt* is usually called *Mod1*.
|
Note that *Alt* is usually called *Mod1*.
|
||||||
|
|
||||||
|
|
@ -469,17 +469,17 @@ e.g. *search-start=none*.
|
||||||
Scroll down/forward a single line in history. Default: _not set_.
|
Scroll down/forward a single line in history. Default: _not set_.
|
||||||
|
|
||||||
*clipboard-copy*
|
*clipboard-copy*
|
||||||
Copies the current selection into the _clipboard_. Default: _Control+Shift+C_.
|
Copies the current selection into the _clipboard_. Default: _Control+Shift+c_.
|
||||||
|
|
||||||
*clipboard-paste*
|
*clipboard-paste*
|
||||||
Pastes from the _clipboard_. Default: _Control+Shift+V_.
|
Pastes from the _clipboard_. Default: _Control+Shift+v_.
|
||||||
|
|
||||||
*primary-paste*
|
*primary-paste*
|
||||||
Pastes from the _primary selection_. Default: _Shift+Insert_ (also
|
Pastes from the _primary selection_. Default: _Shift+Insert_ (also
|
||||||
defined in *mouse-bindings*).
|
defined in *mouse-bindings*).
|
||||||
|
|
||||||
*search-start*
|
*search-start*
|
||||||
Starts a scrollback/history search. Default: _Control+Shift+R_.
|
Starts a scrollback/history search. Default: _Control+Shift+r_.
|
||||||
|
|
||||||
*font-increase*
|
*font-increase*
|
||||||
Increases the font size by 0.5pt. Default: _Control+plus
|
Increases the font size by 0.5pt. Default: _Control+plus
|
||||||
|
|
@ -495,7 +495,7 @@ e.g. *search-start=none*.
|
||||||
*spawn-terminal*
|
*spawn-terminal*
|
||||||
Spawns a new terminal. If the shell has been configured to emit
|
Spawns a new terminal. If the shell has been configured to emit
|
||||||
the OSC 7 escape sequence, the new terminal will start in the
|
the OSC 7 escape sequence, the new terminal will start in the
|
||||||
current working directory. Default: _Control+Shift+N_.
|
current working directory. Default: _Control+Shift+n_.
|
||||||
|
|
||||||
*minimize*
|
*minimize*
|
||||||
Minimizes the window. Default: _not bound_.
|
Minimizes the window. Default: _not bound_.
|
||||||
|
|
@ -527,7 +527,7 @@ e.g. *search-start=none*.
|
||||||
*show-urls-launch*
|
*show-urls-launch*
|
||||||
Enter URL mode, where all currently visible URLs are tagged with a
|
Enter URL mode, where all currently visible URLs are tagged with a
|
||||||
jump label with a key sequence that will open the URL. Default:
|
jump label with a key sequence that will open the URL. Default:
|
||||||
_Control+Shift+U_.
|
_Control+Shift+u_.
|
||||||
|
|
||||||
*show-urls-copy*
|
*show-urls-copy*
|
||||||
Enter URL mode, where all currently visible URLs are tagged with a
|
Enter URL mode, where all currently visible URLs are tagged with a
|
||||||
|
|
@ -548,7 +548,7 @@ scrollback search mode. The syntax is exactly the same as the regular
|
||||||
*commit*
|
*commit*
|
||||||
Exit search mode and copy current selection into the _primary
|
Exit search mode and copy current selection into the _primary
|
||||||
selection_. Viewport is **not** restored. To copy the selection to
|
selection_. Viewport is **not** restored. To copy the selection to
|
||||||
the regular _clipboard_, use *Control+Shift+C*. Default: _Return_.
|
the regular _clipboard_, use *Control+Shift+c*. Default: _Return_.
|
||||||
|
|
||||||
*find-prev*
|
*find-prev*
|
||||||
Search **backwards** in the scrollback history for the next
|
Search **backwards** in the scrollback history for the next
|
||||||
|
|
@ -602,7 +602,7 @@ scrollback search mode. The syntax is exactly the same as the regular
|
||||||
|
|
||||||
*extend-to-next-whitespace*
|
*extend-to-next-whitespace*
|
||||||
Extend the current selection to the next whitespace. Default:
|
Extend the current selection to the next whitespace. Default:
|
||||||
_Control+Shift+W_.
|
_Control+Shift+w_.
|
||||||
|
|
||||||
*clipboard-paste*
|
*clipboard-paste*
|
||||||
Paste from the _clipboard_ into the search buffer. Default:
|
Paste from the _clipboard_ into the search buffer. Default:
|
||||||
|
|
|
||||||
12
foot.ini
12
foot.ini
|
|
@ -87,21 +87,21 @@
|
||||||
# scrollback-down-page=Shift+Page_Down
|
# scrollback-down-page=Shift+Page_Down
|
||||||
# scrollback-down-half-page=none
|
# scrollback-down-half-page=none
|
||||||
# scrollback-down-line=none
|
# scrollback-down-line=none
|
||||||
# clipboard-copy=Control+Shift+C
|
# clipboard-copy=Control+Shift+c
|
||||||
# clipboard-paste=Control+Shift+V
|
# clipboard-paste=Control+Shift+v
|
||||||
# primary-paste=Shift+Insert
|
# primary-paste=Shift+Insert
|
||||||
# search-start=Control+Shift+R
|
# search-start=Control+Shift+r
|
||||||
# font-increase=Control+plus Control+equal Control+KP_Add
|
# font-increase=Control+plus Control+equal Control+KP_Add
|
||||||
# font-decrease=Control+minus Control+KP_Subtract
|
# font-decrease=Control+minus Control+KP_Subtract
|
||||||
# font-reset=Control+0 Control+KP_0
|
# font-reset=Control+0 Control+KP_0
|
||||||
# spawn-terminal=Control+Shift+N
|
# spawn-terminal=Control+Shift+n
|
||||||
# minimize=none
|
# minimize=none
|
||||||
# maximize=none
|
# maximize=none
|
||||||
# fullscreen=none
|
# fullscreen=none
|
||||||
# pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none
|
# pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none
|
||||||
# pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none
|
# pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none
|
||||||
# pipe-selected=[xargs -r firefox] none
|
# pipe-selected=[xargs -r firefox] none
|
||||||
# show-urls-launch=Control+Shift+U
|
# show-urls-launch=Control+Shift+u
|
||||||
# show-urls-copy=none
|
# show-urls-copy=none
|
||||||
|
|
||||||
[search-bindings]
|
[search-bindings]
|
||||||
|
|
@ -120,7 +120,7 @@
|
||||||
# delete-next=Delete
|
# delete-next=Delete
|
||||||
# delete-next-word=Mod1+d Control+Delete
|
# delete-next-word=Mod1+d Control+Delete
|
||||||
# extend-to-word-boundary=Control+w
|
# extend-to-word-boundary=Control+w
|
||||||
# extend-to-next-whitespace=Control+Shift+W
|
# extend-to-next-whitespace=Control+Shift+w
|
||||||
# clipboard-paste=Control+v Control+y
|
# clipboard-paste=Control+v Control+y
|
||||||
# primary-paste=Shift+Insert
|
# primary-paste=Shift+Insert
|
||||||
|
|
||||||
|
|
|
||||||
193
input.c
193
input.c
|
|
@ -350,20 +350,18 @@ key_codes_for_xkb_sym(struct xkb_keymap *keymap, xkb_keysym_t sym)
|
||||||
xkb_keycode_list_t key_codes = tll_init();
|
xkb_keycode_list_t key_codes = tll_init();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find all key codes that map to the lower case
|
* Find all key codes that map to this symbol.
|
||||||
* version of the symbol.
|
|
||||||
*
|
*
|
||||||
* This allows us to match bindings in other layouts
|
* This allows us to match bindings in other layouts
|
||||||
* too.
|
* too.
|
||||||
*/
|
*/
|
||||||
xkb_keysym_t lower_sym = xkb_keysym_to_lower(sym);
|
|
||||||
struct xkb_state *state = xkb_state_new(keymap);
|
struct xkb_state *state = xkb_state_new(keymap);
|
||||||
|
|
||||||
for (xkb_keycode_t code = xkb_keymap_min_keycode(keymap);
|
for (xkb_keycode_t code = xkb_keymap_min_keycode(keymap);
|
||||||
code <= xkb_keymap_max_keycode(keymap);
|
code <= xkb_keymap_max_keycode(keymap);
|
||||||
code++)
|
code++)
|
||||||
{
|
{
|
||||||
if (xkb_state_key_get_one_sym(state, code) == lower_sym)
|
if (xkb_state_key_get_one_sym(state, code) == sym)
|
||||||
tll_push_back(key_codes, code);
|
tll_push_back(key_codes, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,16 +369,134 @@ key_codes_for_xkb_sym(struct xkb_keymap *keymap, xkb_keysym_t sym)
|
||||||
return key_codes;
|
return key_codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xkb_keysym_t
|
||||||
|
maybe_repair_key_combo(const struct seat *seat,
|
||||||
|
xkb_keysym_t sym, xkb_mod_mask_t mods)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Detect combos containing a shifted symbol and the corresponding
|
||||||
|
* modifier, and replace the shifted symbol with its unshifted
|
||||||
|
* variant.
|
||||||
|
*
|
||||||
|
* For example, the combo is “Control+Shift+U”. In this case,
|
||||||
|
* Shift is the modifier used to “shift” ‘u’ to ‘U’, after which
|
||||||
|
* ‘Shift’ will have been “consumed”. Since we filter out consumed
|
||||||
|
* modifiers when matching key combos, this key combo will never
|
||||||
|
* trigger (we will never be able to match the ‘Shift’ modifier).
|
||||||
|
*
|
||||||
|
* There are two correct variants of the above key combo:
|
||||||
|
* - “Control+U” (upper case ‘U’)
|
||||||
|
* - “Control+Shift+u” (lower case ‘u’)
|
||||||
|
*
|
||||||
|
* What we do here is, for each key *code*, check if there are any
|
||||||
|
* (shifted) levels where it produces ‘sym’. If there are, check
|
||||||
|
* *which* sets of modifiers are needed to produce it, and compare
|
||||||
|
* with ‘mods’.
|
||||||
|
*
|
||||||
|
* If there is at least one common modifier, it means ‘sym’ is a
|
||||||
|
* “shifted” symbol, with the corresponding shifting modifier
|
||||||
|
* explicitly included in the key combo. I.e. the key combo will
|
||||||
|
* never trigger.
|
||||||
|
*
|
||||||
|
* We then proceed and “repair” the key combo by replacing ‘sym’
|
||||||
|
* with the corresponding unshifted symbol.
|
||||||
|
*
|
||||||
|
* To reduce the noise, we ignore all key codes where the shifted
|
||||||
|
* symbol is the same as the unshifted symbol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (xkb_keycode_t code = xkb_keymap_min_keycode(seat->kbd.xkb_keymap);
|
||||||
|
code <= xkb_keymap_max_keycode(seat->kbd.xkb_keymap);
|
||||||
|
code++)
|
||||||
|
{
|
||||||
|
xkb_layout_index_t layout_idx =
|
||||||
|
xkb_state_key_get_layout(seat->kbd.xkb_state, code);
|
||||||
|
|
||||||
|
/* Get all unshifted symbols for this key */
|
||||||
|
const xkb_keysym_t *base_syms = NULL;
|
||||||
|
size_t base_count = xkb_keymap_key_get_syms_by_level(
|
||||||
|
seat->kbd.xkb_keymap, code, layout_idx, 0, &base_syms);
|
||||||
|
|
||||||
|
if (base_count == 0 || sym == base_syms[0]) {
|
||||||
|
/* No unshifted symbols, or unshifted symbol is same as ‘sym’ */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name of the unshifted symbol, for logging */
|
||||||
|
char base_name[100];
|
||||||
|
xkb_keysym_get_name(base_syms[0], base_name, sizeof(base_name));
|
||||||
|
|
||||||
|
/* Iterate all shift levels */
|
||||||
|
for (xkb_level_index_t level_idx = 1;
|
||||||
|
level_idx < xkb_keymap_num_levels_for_key(
|
||||||
|
seat->kbd.xkb_keymap, code, layout_idx);
|
||||||
|
level_idx++) {
|
||||||
|
|
||||||
|
/* Get all symbols for current shift level */
|
||||||
|
const xkb_keysym_t *shifted_syms = NULL;
|
||||||
|
size_t shifted_count = xkb_keymap_key_get_syms_by_level(
|
||||||
|
seat->kbd.xkb_keymap, code,
|
||||||
|
layout_idx, level_idx, &shifted_syms);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < shifted_count; i++) {
|
||||||
|
if (shifted_syms[i] != sym)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Get modifier sets that produces the current shift level */
|
||||||
|
xkb_mod_mask_t mod_masks[16];
|
||||||
|
size_t mod_mask_count = xkb_keymap_key_get_mods_for_level(
|
||||||
|
seat->kbd.xkb_keymap, code, layout_idx, level_idx,
|
||||||
|
mod_masks, ALEN(mod_masks));
|
||||||
|
|
||||||
|
/* Check if key combo’s modifier set intersects */
|
||||||
|
for (size_t j = 0; j < mod_mask_count; j++) {
|
||||||
|
if (!(mod_masks[j] & mods))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char combo[64] = {0};
|
||||||
|
|
||||||
|
for (int k = 0; k < sizeof(xkb_mod_mask_t) * 8; k++) {
|
||||||
|
if (!(mods & (1u << k)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const char *mod_name = xkb_keymap_mod_get_name(
|
||||||
|
seat->kbd.xkb_keymap, k);
|
||||||
|
strcat(combo, mod_name);
|
||||||
|
strcat(combo, "+");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(combo);
|
||||||
|
xkb_keysym_get_name(
|
||||||
|
sym, &combo[len], sizeof(combo) - len);
|
||||||
|
|
||||||
|
LOG_WARN(
|
||||||
|
"%s: combo with both explicit modifier and shifted symbol "
|
||||||
|
"(level=%d, mod-mask=0x%08x), "
|
||||||
|
"replacing with %s",
|
||||||
|
combo, level_idx, mod_masks[j], base_name);
|
||||||
|
|
||||||
|
/* Replace with unshifted symbol */
|
||||||
|
return base_syms[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_key_binding(struct seat *seat,
|
convert_key_binding(const struct seat *seat,
|
||||||
const struct config_key_binding *conf_binding,
|
const struct config_key_binding *conf_binding,
|
||||||
key_binding_list_t *bindings)
|
key_binding_list_t *bindings)
|
||||||
{
|
{
|
||||||
|
xkb_mod_mask_t mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers);
|
||||||
|
xkb_keysym_t sym = maybe_repair_key_combo(seat, conf_binding->sym, mods);
|
||||||
|
|
||||||
struct key_binding binding = {
|
struct key_binding binding = {
|
||||||
.mods = conf_modifiers_to_mask(seat, &conf_binding->modifiers),
|
.mods = mods,
|
||||||
.sym = conf_binding->sym,
|
.sym = sym,
|
||||||
.key_codes = key_codes_for_xkb_sym(
|
.key_codes = key_codes_for_xkb_sym(seat->kbd.xkb_keymap, sym),
|
||||||
seat->kbd.xkb_keymap, conf_binding->sym),
|
|
||||||
.action = conf_binding->action,
|
.action = conf_binding->action,
|
||||||
.pipe_argv = conf_binding->pipe.argv,
|
.pipe_argv = conf_binding->pipe.argv,
|
||||||
};
|
};
|
||||||
|
|
@ -822,20 +938,31 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
||||||
|
|
||||||
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
||||||
seat->kbd.xkb_state, XKB_STATE_MODS_DEPRESSED);
|
seat->kbd.xkb_state, XKB_STATE_MODS_DEPRESSED);
|
||||||
//xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods(seat->kbd.xkb_state, key);
|
xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods(
|
||||||
xkb_mod_mask_t consumed = 0x0;
|
seat->kbd.xkb_state, key);
|
||||||
|
|
||||||
xkb_mod_mask_t significant = ctrl | alt | shift | meta;
|
xkb_mod_mask_t significant = ctrl | alt | shift | meta;
|
||||||
xkb_mod_mask_t effective_mods = mods & ~consumed & significant;
|
mods &= significant;
|
||||||
|
consumed &= significant;
|
||||||
|
|
||||||
|
xkb_layout_index_t layout_idx =
|
||||||
|
xkb_state_key_get_layout(seat->kbd.xkb_state, key);
|
||||||
|
|
||||||
|
const xkb_keysym_t *raw_syms = NULL;
|
||||||
|
size_t raw_count = xkb_keymap_key_get_syms_by_level(
|
||||||
|
seat->kbd.xkb_keymap, key, layout_idx, 0, &raw_syms);
|
||||||
|
|
||||||
if (term->is_searching) {
|
if (term->is_searching) {
|
||||||
if (should_repeat)
|
if (should_repeat)
|
||||||
start_repeater(seat, key);
|
start_repeater(seat, key);
|
||||||
search_input(seat, term, key, sym, effective_mods, serial);
|
search_input(
|
||||||
|
seat, term, key, sym, mods, consumed, raw_syms, raw_count, serial);
|
||||||
return;
|
return;
|
||||||
} else if (urls_mode_is_active(term)) {
|
} else if (urls_mode_is_active(term)) {
|
||||||
if (should_repeat)
|
if (should_repeat)
|
||||||
start_repeater(seat, key);
|
start_repeater(seat, key);
|
||||||
urls_input(seat, term, key, sym, effective_mods, serial);
|
urls_input(
|
||||||
|
seat, term, key, sym, mods, consumed, raw_syms, raw_count, serial);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -853,29 +980,43 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LOG_DBG("%s (%u/0x%x): seat=%s, term=%p, serial=%u, "
|
LOG_DBG("%s (%u/0x%x): seat=%s, term=%p, serial=%u, "
|
||||||
"mod=0x%08x, consumed=0x%08x, significant=0x%08x, "
|
"mods=0x%08x, consumed=0x%08x, repeats=%d",
|
||||||
"effective=0x%08x, repeats=%d",
|
|
||||||
sym_name, sym, sym, seat->name, (void *)term, serial,
|
sym_name, sym, sym, seat->name, (void *)term, serial,
|
||||||
mods, consumed, significant, effective_mods, should_repeat);
|
mods, consumed, should_repeat);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* User configurable bindings
|
* User configurable bindings
|
||||||
*/
|
*/
|
||||||
tll_foreach(seat->kbd.bindings.key, it) {
|
tll_foreach(seat->kbd.bindings.key, it) {
|
||||||
if (it->item.mods != effective_mods)
|
const struct key_binding *bind = &it->item;
|
||||||
|
|
||||||
|
/* Match translated symbol */
|
||||||
|
if (bind->sym == sym &&
|
||||||
|
bind->mods == (mods & ~consumed) &&
|
||||||
|
execute_binding(
|
||||||
|
seat, term, bind->action, bind->pipe_argv, serial))
|
||||||
|
{
|
||||||
|
goto maybe_repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind->mods != mods)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Match symbol */
|
/* Match untranslated symbols */
|
||||||
if (it->item.sym == sym) {
|
for (size_t i = 0; i < raw_count; i++) {
|
||||||
if (execute_binding(seat, term, it->item.action, it->item.pipe_argv, serial))
|
if (bind->sym == raw_syms[i] && execute_binding(
|
||||||
|
seat, term, bind->action, bind->pipe_argv, serial))
|
||||||
|
{
|
||||||
goto maybe_repeat;
|
goto maybe_repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match raw key code */
|
/* Match raw key code */
|
||||||
tll_foreach(it->item.key_codes, code) {
|
tll_foreach(bind->key_codes, code) {
|
||||||
if (code->item == key) {
|
if (code->item == key && execute_binding(
|
||||||
if (execute_binding(seat, term, it->item.action, it->item.pipe_argv, serial))
|
seat, term, bind->action, bind->pipe_argv, serial))
|
||||||
goto maybe_repeat;
|
{
|
||||||
|
goto maybe_repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -972,7 +1113,7 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if (effective_mods & alt) {
|
if (mods & alt) {
|
||||||
/*
|
/*
|
||||||
* When the alt modifier is pressed, we do one out of three things:
|
* When the alt modifier is pressed, we do one out of three things:
|
||||||
*
|
*
|
||||||
|
|
|
||||||
34
search.c
34
search.c
|
|
@ -783,7 +783,9 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
void
|
void
|
||||||
search_input(struct seat *seat, struct terminal *term, uint32_t key,
|
search_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
xkb_keysym_t sym, xkb_mod_mask_t mods, uint32_t serial)
|
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
|
||||||
|
const xkb_keysym_t *raw_syms, size_t raw_count,
|
||||||
|
uint32_t serial)
|
||||||
{
|
{
|
||||||
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x", sym, sym, mods);
|
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x", sym, sym, mods);
|
||||||
|
|
||||||
|
|
@ -795,12 +797,13 @@ search_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
|
|
||||||
/* Key bindings */
|
/* Key bindings */
|
||||||
tll_foreach(seat->kbd.bindings.search, it) {
|
tll_foreach(seat->kbd.bindings.search, it) {
|
||||||
if (it->item.mods != mods)
|
const struct key_binding *bind = &it->item;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Match symbol */
|
/* Match translated symbol */
|
||||||
if (it->item.sym == sym) {
|
if (bind->sym == sym &&
|
||||||
if (execute_binding(seat, term, it->item.action, serial,
|
bind->mods == (mods & ~consumed)) {
|
||||||
|
|
||||||
|
if (execute_binding(seat, term, bind->action, serial,
|
||||||
&update_search_result, &redraw))
|
&update_search_result, &redraw))
|
||||||
{
|
{
|
||||||
goto update_search;
|
goto update_search;
|
||||||
|
|
@ -808,10 +811,25 @@ search_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bind->mods != mods)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Match untranslated symbols */
|
||||||
|
for (size_t i = 0; i < raw_count; i++) {
|
||||||
|
if (bind->sym == raw_syms[i]) {
|
||||||
|
if (execute_binding(seat, term, bind->action, serial,
|
||||||
|
&update_search_result, &redraw))
|
||||||
|
{
|
||||||
|
goto update_search;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Match raw key code */
|
/* Match raw key code */
|
||||||
tll_foreach(it->item.key_codes, code) {
|
tll_foreach(bind->key_codes, code) {
|
||||||
if (code->item == key) {
|
if (code->item == key) {
|
||||||
if (execute_binding(seat, term, it->item.action, serial,
|
if (execute_binding(seat, term, bind->action, serial,
|
||||||
&update_search_result, &redraw))
|
&update_search_result, &redraw))
|
||||||
{
|
{
|
||||||
goto update_search;
|
goto update_search;
|
||||||
|
|
|
||||||
7
search.h
7
search.h
|
|
@ -5,6 +5,9 @@
|
||||||
|
|
||||||
void search_begin(struct terminal *term);
|
void search_begin(struct terminal *term);
|
||||||
void search_cancel(struct terminal *term);
|
void search_cancel(struct terminal *term);
|
||||||
void search_input(struct seat *seat, struct terminal *term, uint32_t key,
|
void search_input(
|
||||||
xkb_keysym_t sym, xkb_mod_mask_t mods, uint32_t serial);
|
struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
|
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
|
||||||
|
const xkb_keysym_t *raw_syms, size_t raw_count,
|
||||||
|
uint32_t serial);
|
||||||
void search_add_chars(struct terminal *term, const char *text, size_t len);
|
void search_add_chars(struct terminal *term, const char *text, size_t len);
|
||||||
|
|
|
||||||
32
url-mode.c
32
url-mode.c
|
|
@ -115,23 +115,36 @@ activate_url(struct seat *seat, struct terminal *term, const struct url *url)
|
||||||
|
|
||||||
void
|
void
|
||||||
urls_input(struct seat *seat, struct terminal *term, uint32_t key,
|
urls_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
xkb_keysym_t sym, xkb_mod_mask_t mods, uint32_t serial)
|
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
|
||||||
|
const xkb_keysym_t *raw_syms, size_t raw_count,
|
||||||
|
uint32_t serial)
|
||||||
{
|
{
|
||||||
/* Key bindings */
|
/* Key bindings */
|
||||||
tll_foreach(seat->kbd.bindings.url, it) {
|
tll_foreach(seat->kbd.bindings.url, it) {
|
||||||
if (it->item.mods != mods)
|
const struct key_binding *bind = &it->item;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Match symbol */
|
/* Match translated symbol */
|
||||||
if (it->item.sym == sym) {
|
if (bind->sym == sym &&
|
||||||
execute_binding(seat, term, it->item.action, serial);
|
bind->mods == (mods & ~consumed))
|
||||||
|
{
|
||||||
|
execute_binding(seat, term, bind->action, serial);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bind->mods != mods)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < raw_count; i++) {
|
||||||
|
if (bind->sym == raw_syms[i]) {
|
||||||
|
execute_binding(seat, term, bind->action, serial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Match raw key code */
|
/* Match raw key code */
|
||||||
tll_foreach(it->item.key_codes, code) {
|
tll_foreach(bind->key_codes, code) {
|
||||||
if (code->item == key) {
|
if (code->item == key) {
|
||||||
execute_binding(seat, term, it->item.action, serial);
|
execute_binding(seat, term, bind->action, serial);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,6 +161,9 @@ urls_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mods & ~consumed)
|
||||||
|
return;
|
||||||
|
|
||||||
wchar_t wc = xkb_state_key_get_utf32(seat->kbd.xkb_state, key);
|
wchar_t wc = xkb_state_key_get_utf32(seat->kbd.xkb_state, key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,6 @@ void urls_render(struct terminal *term);
|
||||||
void urls_reset(struct terminal *term);
|
void urls_reset(struct terminal *term);
|
||||||
|
|
||||||
void urls_input(struct seat *seat, struct terminal *term, uint32_t key,
|
void urls_input(struct seat *seat, struct terminal *term, uint32_t key,
|
||||||
xkb_keysym_t sym, xkb_mod_mask_t mods, uint32_t serial);
|
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
|
||||||
|
const xkb_keysym_t *raw_syms, size_t raw_count,
|
||||||
|
uint32_t serial);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue