mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
input: handle XKB errors
* Don’t de-reference the xkb context/keymap/state if we failed to instantiate them. * Don’t try to send a translated utf8 key sequence if the translation failed. * Handle xkb_compose_state_get_utf8() and xkb_state_key_get_utf8() returning more than 64 bytes. This _may_ fix #171.
This commit is contained in:
parent
4c3d2cfc7d
commit
0d319f8793
2 changed files with 76 additions and 60 deletions
|
|
@ -53,6 +53,8 @@
|
|||
(https://codeberg.org/dnkl/foot/issues/170).
|
||||
* Restored window size when window is un-tiled.
|
||||
* XCursor shape in CSD corners when window is tiled.
|
||||
* Error handling when processing keyboard input (maybe
|
||||
https://codeberg.org/dnkl/foot/issues/171).
|
||||
|
||||
|
||||
### Security
|
||||
|
|
|
|||
134
input.c
134
input.c
|
|
@ -487,29 +487,34 @@ keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|||
tll_free(seat->mouse.bindings);
|
||||
|
||||
seat->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
seat->kbd.xkb_keymap = xkb_keymap_new_from_buffer(
|
||||
seat->kbd.xkb, map_str, size, XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
|
||||
if (seat->kbd.xkb != NULL) {
|
||||
seat->kbd.xkb_keymap = xkb_keymap_new_from_buffer(
|
||||
seat->kbd.xkb, map_str, size, XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Shift");
|
||||
seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ;
|
||||
seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control");
|
||||
seat->kbd.mod_meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod4");
|
||||
/* Compose (dead keys) */
|
||||
seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
|
||||
seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
|
||||
seat->kbd.key_arrow_up = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "UP");
|
||||
seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN");
|
||||
if (seat->kbd.xkb_compose_table == NULL) {
|
||||
LOG_WARN("failed to instantiate compose table; dead keys will not work");
|
||||
} else {
|
||||
seat->kbd.xkb_compose_state = xkb_compose_state_new(
|
||||
seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compose (dead keys) */
|
||||
seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
|
||||
seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (seat->kbd.xkb_keymap != NULL) {
|
||||
seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
|
||||
|
||||
if (seat->kbd.xkb_compose_table == NULL) {
|
||||
LOG_WARN("failed to instantiate compose table; dead keys will not work");
|
||||
} else {
|
||||
seat->kbd.xkb_compose_state = xkb_compose_state_new(
|
||||
seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Shift");
|
||||
seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ;
|
||||
seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control");
|
||||
seat->kbd.mod_meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod4");
|
||||
|
||||
seat->kbd.key_arrow_up = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "UP");
|
||||
seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN");
|
||||
}
|
||||
|
||||
munmap(map_str, size);
|
||||
|
|
@ -749,8 +754,12 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
struct seat *seat = data;
|
||||
struct terminal *term = seat->kbd_focus;
|
||||
|
||||
if (seat->kbd.xkb == NULL)
|
||||
if (seat->kbd.xkb == NULL ||
|
||||
seat->kbd.xkb_keymap == NULL ||
|
||||
seat->kbd.xkb_state == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
assert(term != NULL);
|
||||
|
||||
|
|
@ -870,39 +879,43 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
goto maybe_repeat;
|
||||
}
|
||||
|
||||
if (compose_status == XKB_COMPOSE_CANCELLED)
|
||||
goto maybe_repeat;
|
||||
|
||||
/*
|
||||
* Compose, and maybe emit "normal" character
|
||||
*/
|
||||
|
||||
uint8_t buf[64] = {0};
|
||||
int count = 0;
|
||||
assert(seat->kbd.xkb_compose_state != NULL ||
|
||||
compose_status != XKB_COMPOSE_COMPOSED);
|
||||
|
||||
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
||||
assert(seat->kbd.xkb_compose_state != NULL);
|
||||
int count = compose_status == XKB_COMPOSE_COMPOSED
|
||||
? xkb_compose_state_get_utf8(seat->kbd.xkb_compose_state, NULL, 0)
|
||||
: xkb_state_key_get_utf8(seat->kbd.xkb_state, key, NULL, 0);
|
||||
|
||||
count = xkb_compose_state_get_utf8(
|
||||
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
|
||||
if (count <= 0)
|
||||
goto maybe_repeat;
|
||||
|
||||
/* Buffer for translated key. Use a static buffer in most cases,
|
||||
* and use a malloc:ed buffer when necessary */
|
||||
uint8_t buf[32];
|
||||
uint8_t *utf8 = count < sizeof(buf) ? buf : xmalloc(count + 1);
|
||||
|
||||
compose_status == XKB_COMPOSE_COMPOSED
|
||||
? xkb_compose_state_get_utf8(
|
||||
seat->kbd.xkb_compose_state, (char *)utf8, count + 1)
|
||||
: xkb_state_key_get_utf8(
|
||||
seat->kbd.xkb_state, key, (char *)utf8, count + 1);
|
||||
|
||||
if (seat->kbd.xkb_compose_state != NULL)
|
||||
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
|
||||
}
|
||||
|
||||
else if (compose_status == XKB_COMPOSE_CANCELLED) {
|
||||
goto maybe_repeat;
|
||||
}
|
||||
|
||||
else {
|
||||
count = xkb_state_key_get_utf8(
|
||||
seat->kbd.xkb_state, key, (char *)buf, sizeof(buf));
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
goto maybe_repeat;
|
||||
|
||||
#define is_control_key(x) ((x) >= 0x40 && (x) <= 0x7f)
|
||||
#define IS_CTRL(x) ((x) < 0x20 || ((x) >= 0x7f && (x) <= 0x9f))
|
||||
|
||||
if ((keymap_mods & MOD_CTRL) &&
|
||||
!is_control_key(sym) &&
|
||||
(count == 1 && !IS_CTRL(buf[0])) &&
|
||||
(count == 1 && !IS_CTRL(utf8[0])) &&
|
||||
sym < 256)
|
||||
{
|
||||
static const int mod_param_map[32] = {
|
||||
|
|
@ -953,11 +966,11 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
*/
|
||||
if (term->meta.esc_prefix) {
|
||||
term_to_slave(term, "\x1b", 1);
|
||||
term_to_slave(term, buf, count);
|
||||
term_to_slave(term, utf8, count);
|
||||
}
|
||||
|
||||
else if (term->meta.eight_bit && count == 1) {
|
||||
const wchar_t wc = 0x80 | buf[0];
|
||||
const wchar_t wc = 0x80 | utf8[0];
|
||||
|
||||
char utf8[8];
|
||||
mbstate_t ps = {0};
|
||||
|
|
@ -966,17 +979,20 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
if (chars != (size_t)-1)
|
||||
term_to_slave(term, utf8, chars);
|
||||
else
|
||||
term_to_slave(term, buf, count);
|
||||
term_to_slave(term, utf8, count);
|
||||
}
|
||||
|
||||
else {
|
||||
/* Alt ignored */
|
||||
term_to_slave(term, buf, count);
|
||||
term_to_slave(term, utf8, count);
|
||||
}
|
||||
} else
|
||||
term_to_slave(term, buf, count);
|
||||
term_to_slave(term, utf8, count);
|
||||
}
|
||||
|
||||
if (utf8 != buf)
|
||||
free(utf8);
|
||||
|
||||
term_reset_view(term);
|
||||
selection_cancel(term);
|
||||
|
||||
|
|
@ -986,7 +1002,6 @@ maybe_repeat:
|
|||
|
||||
if (should_repeat)
|
||||
start_repeater(seat, key - 8);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -999,21 +1014,20 @@ keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u",
|
||||
mods_depressed, mods_latched, mods_locked, group);
|
||||
|
||||
if (seat->kbd.xkb == NULL)
|
||||
return;
|
||||
if (seat->kbd.xkb_state != NULL) {
|
||||
xkb_state_update_mask(
|
||||
seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
|
||||
xkb_state_update_mask(
|
||||
seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
|
||||
/* Update state of modifiers we're interested in for e.g mouse events */
|
||||
seat->kbd.shift = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
|
||||
seat->kbd.alt = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
|
||||
seat->kbd.ctrl = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED);
|
||||
seat->kbd.meta = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED);
|
||||
/* Update state of modifiers we're interested in for e.g mouse events */
|
||||
seat->kbd.shift = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
|
||||
seat->kbd.alt = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
|
||||
seat->kbd.ctrl = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED);
|
||||
seat->kbd.meta = xkb_state_mod_index_is_active(
|
||||
seat->kbd.xkb_state, seat->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED);
|
||||
}
|
||||
|
||||
if (seat->kbd_focus && seat->kbd_focus->active_surface == TERM_SURF_GRID)
|
||||
term_xcursor_update_for_seat(seat->kbd_focus, seat);
|
||||
|
|
@ -1571,7 +1585,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|||
switch (state) {
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED: {
|
||||
if (!seat->mouse.consumed) {
|
||||
if (seat->wl_keyboard != NULL) {
|
||||
if (seat->wl_keyboard != NULL && seat->kbd.xkb_state != NULL) {
|
||||
/* Seat has keyboard - use mouse bindings *with* modifiers */
|
||||
|
||||
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue