mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -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).
|
(https://codeberg.org/dnkl/foot/issues/170).
|
||||||
* Restored window size when window is un-tiled.
|
* Restored window size when window is un-tiled.
|
||||||
* XCursor shape in CSD corners when window is 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
|
### 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);
|
tll_free(seat->mouse.bindings);
|
||||||
|
|
||||||
seat->kbd.xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
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");
|
/* Compose (dead keys) */
|
||||||
seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ;
|
seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
|
||||||
seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control");
|
seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||||
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");
|
if (seat->kbd.xkb_compose_table == NULL) {
|
||||||
seat->kbd.key_arrow_down = xkb_keymap_key_by_name(seat->kbd.xkb_keymap, "DOWN");
|
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) */
|
if (seat->kbd.xkb_keymap != NULL) {
|
||||||
seat->kbd.xkb_compose_table = xkb_compose_table_new_from_locale(
|
seat->kbd.xkb_state = xkb_state_new(seat->kbd.xkb_keymap);
|
||||||
seat->kbd.xkb, setlocale(LC_CTYPE, NULL), XKB_COMPOSE_COMPILE_NO_FLAGS);
|
|
||||||
|
|
||||||
if (seat->kbd.xkb_compose_table == NULL) {
|
seat->kbd.mod_shift = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Shift");
|
||||||
LOG_WARN("failed to instantiate compose table; dead keys will not work");
|
seat->kbd.mod_alt = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod1") ;
|
||||||
} else {
|
seat->kbd.mod_ctrl = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Control");
|
||||||
seat->kbd.xkb_compose_state = xkb_compose_state_new(
|
seat->kbd.mod_meta = xkb_keymap_mod_get_index(seat->kbd.xkb_keymap, "Mod4");
|
||||||
seat->kbd.xkb_compose_table, XKB_COMPOSE_STATE_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");
|
||||||
}
|
}
|
||||||
|
|
||||||
munmap(map_str, size);
|
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 seat *seat = data;
|
||||||
struct terminal *term = seat->kbd_focus;
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(term != NULL);
|
assert(term != NULL);
|
||||||
|
|
||||||
|
|
@ -870,39 +879,43 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||||
goto maybe_repeat;
|
goto maybe_repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compose_status == XKB_COMPOSE_CANCELLED)
|
||||||
|
goto maybe_repeat;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compose, and maybe emit "normal" character
|
* Compose, and maybe emit "normal" character
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint8_t buf[64] = {0};
|
assert(seat->kbd.xkb_compose_state != NULL ||
|
||||||
int count = 0;
|
compose_status != XKB_COMPOSE_COMPOSED);
|
||||||
|
|
||||||
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
int count = compose_status == XKB_COMPOSE_COMPOSED
|
||||||
assert(seat->kbd.xkb_compose_state != NULL);
|
? 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(
|
if (count <= 0)
|
||||||
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
|
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);
|
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_control_key(x) ((x) >= 0x40 && (x) <= 0x7f)
|
||||||
#define IS_CTRL(x) ((x) < 0x20 || ((x) >= 0x7f && (x) <= 0x9f))
|
#define IS_CTRL(x) ((x) < 0x20 || ((x) >= 0x7f && (x) <= 0x9f))
|
||||||
|
|
||||||
if ((keymap_mods & MOD_CTRL) &&
|
if ((keymap_mods & MOD_CTRL) &&
|
||||||
!is_control_key(sym) &&
|
!is_control_key(sym) &&
|
||||||
(count == 1 && !IS_CTRL(buf[0])) &&
|
(count == 1 && !IS_CTRL(utf8[0])) &&
|
||||||
sym < 256)
|
sym < 256)
|
||||||
{
|
{
|
||||||
static const int mod_param_map[32] = {
|
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) {
|
if (term->meta.esc_prefix) {
|
||||||
term_to_slave(term, "\x1b", 1);
|
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) {
|
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];
|
char utf8[8];
|
||||||
mbstate_t ps = {0};
|
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)
|
if (chars != (size_t)-1)
|
||||||
term_to_slave(term, utf8, chars);
|
term_to_slave(term, utf8, chars);
|
||||||
else
|
else
|
||||||
term_to_slave(term, buf, count);
|
term_to_slave(term, utf8, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
/* Alt ignored */
|
/* Alt ignored */
|
||||||
term_to_slave(term, buf, count);
|
term_to_slave(term, utf8, count);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
term_to_slave(term, buf, count);
|
term_to_slave(term, utf8, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (utf8 != buf)
|
||||||
|
free(utf8);
|
||||||
|
|
||||||
term_reset_view(term);
|
term_reset_view(term);
|
||||||
selection_cancel(term);
|
selection_cancel(term);
|
||||||
|
|
||||||
|
|
@ -986,7 +1002,6 @@ maybe_repeat:
|
||||||
|
|
||||||
if (should_repeat)
|
if (should_repeat)
|
||||||
start_repeater(seat, key - 8);
|
start_repeater(seat, key - 8);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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",
|
LOG_DBG("modifiers: depressed=0x%x, latched=0x%x, locked=0x%x, group=%u",
|
||||||
mods_depressed, mods_latched, mods_locked, group);
|
mods_depressed, mods_latched, mods_locked, group);
|
||||||
|
|
||||||
if (seat->kbd.xkb == NULL)
|
if (seat->kbd.xkb_state != NULL) {
|
||||||
return;
|
xkb_state_update_mask(
|
||||||
|
seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||||
|
|
||||||
xkb_state_update_mask(
|
/* Update state of modifiers we're interested in for e.g mouse events */
|
||||||
seat->kbd.xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
seat->kbd.shift = xkb_state_mod_index_is_active(
|
||||||
|
seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
|
||||||
/* Update state of modifiers we're interested in for e.g mouse events */
|
seat->kbd.alt = xkb_state_mod_index_is_active(
|
||||||
seat->kbd.shift = xkb_state_mod_index_is_active(
|
seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
|
||||||
seat->kbd.xkb_state, seat->kbd.mod_shift, XKB_STATE_MODS_DEPRESSED);
|
seat->kbd.ctrl = xkb_state_mod_index_is_active(
|
||||||
seat->kbd.alt = xkb_state_mod_index_is_active(
|
seat->kbd.xkb_state, seat->kbd.mod_ctrl, XKB_STATE_MODS_DEPRESSED);
|
||||||
seat->kbd.xkb_state, seat->kbd.mod_alt, XKB_STATE_MODS_DEPRESSED);
|
seat->kbd.meta = xkb_state_mod_index_is_active(
|
||||||
seat->kbd.ctrl = xkb_state_mod_index_is_active(
|
seat->kbd.xkb_state, seat->kbd.mod_meta, XKB_STATE_MODS_DEPRESSED);
|
||||||
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)
|
if (seat->kbd_focus && seat->kbd_focus->active_surface == TERM_SURF_GRID)
|
||||||
term_xcursor_update_for_seat(seat->kbd_focus, seat);
|
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) {
|
switch (state) {
|
||||||
case WL_POINTER_BUTTON_STATE_PRESSED: {
|
case WL_POINTER_BUTTON_STATE_PRESSED: {
|
||||||
if (!seat->mouse.consumed) {
|
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 */
|
/* Seat has keyboard - use mouse bindings *with* modifiers */
|
||||||
|
|
||||||
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
xkb_mod_mask_t mods = xkb_state_serialize_mods(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue