search: replace hard-coded key bindings with "user configurable" ones

They aren't really user configurable. At least not yet.

However, with this, we now handle raw key codes just like the normal
key bindings. Meaning, e.g. ctrl+g, ctrl+a, ctrl+e etc now works while
searching with e.g. a russian layout.
This commit is contained in:
Daniel Eklöf 2020-03-18 15:30:14 +01:00
parent a69b818a62
commit 0419156494
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
7 changed files with 238 additions and 177 deletions

View file

@ -455,9 +455,10 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
} }
static bool static bool
verify_key_combo(const struct config *conf, const char *combo, const char *path, unsigned lineno) verify_key_combo(const struct config *conf, const char *combo, const char *path,
unsigned lineno)
{ {
for (enum binding_action action = 0; action < BIND_ACTION_COUNT; action++) { for (enum bind_action_normal action = 0; action < BIND_ACTION_COUNT; action++) {
if (conf->bindings.key[action] == NULL) if (conf->bindings.key[action] == NULL)
continue; continue;
@ -481,8 +482,7 @@ verify_key_combo(const struct config *conf, const char *combo, const char *path,
struct xkb_keymap *keymap = xkb_keymap_new_from_names( struct xkb_keymap *keymap = xkb_keymap_new_from_names(
ctx, &(struct xkb_rule_names){0}, XKB_KEYMAP_COMPILE_NO_FLAGS); ctx, &(struct xkb_rule_names){0}, XKB_KEYMAP_COMPILE_NO_FLAGS);
bool valid_combo = input_parse_key_binding_for_action( bool valid_combo = input_parse_key_binding(keymap, combo, NULL);
keymap, BIND_ACTION_NONE, combo, NULL);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(ctx); xkb_context_unref(ctx);
@ -500,7 +500,7 @@ parse_section_key_bindings(
const char *key, const char *value, struct config *conf, const char *key, const char *value, struct config *conf,
const char *path, unsigned lineno) const char *path, unsigned lineno)
{ {
for (enum binding_action 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) if (binding_action_map[action] == NULL)
continue; continue;
@ -532,7 +532,7 @@ parse_section_mouse_bindings(
const char *key, const char *value, struct config *conf, const char *key, const char *value, struct config *conf,
const char *path, unsigned lineno) const char *path, unsigned lineno)
{ {
for (enum binding_action 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) if (binding_action_map[action] == NULL)
continue; continue;
@ -562,7 +562,7 @@ parse_section_mouse_bindings(
const int count = 1; const int count = 1;
/* Make sure button isn't already mapped to another action */ /* Make sure button isn't already mapped to another action */
for (enum binding_action j = 0; j < BIND_ACTION_COUNT; j++) { for (enum bind_action_normal j = 0; j < BIND_ACTION_COUNT; j++) {
const struct mouse_binding *collision = &conf->bindings.mouse[j]; const struct mouse_binding *collision = &conf->bindings.mouse[j];
if (collision->button == i && collision->count == count) { if (collision->button == i && collision->count == count) {
LOG_ERR("%s:%d: %s already mapped to %s", path, lineno, LOG_ERR("%s:%d: %s already mapped to %s", path, lineno,
@ -856,6 +856,22 @@ config_load(struct config *conf, const char *conf_path)
[BIND_ACTION_PRIMARY_PASTE] = {BTN_MIDDLE, 1, BIND_ACTION_PRIMARY_PASTE}, [BIND_ACTION_PRIMARY_PASTE] = {BTN_MIDDLE, 1, BIND_ACTION_PRIMARY_PASTE},
}, },
.search = { .search = {
[BIND_ACTION_SEARCH_CANCEL] = strdup("Control+g Escape"),
[BIND_ACTION_SEARCH_COMMIT] = strdup("Return"),
[BIND_ACTION_SEARCH_FIND_PREV] = strdup("Control+r"),
[BIND_ACTION_SEARCH_FIND_NEXT] = strdup("Control+s"),
[BIND_ACTION_SEARCH_EDIT_LEFT] = strdup("Left Control+b"),
[BIND_ACTION_SEARCH_EDIT_LEFT_WORD] = strdup("Control+Left Mod1+b"),
[BIND_ACTION_SEARCH_EDIT_RIGHT] = strdup("Right Control+f"),
[BIND_ACTION_SEARCH_EDIT_RIGHT_WORD] = strdup("Control+Right Mod1+f"),
[BIND_ACTION_SEARCH_EDIT_HOME] = strdup("Home Control+a"),
[BIND_ACTION_SEARCH_EDIT_END] = strdup("End Control+e"),
[BIND_ACTION_SEARCH_DELETE_PREV] = strdup("BackSpace"),
[BIND_ACTION_SEARCH_DELETE_PREV_WORD] = strdup("Mod1+BackSpace Control+BackSpace"),
[BIND_ACTION_SEARCH_DELETE_NEXT] = strdup("Delete "),
[BIND_ACTION_SEARCH_DELETE_NEXT_WORD] = strdup("Mod1+d Control+Delete"),
[BIND_ACTION_SEARCH_EXTEND_WORD] = strdup("Control+w"),
[BIND_ACTION_SEARCH_EXTEND_WORD_WS] = strdup("Control+Shift+W"),
}, },
}, },
@ -917,8 +933,8 @@ config_free(struct config conf)
tll_free_and_free(conf.fonts, free); tll_free_and_free(conf.fonts, free);
free(conf.server_socket_path); free(conf.server_socket_path);
for (size_t i = 0; i < BIND_ACTION_COUNT; i++) { for (enum bind_action_normal i = 0; i < BIND_ACTION_COUNT; i++)
free(conf.bindings.key[i]); free(conf.bindings.key[i]);
for (enum bind_action_search i = 0; i < BIND_ACTION_SEARCH_COUNT; i++)
free(conf.bindings.search[i]); free(conf.bindings.search[i]);
}
} }

View file

@ -47,7 +47,7 @@ struct config {
/* While searching (not - action to *start* a search is in the /* While searching (not - action to *start* a search is in the
* 'key' bindings above */ * 'key' bindings above */
char *search[BIND_ACTION_COUNT]; char *search[BIND_ACTION_SEARCH_COUNT];
} bindings; } bindings;
struct { struct {

64
input.c
View file

@ -33,9 +33,9 @@
#define ALEN(v) (sizeof(v) / sizeof(v[0])) #define ALEN(v) (sizeof(v) / sizeof(v[0]))
void static void
input_execute_binding(struct terminal *term, enum binding_action action, execute_binding(struct terminal *term, enum bind_action_normal action,
uint32_t serial) uint32_t serial)
{ {
switch (action) { switch (action) {
case BIND_ACTION_NONE: case BIND_ACTION_NONE:
@ -109,14 +109,12 @@ input_execute_binding(struct terminal *term, enum binding_action action,
} }
bool bool
input_parse_key_binding_for_action( input_parse_key_binding(struct xkb_keymap *keymap, const char *combos,
struct xkb_keymap *keymap, enum binding_action action, key_binding_list_t *bindings)
const char *combos, key_binding_list_t *bindings)
{ {
if (combos == NULL) if (combos == NULL)
return true; return true;
xkb_mod_mask_t mod_mask = 0;
xkb_keysym_t sym = XKB_KEY_NoSymbol; xkb_keysym_t sym = XKB_KEY_NoSymbol;
char *copy = strdup(combos); char *copy = strdup(combos);
@ -125,6 +123,7 @@ input_parse_key_binding_for_action(
combo != NULL; combo != NULL;
combo = strtok_r(NULL, " ", &save1)) combo = strtok_r(NULL, " ", &save1))
{ {
xkb_mod_mask_t mod_mask = 0;
xkb_keycode_list_t key_codes = tll_init(); xkb_keycode_list_t key_codes = tll_init();
LOG_DBG("%s", combo); LOG_DBG("%s", combo);
@ -177,7 +176,7 @@ input_parse_key_binding_for_action(
} }
} }
LOG_DBG("action=%u: mods=0x%08x, sym=%d", action, mod_mask, sym); LOG_DBG("mods=0x%08x, sym=%d", mod_mask, sym);
if (sym == XKB_KEY_NoSymbol) { if (sym == XKB_KEY_NoSymbol) {
assert(tll_length(key_codes) == 0); assert(tll_length(key_codes) == 0);
@ -191,7 +190,6 @@ input_parse_key_binding_for_action(
.mods = mod_mask, .mods = mod_mask,
.sym = sym, .sym = sym,
.key_codes = key_codes, .key_codes = key_codes,
.action = action,
}; };
tll_push_back(*bindings, binding); tll_push_back(*bindings, binding);
@ -235,11 +233,11 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
} }
tll_foreach(wayl->kbd.bindings.key, it) tll_foreach(wayl->kbd.bindings.key, it)
tll_free(it->item.key_codes); tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.key); tll_free(wayl->kbd.bindings.key);
tll_foreach(wayl->kbd.bindings.search, it) tll_foreach(wayl->kbd.bindings.search, it)
tll_free(it->item.key_codes); tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.search); tll_free(wayl->kbd.bindings.search);
wayl->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); wayl->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@ -264,14 +262,32 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
munmap(map_str, size); munmap(map_str, size);
close(fd); close(fd);
for (size_t i = 0; i < BIND_ACTION_COUNT; i++) { for (enum bind_action_normal i = 0; i < BIND_ACTION_COUNT; i++) {
input_parse_key_binding_for_action( key_binding_list_t bindings = tll_init();
wayl->kbd.xkb_keymap, i, input_parse_key_binding(
wayl->conf->bindings.key[i], &wayl->kbd.bindings.key); wayl->kbd.xkb_keymap, wayl->conf->bindings.key[i], &bindings);
input_parse_key_binding_for_action( tll_foreach(bindings, it) {
wayl->kbd.xkb_keymap, i, tll_push_back(
wayl->conf->bindings.search[i], &wayl->kbd.bindings.search); wayl->kbd.bindings.key,
((struct key_binding_normal){.bind = it->item, .action = i}));
}
tll_free(bindings);
}
for (enum bind_action_search i = 0; i < BIND_ACTION_SEARCH_COUNT; i++) {
key_binding_list_t bindings = tll_init();
input_parse_key_binding(
wayl->kbd.xkb_keymap, wayl->conf->bindings.search[i], &bindings);
tll_foreach(bindings, it) {
tll_push_back(
wayl->kbd.bindings.search,
((struct key_binding_search){.bind = it->item, .action = i}));
}
tll_free(bindings);
} }
} }
@ -558,19 +574,19 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
* User configurable bindings * User configurable bindings
*/ */
tll_foreach(wayl->kbd.bindings.key, it) { tll_foreach(wayl->kbd.bindings.key, it) {
if (it->item.mods != effective_mods) if (it->item.bind.mods != effective_mods)
continue; continue;
/* Match symbol */ /* Match symbol */
if (it->item.sym == sym) { if (it->item.bind.sym == sym) {
input_execute_binding(term, it->item.action, serial); execute_binding(term, it->item.action, serial);
goto maybe_repeat; goto maybe_repeat;
} }
/* Match raw key code */ /* Match raw key code */
tll_foreach(it->item.key_codes, code) { tll_foreach(it->item.bind.key_codes, code) {
if (code->item == key) { if (code->item == key) {
input_execute_binding(term, it->item.action, serial); execute_binding(term, it->item.action, serial);
goto maybe_repeat; goto maybe_repeat;
} }
} }
@ -1192,7 +1208,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
continue; continue;
} }
input_execute_binding(term, binding->action, serial); execute_binding(term, binding->action, serial);
break; break;
} }
selection_cancel(term); selection_cancel(term);

View file

@ -10,9 +10,5 @@ extern const struct wl_pointer_listener pointer_listener;
void input_repeat(struct wayland *wayl, uint32_t key); void input_repeat(struct wayland *wayl, uint32_t key);
bool input_parse_key_binding_for_action( bool input_parse_key_binding(struct xkb_keymap *keymap, const char *combos,
struct xkb_keymap *keymap, enum binding_action action, key_binding_list_t *bindings);
const char *combos, key_binding_list_t *bindings);
void input_execute_binding(
struct terminal *term, enum binding_action action, uint32_t serial);

248
search.c
View file

@ -412,63 +412,29 @@ distance_prev_word(const struct terminal *term)
return term->search.cursor - cursor; return term->search.cursor - cursor;
} }
void static bool
search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, execute_binding(struct terminal *term, enum bind_action_search action,
xkb_mod_mask_t mods, uint32_t serial) uint32_t serial)
{ {
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x", sym, sym, mods); switch (action) {
case BIND_ACTION_SEARCH_NONE:
return false;
const xkb_mod_mask_t ctrl = 1 << term->wl->kbd.mod_ctrl; case BIND_ACTION_SEARCH_CANCEL:
const xkb_mod_mask_t alt = 1 << term->wl->kbd.mod_alt;
const xkb_mod_mask_t shift = 1 << term->wl->kbd.mod_shift;
//const xkb_mod_mask_t meta = 1 << term->wl->kbd.mod_meta;
enum xkb_compose_status compose_status = xkb_compose_state_get_status(
term->wl->kbd.xkb_compose_state);
/*
* User configurable bindings
*/
tll_foreach(term->wl->kbd.bindings.search, it) {
if (it->item.mods != mods)
continue;
/* Match symbol */
if (it->item.sym == sym) {
input_execute_binding(term, it->item.action, serial);
return;
}
/* Match raw key code */
tll_foreach(it->item.key_codes, code) {
if (code->item == key) {
input_execute_binding(term, it->item.action, serial);
return;
}
}
}
/* Cancel search */
if ((mods == 0 && sym == XKB_KEY_Escape) ||
(mods == ctrl && sym == XKB_KEY_g))
{
if (term->search.view_followed_offset) if (term->search.view_followed_offset)
term->grid->view = term->grid->offset; term->grid->view = term->grid->offset;
else else
term->grid->view = term->search.original_view; term->grid->view = term->search.original_view;
term_damage_view(term); term_damage_view(term);
search_cancel(term); search_cancel(term);
return; return true;
}
/* "Commit" search - copy selection to primary and cancel search */ case BIND_ACTION_SEARCH_COMMIT:
else if (mods == 0 && sym == XKB_KEY_Return) {
selection_finalize(term, term->wl->input_serial); selection_finalize(term, term->wl->input_serial);
search_cancel_keep_selection(term); search_cancel_keep_selection(term);
return; return true;
}
else if (mods == ctrl && sym == XKB_KEY_r) { case BIND_ACTION_SEARCH_FIND_PREV:
if (term->search.match_len > 0) { if (term->search.match_len > 0) {
int new_col = term->search.match.col - 1; int new_col = term->search.match.col - 1;
int new_row = term->search.match.row; int new_row = term->search.match.row;
@ -483,9 +449,9 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
term->search.match.row = new_row; term->search.match.row = new_row;
} }
} }
} return false;
else if (mods == ctrl && sym == XKB_KEY_s) { case BIND_ACTION_SEARCH_FIND_NEXT:
if (term->search.match_len > 0) { if (term->search.match_len > 0) {
int new_col = term->search.match.col + 1; int new_col = term->search.match.col + 1;
int new_row = term->search.match.row; int new_row = term->search.match.row;
@ -501,49 +467,43 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
term->search.direction = SEARCH_FORWARD; term->search.direction = SEARCH_FORWARD;
} }
} }
} return false;
else if ((mods == 0 && sym == XKB_KEY_Left) || case BIND_ACTION_SEARCH_EDIT_LEFT:
(mods == ctrl && sym == XKB_KEY_b))
{
if (term->search.cursor > 0) if (term->search.cursor > 0)
term->search.cursor--; term->search.cursor--;
} return false;
else if ((mods == ctrl && sym == XKB_KEY_Left) || case BIND_ACTION_SEARCH_EDIT_LEFT_WORD: {
(mods == alt && sym == XKB_KEY_b))
{
size_t diff = distance_prev_word(term); size_t diff = distance_prev_word(term);
term->search.cursor -= diff; term->search.cursor -= diff;
assert(term->search.cursor >= 0); assert(term->search.cursor >= 0);
assert(term->search.cursor <= term->search.len); assert(term->search.cursor <= term->search.len);
return false;
} }
else if ((mods == 0 && sym == XKB_KEY_Right) || case BIND_ACTION_SEARCH_EDIT_RIGHT:
(mods == ctrl && sym == XKB_KEY_f))
{
if (term->search.cursor < term->search.len) if (term->search.cursor < term->search.len)
term->search.cursor++; term->search.cursor++;
} return false;
else if ((mods == ctrl && sym == XKB_KEY_Right) || case BIND_ACTION_SEARCH_EDIT_RIGHT_WORD: {
(mods == alt && sym == XKB_KEY_f))
{
size_t diff = distance_next_word(term); size_t diff = distance_next_word(term);
term->search.cursor += diff; term->search.cursor += diff;
assert(term->search.cursor >= 0); assert(term->search.cursor >= 0);
assert(term->search.cursor <= term->search.len); assert(term->search.cursor <= term->search.len);
return false;
} }
else if ((mods == 0 && sym == XKB_KEY_Home) || case BIND_ACTION_SEARCH_EDIT_HOME:
(mods == ctrl && sym == XKB_KEY_a))
term->search.cursor = 0; term->search.cursor = 0;
return false;
else if ((mods == 0 && sym == XKB_KEY_End) || case BIND_ACTION_SEARCH_EDIT_END:
(mods == ctrl && sym == XKB_KEY_e))
term->search.cursor = term->search.len; term->search.cursor = term->search.len;
return false;
else if (mods == 0 && sym == XKB_KEY_BackSpace) { case BIND_ACTION_SEARCH_DELETE_PREV:
if (term->search.cursor > 0) { if (term->search.cursor > 0) {
memmove( memmove(
&term->search.buf[term->search.cursor - 1], &term->search.buf[term->search.cursor - 1],
@ -552,9 +512,9 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
term->search.cursor--; term->search.cursor--;
term->search.buf[--term->search.len] = L'\0'; term->search.buf[--term->search.len] = L'\0';
} }
} return false;
else if ((mods == alt || mods == ctrl) && sym == XKB_KEY_BackSpace) { case BIND_ACTION_SEARCH_DELETE_PREV_WORD: {
size_t diff = distance_prev_word(term); size_t diff = distance_prev_word(term);
size_t old_cursor = term->search.cursor; size_t old_cursor = term->search.cursor;
size_t new_cursor = old_cursor - diff; size_t new_cursor = old_cursor - diff;
@ -565,10 +525,20 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
term->search.len -= diff; term->search.len -= diff;
term->search.cursor = new_cursor; term->search.cursor = new_cursor;
return false;
} }
else if ((mods == alt && sym == XKB_KEY_d) || case BIND_ACTION_SEARCH_DELETE_NEXT:
(mods == ctrl && sym == XKB_KEY_Delete)) { if (term->search.cursor < term->search.len) {
memmove(
&term->search.buf[term->search.cursor],
&term->search.buf[term->search.cursor + 1],
(term->search.len - term->search.cursor - 1) * sizeof(wchar_t));
term->search.buf[--term->search.len] = L'\0';
}
return false;
case BIND_ACTION_SEARCH_DELETE_NEXT_WORD: {
size_t diff = distance_next_word(term); size_t diff = distance_next_word(term);
size_t cursor = term->search.cursor; size_t cursor = term->search.cursor;
@ -577,66 +547,98 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
(term->search.len - (cursor + diff)) * sizeof(wchar_t)); (term->search.len - (cursor + diff)) * sizeof(wchar_t));
term->search.len -= diff; term->search.len -= diff;
return false;
} }
else if (mods == 0 && sym == XKB_KEY_Delete) { case BIND_ACTION_SEARCH_EXTEND_WORD:
if (term->search.cursor < term->search.len) {
memmove(
&term->search.buf[term->search.cursor],
&term->search.buf[term->search.cursor + 1],
(term->search.len - term->search.cursor - 1) * sizeof(wchar_t));
term->search.buf[--term->search.len] = L'\0';
}
}
else if (mods == ctrl && sym == XKB_KEY_w)
search_match_to_end_of_word(term, false); search_match_to_end_of_word(term, false);
return false;
else if (mods == (ctrl | shift) && sym == XKB_KEY_W) case BIND_ACTION_SEARCH_EXTEND_WORD_WS:
search_match_to_end_of_word(term, true); search_match_to_end_of_word(term, true);
return false;
else { case BIND_ACTION_SEARCH_COUNT:
uint8_t buf[64] = {0}; assert(false);
int count = 0; return false;
if (compose_status == XKB_COMPOSE_COMPOSED) {
count = xkb_compose_state_get_utf8(
term->wl->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(term->wl->kbd.xkb_compose_state);
} else if (compose_status == XKB_COMPOSE_CANCELLED) {
count = 0;
} else {
count = xkb_state_key_get_utf8(
term->wl->kbd.xkb_state, key, (char *)buf, sizeof(buf));
}
const char *src = (const char *)buf;
mbstate_t ps = {0};
size_t wchars = mbsnrtowcs(NULL, &src, count, 0, &ps);
if (wchars == -1) {
LOG_ERRNO("failed to convert %.*s to wchars", count, buf);
return;
}
if (!search_ensure_size(term, term->search.len + wchars))
return;
assert(term->search.len + wchars < term->search.sz);
memmove(&term->search.buf[term->search.cursor + wchars],
&term->search.buf[term->search.cursor],
(term->search.len - term->search.cursor) * sizeof(wchar_t));
memset(&ps, 0, sizeof(ps));
mbsnrtowcs(&term->search.buf[term->search.cursor], &src, count,
wchars, &ps);
term->search.len += wchars;
term->search.cursor += wchars;
term->search.buf[term->search.len] = L'\0';
} }
assert(false);
return false;
}
void
search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym,
xkb_mod_mask_t mods, uint32_t serial)
{
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x", sym, sym, mods);
enum xkb_compose_status compose_status = xkb_compose_state_get_status(
term->wl->kbd.xkb_compose_state);
/* Key bindings */
tll_foreach(term->wl->kbd.bindings.search, it) {
if (it->item.bind.mods != mods)
continue;
/* Match symbol */
if (it->item.bind.sym == sym) {
if (!execute_binding(term, it->item.action, serial))
goto update_search;
return;
}
/* Match raw key code */
tll_foreach(it->item.bind.key_codes, code) {
if (code->item == key) {
if (!execute_binding(term, it->item.action, serial))
goto update_search;
return;
}
}
}
uint8_t buf[64] = {0};
int count = 0;
if (compose_status == XKB_COMPOSE_COMPOSED) {
count = xkb_compose_state_get_utf8(
term->wl->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
xkb_compose_state_reset(term->wl->kbd.xkb_compose_state);
} else if (compose_status == XKB_COMPOSE_CANCELLED) {
count = 0;
} else {
count = xkb_state_key_get_utf8(
term->wl->kbd.xkb_state, key, (char *)buf, sizeof(buf));
}
const char *src = (const char *)buf;
mbstate_t ps = {0};
size_t wchars = mbsnrtowcs(NULL, &src, count, 0, &ps);
if (wchars == -1) {
LOG_ERRNO("failed to convert %.*s to wchars", count, buf);
return;
}
if (!search_ensure_size(term, term->search.len + wchars))
return;
assert(term->search.len + wchars < term->search.sz);
memmove(&term->search.buf[term->search.cursor + wchars],
&term->search.buf[term->search.cursor],
(term->search.len - term->search.cursor) * sizeof(wchar_t));
memset(&ps, 0, sizeof(ps));
mbsnrtowcs(&term->search.buf[term->search.cursor], &src, count,
wchars, &ps);
term->search.len += wchars;
term->search.cursor += wchars;
term->search.buf[term->search.len] = L'\0';
update_search:
LOG_DBG("search: buffer: %S", term->search.buf); LOG_DBG("search: buffer: %S", term->search.buf);
search_find_next(term); search_find_next(term);
render_refresh_search(term); render_refresh_search(term);

View file

@ -924,11 +924,11 @@ wayl_destroy(struct wayland *wayl)
wp_presentation_destroy(wayl->presentation); wp_presentation_destroy(wayl->presentation);
tll_foreach(wayl->kbd.bindings.key, it) tll_foreach(wayl->kbd.bindings.key, it)
tll_free(it->item.key_codes); tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.key); tll_free(wayl->kbd.bindings.key);
tll_foreach(wayl->kbd.bindings.search, it) tll_foreach(wayl->kbd.bindings.search, it)
tll_free(it->item.key_codes); tll_free(it->item.bind.key_codes);
tll_free(wayl->kbd.bindings.search); tll_free(wayl->kbd.bindings.search);
if (wayl->kbd.xkb_compose_state != NULL) if (wayl->kbd.xkb_compose_state != NULL)

View file

@ -66,7 +66,17 @@ struct monitor {
float inch; /* e.g. 24" */ float inch; /* e.g. 24" */
}; };
enum binding_action {
typedef tll(xkb_keycode_t) xkb_keycode_list_t;
struct key_binding {
xkb_mod_mask_t mods;
xkb_keysym_t sym;
xkb_keycode_list_t key_codes;
};
typedef tll(struct key_binding) key_binding_list_t;
enum bind_action_normal {
BIND_ACTION_NONE, BIND_ACTION_NONE,
BIND_ACTION_SCROLLBACK_UP, BIND_ACTION_SCROLLBACK_UP,
BIND_ACTION_SCROLLBACK_DOWN, BIND_ACTION_SCROLLBACK_DOWN,
@ -84,20 +94,41 @@ enum binding_action {
BIND_ACTION_COUNT, BIND_ACTION_COUNT,
}; };
typedef tll(xkb_keycode_t) xkb_keycode_list_t; struct key_binding_normal {
struct key_binding bind;
struct key_binding { enum bind_action_normal action;
xkb_mod_mask_t mods;
xkb_keysym_t sym;
xkb_keycode_list_t key_codes;
enum binding_action action;
}; };
typedef tll(struct key_binding) key_binding_list_t;
struct mouse_binding { struct mouse_binding {
uint32_t button; uint32_t button;
int count; int count;
enum binding_action action; enum bind_action_normal action;
};
enum bind_action_search {
BIND_ACTION_SEARCH_NONE,
BIND_ACTION_SEARCH_CANCEL,
BIND_ACTION_SEARCH_COMMIT,
BIND_ACTION_SEARCH_FIND_PREV,
BIND_ACTION_SEARCH_FIND_NEXT,
BIND_ACTION_SEARCH_EDIT_LEFT,
BIND_ACTION_SEARCH_EDIT_LEFT_WORD,
BIND_ACTION_SEARCH_EDIT_RIGHT,
BIND_ACTION_SEARCH_EDIT_RIGHT_WORD,
BIND_ACTION_SEARCH_EDIT_HOME,
BIND_ACTION_SEARCH_EDIT_END,
BIND_ACTION_SEARCH_DELETE_PREV,
BIND_ACTION_SEARCH_DELETE_PREV_WORD,
BIND_ACTION_SEARCH_DELETE_NEXT,
BIND_ACTION_SEARCH_DELETE_NEXT_WORD,
BIND_ACTION_SEARCH_EXTEND_WORD,
BIND_ACTION_SEARCH_EXTEND_WORD_WS,
BIND_ACTION_SEARCH_COUNT,
};
struct key_binding_search {
struct key_binding bind;
enum bind_action_search action;
}; };
struct kbd { struct kbd {
@ -127,8 +158,8 @@ struct kbd {
bool meta; bool meta;
struct { struct {
key_binding_list_t key; tll(struct key_binding_normal) key;
key_binding_list_t search; tll(struct key_binding_search) search;
} bindings; } bindings;
}; };